Python Snippets

Zebra 9

Emperor
Joined
May 17, 2006
Messages
1,554
Location
Middle of Cyberspace
Intro:
Lately I have been doing alot of small things with python, such as setting civics so they require religions and units that require a certain leader, that sort of thing. So I decided to make this Python Snippets Thread where anyone can come and find some realy cool, and realy simple, python code snippets.
Index:
Python Snippets For CvGameUtils.py
First I will be doing several python snippets that work from the CvGameUtils.py file. From this file we can control the civics a player adopts, the units, buildings, and projects a city can build, a s well as allowing us to control the amount of money you get from capturing cities and pillaging.
Note: If you are using these snippets you may have to make some changes to PythonCallbackDefines.xml. If you are not sure about how to make the change post your question here so I (or any other modder) can help get you on your way. I will be posting the tags that must be changed soon. :cool:


Religious Civics<Back To Top>
The following snippet allows a player to adopt a civic only if they have the correct state religion. The code is as follows:
Code:
        religion = [U][I]Religion Type[/I][/U]        ## The Religion
        civic = [U][I]Civic Type[/I][/U]        ## The Civic

        ## If The Civ Doesn't Have The Correct Religion Tell the SDK Not To Allow The Player To Chose This Civic
        if eCivic == gc.getInfoTypeForString(civic):
            if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString(religion):
                return True
Now this code goes inside of the cannotDoCivic function, in an unMODed game this function looks like:
Code:
    def cannotDoCivic(self,argsList):
        ePlayer = argsList[0]
        eCivic = argsList[1]
        return False
Place the snippet after eCivic = argsList[1] and before return False.
Code:
    def cannotDoCivic(self,argsList):
        ePlayer = argsList[0]
        eCivic = argsList[1]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the required state religion place the religion's type tag after religion = , but remember the type tag must be inside of quote marks.
Code:
        religion = [B]"[/B]RELIGION_JUDAISM[B]"[/B]        ## The Religion
Next to set the civic that requires that religion, place the civic's type tag after civic = , again remember the type tag must be inside of quote marks.
Code:
        civic = [B]"[/B]CIVIC_HEREDITARY_RULE[B]"[/B]        ## The Civic
If you follow those instructions you shouldn't have any problems.:thumbsup:


Civic Specific Units<Back To Top>
The following snippet only allows a player to train a certain unit if they have adopted a certain civic:
Code:
        civic = [U][I]Civic Type[/I][/U]        ## The Civic
        unit = [U][I]Unit Type[/I][/U]        ## The Unit

        ## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Train This Unit
        if eUnit == gc.getInfoTypeForString(unit):
            if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoTypeForString(civic)):
                return True
Now this code goes inside of the cannotTrainUnit function, in an unMODed game this function looks like:
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        return False
Place the snippet after bTestVisible = argsList[3] and before return False.
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the required civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.
Code:
        civic = [B]"[/B]CIVIC_HEREDITARY_RULE[B]"[/B]        ## The Civic
Next to set the unit that requires that civic, place the unit's type tag after unit = , again remember the type tag must be inside of quote marks.
Code:
        unit = [B]"[/B]UNIT_GUNSHIP[B]"[/B]        ## The Unit
If you follow those instructions you shouldn't have any problems.:thumbsup:


Civic Specific Buildings<Back To Top>
The following snippet only allows a player to construct a certain building if they have adopted a certain civic:
Code:
        civic = [U][I]Civic Type[/I][/U]        ## The Civic
        building = [U][I]Building Type[/I][/U]        ## The Building

        ## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Costruct This Building
        if eBuilding == gc.getInfoTypeForString(building):
            if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoTypeForString(civic)):
                return True
Now this code goes inside of the cannotConstruct function, in an unMODed game this function looks like:
Code:
    def cannotConstruct(self,argsList):
        pCity = argsList[0]
        eBuilding = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        bIgnoreCost = argsList[4]
        return False
Place the snippet after bIgnoreCost = argsList[4] and before return False.
Code:
    def cannotConstruct(self,argsList):
        pCity = argsList[0]
        eBuilding = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        bIgnoreCost = argsList[4]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the required civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.
Code:
        civic = [B]"[/B]CIVIC_HEREDITARY_RULE[B]"[/B]        ## The Civic
Next to set the building that requires that civic, place the building's type tag after building = , again remember the type tag must be inside of quote marks.
Code:
        building = [B]"[/B]BUILDIN_FORGE[B]"[/B]        ## The Building
If you follow those instructions you shouldn't have any problems.:thumbsup:


