Is there someway to use python to give random promotions?
I was going to use Occasional Promotions but it's DLL.
It needs to be python...
I was going to use Occasional Promotions but it's DLL.
It needs to be python...
Something that gives you a random promotion after a battleWhat exactly do you need? What should prompt these random promotions?
Situational, Depending on unit type and prerequisites.Is there some set promotions that are valid or would that be situational? (Depending on unit type, prerequisites, et cetera.)
No, I can't program in python, so I need a ready-to-use fix.And do you know how to program in Python or do you need a ready-to-use fix?
What's it for? I might be able to help. Yes, it might be possible to give a unit a random promotion from a list when it gets out of combat. My mind's working at it already. I needed a Python idea anyway. So give me the specifics and I might be able to help. Is this a trait or what? Should it be any promotion, or just certain promotions? Should this be for all units, or just some?
You really should consider learning Python, it's really easy if you read a good book first, like Head First Programming.
def getPromotions(self, pPlayer, bGarrison):
if self.level < 2: return
eCombat = getCombatType(self.type)
if not isValid(eCombat): return
pTeam = gc.getTeam(pPlayer.getTeam())
tScript = getScript(bGarrison, pTeam.isHasTech(iGunpowder), pTeam.isHasTech(iMilitaryScience))
self.promotions = []
while len(self.promotions) <= self.level - 1:
if self.processScript(tScript, eCombat):
return
def processScript(self, tScript, eCombat):
iLength = len(self.promotions)
i = 0
for tSettings in tScript:
lCombatTypes, bDefensive, lPrerequisites, bModern, eStart, iRange, bRandom = tSettings
i += 1
if eCombat in lCombatTypes and bDefensive and self.checkPrerequisite(lPrerequisites) and bModern:
if not isValid(bRandom):
ePromotion = eStart
elif bRandom:
ePromotion = self.getRandomPromotion(eStart, iRange)
else:
ePromotion = self.getOrderedPromotion(eStart, iRange)
if isValid(ePromotion) and not ePromotion in self.promotions:
self.promotions.append(ePromotion)
if len(self.promotions) == self.level - 1: return True
if len(self.promotions) == iLength: return True
def checkPrerequisite(self, lPrerequisites):
if isEmpty(lPrerequisites): return True
for ePrerequisite in lPrerequisites:
if ePrerequisite in self.promotions:
return True
return False
def getRandomPromotion(self, eStart, iRange):
rnd = gc.getGame().getSorenRandNum(iRange, 'random promotion')
for i in range(rnd, iRange + rnd):
ePromotion = eStart + (i % iRange)
if not ePromotion in self.promotions:
return ePromotion
def getOrderedPromotion(self, eStart, iRange):
for ePromotion in range(eStart, eStart + iRange):
if not ePromotion in self.promotions:
return ePromotion
def setPromotions(self, pUnit):
for ePromotion in self.promotions:
if self.forcePromotions or pUnit.isPromotionValid(ePromotion):
pUnit.setHasPromotion(ePromotion, True)
def getScript(bGar, bGP, bMS):
return (([3,4], not bGar,[0,29],True, 23, 3, False), #city raider
([1,5], bGar, [], True, 26, 3, False), #city garrison
([3], not bGar,[1], True, 5, 2, True), #shock/cover
([2,3], True, [1], not bMS,8, 2, True), #formation/charge
([5], True, [2], bMS, 10, 3, True), #gunpowder
([4], not bGar,[], True, 36, 0, None), #accuracy
([9], True, [2], True, 53, 0, None), #ace
([9], True, [], True, 49, 2, False), #range
([2,5,6,7,9], True, [1], bGP, 7, 0, None), #pinch
([2,6,7,8], not bGar,[2], bMS, 13, 0, None), #blitz
([0,1,2,3,5,6], not bGar,[3], bMS, 14, 0, None), #commando
([0,1,2,3,4,5,6,8],True,[3,32], True, 15, 2, False), #medic
([0,1,2,3,5,6,7,8,9],True,[], True, 0, 5, False), #combat
([1,4,6], True, [], True, 29, 4, False), #drill
([8], True, [37], True, 41, 2, False), #navigation
([2,6,7,8], True, [], True, 37, 2, False), #flanking
([4], True, [], True, 33, 3, False), #barrage
([0], True, [0,29], True, 20, 2, False), #woodsman(scout)
([0], True, [0,29], True, 17, 2, False), #guerilla(scout)
([5], not bGar,[0,29],True, 20, 3, False), #woodsman
([1,5], not bGar,[0,29],True, 17, 3, False)) #guerilla
unitCombatPromotionDict = dict()
for eUnitCombatType in range(-1, gc.getNumUnitCombatInfos()):
unitCombatPromotionDict[eUnitCombatType] = list()
for ePromotion in range(gc.getNumPromotionInfos()):
pPromotionInfo = gc.getPromotionInfo(ePromotion)
if pPromotionInfo.isLeader():
unitCombatPromotionDict[-1].append(ePromotion)
else:
for eUnitCombatType in range(gc.getNumUnitCombatInfos()):
if pPromotionInfo.getUnitCombat(eUnitCombatType):
unitCombatPromotionDict[eUnitCombatType].append(ePromotion)
lValidPromotions = list()
if pUnit.isLeader():
for ePromotion in unitCombatPromotionDict[-1]:
if pUnit.isPromotionValid(ePromotion) and not pUnit.isHasPromotion(ePromotion):
lValidPromotions.append(ePromotion)
eUnitCombatType = gc.getUnitInfo(pUnit.getUnitType()).getUnitCombatType()
for ePromotion in unitCombatPromotionDict[eUnitCombatType]:
if pUnit.isPromotionValid(ePromotion) and not pUnit.isHasPromotion(ePromotion):
lValidPromotions.append(ePromotion)
iRandNum = CyGame().getSorenRandNum(len(lValidPromotions), "random promotion")
pUnit.setHasPromotion(lValidPromotions[iRandNum])
Yeah, like spit out the entire spreadsheet with units and their available promotions.
Or should everything just "make sense" with regard to how the original game is designed? Basically lookup all available promotions, check which ones are valid for the unit in question at a given point in the game, add those to a list and choose one of those at random?
edit: I looked into it and the main challenge is of curse to make any such code as efficient as possible. A good start might be to map all available promotions to some UnitCombatTypes value, and also weed out special cases like leader promotions. This should be possible to do with CvPromotionInfo.getUnitCombat() and CvPromotionsInfo.isLeader(). Something like this:
If this is valid (I haven't tested any of it myself) its only a matter of knowing where to put the code.Spoiler :
@init:
@script:PHP:unitCombatPromotionDict = dict() for eUnitCombatType in range(-1, gc.getNumUnitCombatInfos()): unitCombatPromotionDict[eUnitCombatType] = list() for ePromotion in range(gc.getNumPromotionInfos()): pPromotionInfo = gc.getPromotionInfo(ePromotion) if pPromotionInfo.isLeader(): unitCombatPromotionDict[-1].append(ePromotion) else: for eUnitCombatType in range(gc.getNumUnitCombatInfos()): if pPromotionInfo.getUnitCombat(eUnitCombatType): unitCombatPromotionDict[eUnitCombatType].append(ePromotion)
PHP:lValidPromotions = list() if pUnit.isLeader(): for ePromotion in unitCombatPromotionDict[-1]: if pUnit.isPromotionValid(ePromotion) and not pUnit.isHasPromotion(ePromotion): lValidPromotions.append(ePromotion) eUnitCombatType = gc.getUnitInfo(pUnit.getUnitType()).getUnitCombatType() for ePromotion in unitCombatPromotionDict[eUnitCombatType]: if pUnit.isPromotionValid(ePromotion) and not pUnit.isHasPromotion(ePromotion): lValidPromotions.append(ePromotion) iRandNum = CyGame().getSorenRandNum(len(lValidPromotions), "random promotion") pUnit.setHasPromotion(lValidPromotions[iRandNum])
![]()
The basic idea for a custom setup like this is to put all units/unit classes/unit combat types into a dictionary or some other data structure. Like this:Alright, not a spreadsheet and just 1 unit & 3 promotions so far, but...
Name - Basic General
Traits (Promotions) - Good Commander, Intelligent, and Learned.
unitPromotionDict = { eBasicGeneral: [eGoodCommander, eIntelligent, eLearned] }
unitPromotionDict = {
eBasicGeneral: [eGoodCommander, eIntelligent, eLearned],
eAnotherUnit: [eSomePromotion, eOtherPromotion]
}
eBasicGeneral = gc.getInfoTypeForString("UNIT_BASIC_GENERAL")
eGoodCommander = gc.getInfoTypeForString("PROMOTION_GOOD_GENERAL")
eIntelligent = gc.getInfoTypeForString("PROMOTION_INTELLIGENT")
eLearned = gc.getInfoTypeForString("PROMOTION_LEARNED")
eUnitType = pUnit.getUnitType()
lValidPromotions = unitPromotionDict.get(eUnitType, [])
lAvailablePromotions = lValidPromotins[:]
while lAvailablePromotions:
iNumPromotions = len(lAvailablePromotions)
iRandNum = Game().getSorenRandNum(iNumPromotions, "random promotion")
ePromotion = lAvailablePromotions[iRandNum]
if pUnit.isHasPromotion(ePromotion):
lAvailablePromotions.remove(ePromotion)
pUnit.setHasPromotion(ePromotion)
If you submit your copy of CvEventManager I can implant a customized version of my code into it.
The basic idea for a custom setup like this is to put all units/unit classes/unit combat types into a dictionary or some other data structure. Like this:
Firstly, this is a dictionary with the unit as the key and a list of promotions as the value. Secondly, you add more entries in the same fashion but you separate them with a comma:Code:unitPromotionDict = { eBasicGeneral: [eGoodCommander, eIntelligent, eLearned] }
Note that line breaks are arbitrary.Code:unitPromotionDict = { eBasicGeneral: [eGoodCommander, eIntelligent, eLearned], eAnotherUnit: [eSomePromotion, eOtherPromotion] }
Now, before using these variables you should define them:
Two things of note: The string tags must correspond to the actual XML entries - these are just examples. And since the XML is loaded only after Python is loaded you can't define the variables in this fashion at initialization. This complicates things somewhat.Code:eBasicGeneral = gc.getInfoTypeForString("UNIT_BASIC_GENERAL") eGoodCommander = gc.getInfoTypeForString("PROMOTION_GOOD_GENERAL") eIntelligent = gc.getInfoTypeForString("PROMOTION_INTELLIGENT") eLearned = gc.getInfoTypeForString("PROMOTION_LEARNED")
But once you have all the constants done you can access the dictionary to do your dirty work:
Code:eUnitType = pUnit.getUnitType() lValidPromotions = unitPromotionDict.get(eUnitType, []) lAvailablePromotions = lValidPromotins[:] while lAvailablePromotions: iNumPromotions = len(lAvailablePromotions) iRandNum = Game().getSorenRandNum(iNumPromotions, "random promotion") ePromotion = lAvailablePromotions[iRandNum] if pUnit.isHasPromotion(ePromotion): lAvailablePromotions.remove(ePromotion) pUnit.setHasPromotion(ePromotion)
Aha, but what game event will prompt a unit to get a random promotion/trait? Because this is what the Event Handler does - it fires Python code on game events.
Is it on unit creation, perhaps? (Thats a game event.)
If you get the dictionary of units and traits in order I can create a RandomPromotion module for you, and plug it into CvEventManager. You also need to define all the promotions and units as variables - see example. (Its mostly a copy-paste job.)