Leader Specific Units<Back To Top>
The following snippet only allows a player to train a certain unit if they have the correct leader:
Code:
        leader = [U][I]Leader Type[/I][/U]        ## The Leader
        unit = [U][I]Unit Type[/I][/U]        ## The Unit

        ## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
        if eUnit == gc.getInfoTypeForString(unit):
            leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner()).getLeaderType()).getType()
            if leaderType != gc.getInfoTypeForString(leader):
                return True
Now this code goes inside of the cannotTrain function, in an unMODed game this function looks like:
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        return False
Place the snippet after bTestVisible = argsList[3] and before return False.
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the required leader place the leader's type tag after leader = , but remember the type tag must be inside of quote marks.
Code:
        leader = [B]"[/B]LEADER_VICTORIAH[B]"[/B]        ## The Leader
Next to set the unit that requires the leader, place the unit's type tag after unit = , again remember the type tag must be inside of quote marks.
Code:
        unit = [B]"[/B]UNIT_ENGLISH_READCOAT[B]"[/B]        ## The Unit
If you follow those instructions you shouldn't have any problems.:thumbsup:


Leader Specific Buildings<Back To Top>
The following snippet only allows a player to construct a certain building if they have the correct leader:
Code:
        leader = [U][I]Leader Type[/I][/U]        ## The Leader
        building = [U][I]Building Type[/I][/U]        ## The Building

        ## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
        if eBuilding == gc.getInfoTypeForString(building):
            leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner()).getLeaderType()).getType()
            if leaderType != gc.getInfoTypeForString(leader):
                return True
Now this code goes inside of the cannotConstruct function, in an unMODed game this function looks like:
Code:
    def cannotConstruct(self,argsList):
        pCity = argsList[0]
        eBuilding = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        bIgnoreCost = argsList[4]
        return False
Place the snippet after bIgnoreCost = argsList[4] and before return False.
Code:
    def cannotConstruct(self,argsList):
        pCity = argsList[0]
        eBuilding = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        bIgnoreCost = argsList[4]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the required leader place the leader's type tag after leader = , but remember the type tag must be inside of quote marks.
Code:
        leader = [B]"[/B]LEADER_VICTORIAH[B]"[/B]        ## The Leader
Next to set the building that requires the leader, place the building's type tag after building = , again remember the type tag must be inside of quote marks.
Code:
        building = [B]"[/B]BUILDIN_FORGE[B]"[/B]        ## The Building
If you follow those instructions you shouldn't have any problems.:thumbsup:


Lockable Civics<Back To Top>
The following snippet allows you to set a civic as locked. Once a player adopts a locked civic they are stuck with it (well at least until the UN):
Code:
        civic = [U][I]Leader Type[/I][/U]        ## The Civic

        pPlayer = gc.getPlayer(ePlayer)

        civicType = gc.getCivicInfo(eCivic).getType()
        civicOptType = gc.getCivicInfo(eCivic).getCivicOptionType()
        testCivic = gc.getCivicInfo(pPlayer.getCivics(civicOptType)).getType()

        if testCivic == civic and testCivic != civicType:
            return True
Now this code goes inside of the cannotDoCivic function, in an unMODed game this function looks like:
Code:
    def cannotDoCivic(self,argsList):
        ePlayer = argsList[0]
        eCivic = argsList[1]
        return False
Place the snippet after eCivic = argsList[1] and before return False.
Code:
    def cannotDoCivic(self,argsList):
        ePlayer = argsList[0]
        eCivic = argsList[1]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the locked civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.
Code:
        civic = [B]"[/B]CIVIC_HEREDITARY_RULE[B]"[/B]        ## The Civic
If you follow those instructions you shouldn't have any problems.:thumbsup:

City Max Unit Limit<Back To Top>
The following snippet allows you to set a certain amount of units that each city can support. For example if a civ has 5 cities and each city can support 3 units the civ can build only 15 units, but if they build a 6th city they can then build 18 units.:
Code:
def cannotTrain(self,argsList):
    pCity = argsList[0]
    eUnit = argsList[1]
    bContinue = argsList[2]
    bTestVisible = argsList[3]

    pPlayer = gc.getPlayer(pCity.getOwner())
    numUnitsPerCity = [U][I]Num Units Supported by one City[/I][/U]        ## The Number Of Units A City Supports
    maxUnits = pPlayer.getNumCities() * numUnitsPerCity
    if pPlayer.getNumUnits() >= maxUnits:
        return True
    return False
Now this code goes inside of the cannotTrain function, in an unMODed game this function looks like:
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        return False
Place the snippet after bTestVisible = argsList[1] and before return False.
Code:
    def cannotTrain(self,argsList):
        pCity = argsList[0]
        eUnit = argsList[1]
        bContinue = argsList[2]
        bTestVisible = argsList[3]
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
        return False
To set the number of units supported by each city set numUnitsPerCity = to what ever you want.
Code:
    numUnitsPerCity = [B]5[/B]        ## The Number Of Units A City
If you follow those instructions you shouldn't have any problems.:thumbsup:

Hope this helps alot of ya. I know I find these to be cool and useful.:goodjob:
<Back To Top>
 
Python Snippets For CvEventManager.py
Next I will be doing several python snippets that work from the CvEventManager.py file. This file is where we receive information about what is happening. In this file we can find out when a city is built, a unit is constructed, a unit is moved, an improvement is destroyed, ect..


Thumbtack System (Ambreville's Idea)<Back To Top>
The following snippet allows a player to turn the unit cycling option on and off w/ the key board (ALT-C). The code is as follows:
Code:
			## This line checks to see if the ALT and C keys where pressed
			if theKey == InputTypes.KB_C and self.bAlt:
				## This turns the Unit Cycling on or off
				if gc.getActivePlayer().isOption(PlayerOptionTypes.PLAYEROPTION_NO_UNIT_CYCLING):
					gc.getActivePlayer().setOption(PlayerOptionTypes.PLAYEROPTION_NO_UNIT_CYCLING, False)
				else:
					gc.getActivePlayer().setOption(PlayerOptionTypes.PLAYEROPTION_NO_UNIT_CYCLING, True)
Now this code goes inside of the onKbdEvent function, in an unMODed game this function looks like:
Code:
	def onKbdEvent(self, argsList):
		'keypress handler - return 1 if the event was consumed'

		eventType,key,mx,my,px,py = argsList
		game = CyGame()
		
		if (self.bAllowCheats):
			# notify debug tools of input to allow it to override the control
			argsList = (eventType,key,self.bCtrl,self.bShift,self.bAlt,mx,my,px,py,CyGame().isNetworkMultiPlayer())
			if ( CvDebugTools.g_CvDebugTools.notifyInput(argsList) ):
				return 0
		
		if ( eventType == self.EventKeyDown ):
			theKey=int(key)
			
			CvCameraControls.g_CameraControls.handleInput( theKey )
						
			# Shift - T (Debug - No MP)
			if (self.bAllowCheats and theKey == int(InputTypes.KB_T)):
				if ( self.bShift ):
					self.beginEvent(CvUtil.EventAwardTechsAndGold)
					#self.beginEvent(CvUtil.EventCameraControlPopup)
					return 1
						
			# Shift - ] (Debug - currently mouse-overd unit, health += 10
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_LBRACKET) and self.bShift ):
				unit = CyMap().plot(px, py).getUnit(0)
				if ( not unit.isNone() ):
					d = min( unit.maxHitPoints()-1, unit.getDamage() + 10 )
					unit.setDamage( d, PlayerTypes.NO_PLAYER )
				
			# Shift - [ (Debug - currently mouse-overd unit, health -= 10
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_RBRACKET) and self.bShift ):
				unit = CyMap().plot(px, py).getUnit(0)
				if ( not unit.isNone() ):
					d = max( 0, unit.getDamage() - 10 )
					unit.setDamage( d, PlayerTypes.NO_PLAYER )
				
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F1)):
				if ( self.bShift ):
					CvScreensInterface.replayScreen.showScreen(False)
					return 1
				# don't return 1 unless you want the input consumed
			
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F2)):
				if ( self.bShift ):
					import CvDebugInfoScreen
 					CvScreensInterface.showDebugInfoScreen()
					return 1
			
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F3)):
				if ( self.bShift ):
					CvScreensInterface.showDanQuayleScreen(())
					return 1
					
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F4)):
				if ( self.bShift ):
					CvScreensInterface.showUnVictoryScreen(())
					return 1
		return 0
Place the snippet after return 1 and before return 0.
Code:
	def onKbdEvent(self, argsList):
		'keypress handler - return 1 if the event was consumed'

		eventType,key,mx,my,px,py = argsList
		game = CyGame()
		
		if (self.bAllowCheats):
			# notify debug tools of input to allow it to override the control
			argsList = (eventType,key,self.bCtrl,self.bShift,self.bAlt,mx,my,px,py,CyGame().isNetworkMultiPlayer())
			if ( CvDebugTools.g_CvDebugTools.notifyInput(argsList) ):
				return 0
		
		if ( eventType == self.EventKeyDown ):
			theKey=int(key)
			
			CvCameraControls.g_CameraControls.handleInput( theKey )
						
			# Shift - T (Debug - No MP)
			if (self.bAllowCheats and theKey == int(InputTypes.KB_T)):
				if ( self.bShift ):
					self.beginEvent(CvUtil.EventAwardTechsAndGold)
					#self.beginEvent(CvUtil.EventCameraControlPopup)
					return 1
						
			# Shift - ] (Debug - currently mouse-overd unit, health += 10
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_LBRACKET) and self.bShift ):
				unit = CyMap().plot(px, py).getUnit(0)
				if ( not unit.isNone() ):
					d = min( unit.maxHitPoints()-1, unit.getDamage() + 10 )
					unit.setDamage( d, PlayerTypes.NO_PLAYER )
				
			# Shift - [ (Debug - currently mouse-overd unit, health -= 10
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_RBRACKET) and self.bShift ):
				unit = CyMap().plot(px, py).getUnit(0)
				if ( not unit.isNone() ):
					d = max( 0, unit.getDamage() - 10 )
					unit.setDamage( d, PlayerTypes.NO_PLAYER )
				
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F1)):
				if ( self.bShift ):
					CvScreensInterface.replayScreen.showScreen(False)
					return 1
				# don't return 1 unless you want the input consumed
			
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F2)):
				if ( self.bShift ):
					import CvDebugInfoScreen
 					CvScreensInterface.showDebugInfoScreen()
					return 1
			
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F3)):
				if ( self.bShift ):
					CvScreensInterface.showDanQuayleScreen(())
					return 1
					
			elif (self.bAllowCheats and theKey == int(InputTypes.KB_F4)):
				if ( self.bShift ):
					CvScreensInterface.showUnVictoryScreen(())
					return 1
        [B]## Place Snippet Below Here[/B]

        [B]## But Above Here[/B]
		return 0
If you follow those instructions you shouldn't have any problems.:thumbsup:

 
Any File
Python Activated Always War/Peace<Back To Top>
Author: Dale (Gaius Octavius posted a more basic version first)
Author's Post: Here Post 72
The following snippet allows python to turn on/off always war/peace. The code is as follows:
Code:
def resetWarPeace(self, bValue):
     for iPlayerLoop1 in range(gc.getMAX_PLAYERS()):
         if(gc.getPlayer(iPlayerLoop1).isAlive()):
             for iPlayerLoop2 in range(gc.getMAX_PLAYERS()):
                 if(gc.getPlayer(iPlayerLoop2).isAlive()):
                     gc.getTeam(gc.getPlayer(iPlayerLoop1).getTeam()).setPermanentWarPeace(iPlayerLoop2, bValue)
Place in whatever python file you are working with. Then all you need to call is resetWarPeace(true) (for always war) or resetWarPeace(false) (for always peace).
If you have any problems or need help post here and someone is bound to help.:thumbsup:

 
And another...

I call that one the "Thumbtack" function. :)

Is it just me, or are there other people who feel the same way about the computer systematically selecting a unit to be played in other area than the one you're trying to focus on at the time, preferably an area exactly on the other end of the map!? :rolleyes:

This can get tedious and really frustrating.

There is nothing more annoying with CIV games when the computer jumps about, selecting some random unit as the one to be played next. One thing the games doesn't do well, is picking the next closest unit as the next one in line (unless dealing with units in the same stack).

Arguably, one can turn off the "unit cycling" option, but it's inconvenient and confusing, as well as making it obviously far more likely to "forget" to play some vital units. This is why I thought of the "thumbtack".

What does the thumbtack intend to do?

The idea is to keep the automatic unit cycling option on, and still force the game to stay focused on a given area of the map. This allows the player to focus on that specific map area until ready to move on -- without having to constantly fight with the game!

When a player deals with a map area requiring some focus, the player would be able to toggle the thumbtack on, using a hotkey, which would force the chosen map area to remain on the screen, regardless of what unit the computer selects as the next in line to be played. When done, toggle the thumbtack off, and keep on playing as usual (etc).

I think some coding for that would be ideal for big, complicated scenarios... Any interest?
 
How difficult would it be to allow a specific unit (a canoe for example) to ONLY be able to move along rivers, and at a MV rate of 2 upstream, and 3 downstream?
It's possible, but would be quite the hack done from python. It's more of an SDK thing.

So basically the "Thumbtack" idea would be just a way to toggle the "Unit Cycling" option on and off w/ the keyboard, right? I don't think that would be too hard.
 
So basically the "Thumbtack" idea would be just a way to toggle the "Unit Cycling" option on and off w/ the keyboard, right? I don't think that would be too hard.

No, no, no, the unit cycling stays on. What the thumbtack does it force the map to stay centered where the player wants, regardless of what unit the computer has selected as the next to be played. You ought to be able to toggle the thumbtack function on and off of course.
 
So it could be done by turning the unit cycleing off then back on.

No. Have you ever tried playing with unit cycling off? It sucks -- I think the interface is very confusing.

I mean for the unit cycling to remain ON. When the "thumbtack" is also ON, the map stays centered as the player needs, regardless of the next unit in line. When the thumbtack is toggled OFF, the computer zooms back to the next unit in line at that point... I thought I was being clear. :confused:
 
Yes, you are being clear, but I was saying what i thought might work. I will see what I can do. :thumbsup:

You are correct in saying that the simple approach is just to toggle the unit cycling ON & OFF. That's what I tried to do initially. It's just I find the unit cycling in the OFF mode just wrechedly bad! ;)

Thanks for checking into my harebrained ideas!
 
Here another idea. I didn't find this one anywhere in this part of the forum.

Effect: What I'm looking is to make a unit become temporarily "invisible" when it fortifies itself in a space. It stays hidden from view until it moves again or until an enemy unit "bumps into" it. At that point, the hiding unit is revealed and gets a free first attack with maximum damage.

Conditions: the unit needs to have either double-Woodsman promotions OR double-Guerilla promotions. Obviously, the ambushing unit must be in the proper type of terrain/feature for the ambush to work. If there's more than one such hiding unit, they all get to attack first. (This has nothing to do with the Ambush promotion against Armor.)

A nice touch would add a line in the event log, such as "AMBUSH!!!" with some sound. :mischief:

I wanted this for my scenario (17th Century European troops vs. American Indian warriors). It would be a way for low combat value native troops to fight against musket-toting military. Native scouts and spies (not explorers) should be able to see a unit hiding in ambush, just like destroyers reveal subs, which would negate the special ambush combat bonus.

Other mod designers might be interested in something like this, say for a hidden bunker position w/machinegun or AT gun units. Airplanes can't spot them... you need a recon unit or a spy to reveal them.

I'm assuming subs already use part of what I'm looking for, but this goes only half-way. By the way, do subs get a bonus when a naval unit runs into it when it couldn't see the sub? It doesn't look so.

Interested??
 
It sounds good, but granting an automatic maximum strength first attack may be too much, since it's not guaranteed that the ambush will be successful, and even if it is, it may only be partially so.

It is a nice idea, though.
 
It sounds good, but granting an automatic maximum strength first attack may be too much, since it's not guaranteed that the ambush will be successful, and even if it is, it may only be partially so.

I'm a bit confused by your sentence. The two parts of your answer seem to be conflicting. How can the max strength combat bonus be too much if there is no guarantee the ambush will work in the first place? The combat bonus compensates for the fact there is no guarantee anyone will "bump" into the hidden unit, and the unit may have to remain in place for quite some time before anything happens.

And how can the ambush be partially successful? It either is or not.

The reason why I'm thinking about a big combat bonus is that it only works if an enemy unit "bumps" into the hidden one. That's the only way I intended for the bonus to kick in. That's the main point of the ambush.

Otherwise, if you move the unit from its hiding place, it becomes visible and it therefore loses its ambush bonus. Even this way though, it's still useful because the subterfuge may still allow your unit to intercept unsupecting enemies passing by.

Does this make more sense?

-----------------------------------------------

EDIT

I know where the confusion comes from. I wrote in my original post something about a "free first attack with maximum damage". What I meant was that if an enemy unit bumps into the one waiting in ambush, the ambushing unit gets a big combat bonus at the very least, and a first strike chance (as in the Drill promotion). Better?
 
Greetings & Salutations! :lol:

I need a mod comp that ties a unit promotion to a particular bonus. For example: I have a "Horse" promotion that allows qualifying infantry or artillery to benefit from horse transportation (in exchange for a combat penalty). This promotion should be given to a unit only when the Horse bonus is available. If not, it does not appear in the list of promotions when the unit qualifies for one. If a note appears in the Tech Tree showing that Horse is needed for the promotion, great, but I would just as happy with the comp, even without the Tech Tree notification. Would you have time to do something like this?

Thanks, and welcome back! ;)
 
Have you ever considered learning Python?
 
Top Bottom