View Full Version : Help Extracting Fort Commander Code


MaxAstro
Aug 17, 2009, 02:02 PM
I'm trying to extract the Fort commander code and import it into my custom mod-mod. So far everything has worked fine; I have claimable forts, fort commanders are generated and upgrade properly. However, I can't for the life of me get them to generate influence.

I've pulled updateAllForts, updateFortCulture, updateCastleCulture, and updateCitadelCulture out of EventManager.py, but that doesn't seem to be enough; is there any other python that is needed for fort commanders to generate culture?

Valkrionn
Aug 17, 2009, 02:23 PM
Did you toss self.updateAllForts() into def onendgameturn? Also in eventmanager.py... It's the part that calls the rest of the culture updates. Without it, they'll never run.

MaxAstro
Aug 17, 2009, 04:36 PM
Ah, thanks, that was it. One little line of code and it completely messed me up. XD

MaxAstro
Aug 17, 2009, 05:24 PM
New question: Is there any way easily apply the civilization's race to a fort commander when he is created? Otherwise, pretty much every civ with a racial promotion will need a UU fort commander.

Valkrionn
Aug 17, 2009, 11:37 PM
I'm sure there's a way to get the civs racial, and apply it.. But I'm not sure ATM. Will check when I'm at my comp, would be a good thing to add all around.

MagisterCultuum
Aug 18, 2009, 12:03 AM
Shouldn't the racial promotion be applied automatically whenever a non-mechanized unit lacking a race is initialized?

Valkrionn
Aug 18, 2009, 12:09 AM
Well, they ARE siege units, so they may have the mechanized tag. Basically copy/pasted from Orbis.

Valkrionn
Aug 18, 2009, 12:00 PM
Hmm. They are definitely siege units, but do NOT have the mechanized tag. Maybe no siege units whatsoever get access to the race?

I could always just make them Archery, but that would give them a few more promotions.... I'll check for a python fix first.

Valkrionn
Aug 18, 2009, 12:13 PM
Here you go. Updated the claim fort spell so you don't have to add anything for new Commander UUs (Thanks MrUnderhill!), and added a bit of code to add the race. It checks the caster's race, and if it exists, adds to the Commander. Yes, this can make some interesting commanders where the caster is dominated and has some other race... But that's a low occurrence, and I'm okay with it. :lol: There's a second check for Undead, as that's no longer a race in FF/FFPlus.

Keep in mind, it's not actually tested. However, the initial change was from MrUnderhill, pretty sure it's working... And the race fix was already in use for an event, which is where I got it. :lol:

def spellClaimFort(pCaster):
pPlayer = gc.getPlayer(pCaster.getOwner())
iUnit = gc.getInfoTypeForString('UNITCLASS_FORT_COMMANDER' )
infoCiv = gc.getCivilizationInfo(pPlayer.getCivilizationType ())
iUnit = infoCiv.getCivilizationUnits(iUnit)
iRace = pCaster.getRace()
newUnit = pPlayer.initUnit(iUnit, pCaster.getX(), pCaster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
if iRace != -1:
newUnit.setHasPromotion(iRace, True)
if pCaster.isHasPromotion(gc.getInfoTypeForString('PR OMOTION_UNDEAD')):
newUnit.setHasPromotion(gc.getInfoTypeForString('P ROMOTION_UNDEAD'), True)

MaxAstro
Aug 18, 2009, 01:27 PM
Could also cause some weirdness with things like Soldiers of Kilmorph for non-dwarven civs, but that should also be a relatively low occurrence; in my experience it's usually either workers or scouts casting Claim Fort, at least outside of war.

Which reminds me, having forts stolen from under you is not fun. XD The first game I actually built a fort in FF+, I didn't have the tech and I only had two captured gretchins with which to build it, so they took ~forever~.

The very turn they finished the fort, before I had a chance to tell them to claim it, one of Hannah the Irin's scouts moved onto the fort and claimed it. >.<

...At least it proved that the AI could use forts... XD

Valkrionn
Aug 18, 2009, 03:58 PM
Could also cause some weirdness with things like Soldiers of Kilmorph for non-dwarven civs, but that should also be a relatively low occurrence; in my experience it's usually either workers or scouts casting Claim Fort, at least outside of war.

Which reminds me, having forts stolen from under you is not fun. XD The first game I actually built a fort in FF+, I didn't have the tech and I only had two captured gretchins with which to build it, so they took ~forever~.

The very turn they finished the fort, before I had a chance to tell them to claim it, one of Hannah the Irin's scouts moved onto the fort and claimed it. >.<

...At least it proved that the AI could use forts... XD

Well... As annoying as that would be, I'll leave it as a feature. :lol:

odalrick
Aug 18, 2009, 04:24 PM
The very turn they finished the fort, before I had a chance to tell them to claim it, one of Hannah the Irin's scouts moved onto the fort and claimed it. >.<

Unless you were using simultaneous turns, she couldn't have taken the fort before you had a chance to claim it. Just before you were prompted to.

The workers completed the fort on your turn and had you selected them, you could have claimed the fort. I'm pointing it out since you could have loaded an autosave to avoid the problem, if you thought it was worth it.

MaxAstro
Aug 18, 2009, 05:28 PM
Unless you were using simultaneous turns, she couldn't have taken the fort before you had a chance to claim it. Just before you were prompted to.

The workers completed the fort on your turn and had you selected them, you could have claimed the fort. I'm pointing it out since you could have loaded an autosave to avoid the problem, if you thought it was worth it.

That particular game it was indeed just before I was prompted. I have had something similar happen in simultaneous turns since then, though. :)

EDIT: Also, Valk, since you are already getting the civilization as part of that code, isn't there a way to check the race associated with the civ? It seems like there must be a python check for that.

Valkrionn
Aug 18, 2009, 05:36 PM
I'm sure there is, but I haven't seen it... And can't test the code atm. Still haven't gotten a new copy of the game. :lol: To be honest, I haven't even played the new version of FFPlus yet.

MaxAstro
Aug 18, 2009, 05:46 PM
That code actually seems to be causing crashes for me. I would get repeated crashes that I can only assume where happening when an AI was casting Claim Fort. The strange thing was it wasn't all the time, since I saw AI fort commanders.

In any case, changing it to simply
def spellClaimFort(pCaster):
pPlayer = gc.getPlayer(pCaster.getOwner())
iUnit = gc.getInfoTypeForString('UNIT_FORT_COMMANDER')
newUnit = pPlayer.initUnit(iUnit, pCaster.getX(), pCaster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
seems to have made it stop crashing, although that of course requires UU fort commanders to be explicitly defined. I'm also sure that it wasn't the new code you added to apply race; I was getting the crash with MrUnderhill's code from the other thread. It seems for some reason that implementation of creating the commander based on unitclass causes AI crashing. It's possible that something else in my personal mod is aggravating the issue; if someone could do some outside testing it would be appreciated.

Valkrionn
Aug 18, 2009, 05:47 PM
That code actually seems to be causing crashes for me. I would get repeated crashes that I can only assume where happening when an AI was casting Claim Fort. The strange thing was it wasn't all the time, since I saw AI fort commanders.

In any case, changing it to simply
def spellClaimFort(pCaster):
pPlayer = gc.getPlayer(pCaster.getOwner())
iUnit = gc.getInfoTypeForString('UNIT_FORT_COMMANDER')
newUnit = pPlayer.initUnit(iUnit, pCaster.getX(), pCaster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
seems to have made it stop crashing, although that of course requires UU fort commanders to be explicitly defined. I'm also sure that it wasn't the new code you added to apply race; I was getting the crash with MrUnderhill's code from the other thread. It seems for some reason that implementation of creating the commander based on unitclass causes AI crashing. It's possible that something else in my personal mod is aggravating the issue; if someone could do some outside testing it would be appreciated.

Hmm... I'll look through the code for an example I can use, then.

Valkrionn
Aug 18, 2009, 06:32 PM
Found the issue. If the civ didn't have a UU, it would crash. Here's the fixed code, new part is in bold... All it does is assign the standard unit if there's no UU.

def spellClaimFort(pCaster):
pPlayer = gc.getPlayer(pCaster.getOwner())
iUnit = gc.getInfoTypeForString('UNITCLASS_FORT_COMMANDER' )
infoCiv = gc.getCivilizationInfo(pPlayer.getCivilizationType ())
iUnit = infoCiv.getCivilizationUnits(iUnit)
if iUnit == -1:
iUnit = gc.getInfoTypeForString('UNIT_FORT_COMMANDER')
iRace = pCaster.getRace()
newUnit = pPlayer.initUnit(iUnit, pCaster.getX(), pCaster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
if iRace != -1:
newUnit.setHasPromotion(iRace, True)
if pCaster.isHasPromotion(gc.getInfoTypeForString('PR OMOTION_UNDEAD')):
newUnit.setHasPromotion(gc.getInfoTypeForString('P ROMOTION_UNDEAD'), True)


Also... This MIGHT work for the race, but I'm not sure. If you could test, replace the iRace code above with this... Believe you have to leave the undead check though, the promotion is not a race.

iRace = infoCiv.getDefaultRace()

MaxAstro
Aug 19, 2009, 04:14 PM
Found the issue. If the civ didn't have a UU, it would crash. Here's the fixed code, new part is in bold... All it does is assign the standard unit if there's no UU.

Also... This MIGHT work for the race, but I'm not sure. If you could test, replace the iRace code above with this... Believe you have to leave the undead check though, the promotion is not a race.

Awesome, thanks for the fix. Also, that bit with the race should work even for the Scions; as long as it grabs whatever promotion is set in the <defaultrace> field for the apropriate civ it should work with pretty much anything.

I'll test it as soon as I can.

Valkrionn
Aug 19, 2009, 04:36 PM
Hopefully it will work when you test it... Haven't included it in the D'teshi Commander module yet because I'm not sure it'll work. :lol:

MaxAstro
Aug 19, 2009, 10:42 PM
Tested and confirmed working. Started a game as the Scions, gave them Bambur, had him cast Claim Fort, the fort commander ended up Undead and not Dwarven.

Also tested with the Ljosalfar, the one race I've given a UU to so far, and the UU was created properly and had Elven.

Thanks a lot for the help, I was really pulling my hair out over this one. :)

Valkrionn
Aug 19, 2009, 10:56 PM
Awesome! I'll have to update the D'teshi Commander Module...

What UU did you give the Ljos? I'm trying to get one for each civ, but only have a very vague idea for them.

MaxAstro
Aug 20, 2009, 12:54 PM
I went with an archery theme, actually inspired by one of my favorite M:tG cards. The unit is called the Sagittar, and uses the Ljo Longbowman graphics instead of the regular FC graphics (I have zero skill at doing artwork, so...). Instead of the Siegecombat promo, it has a similar promo that does basically the same thing but additionally allows it to promote to the Archery promos. I also decided to have it start with Woodsman I; was considering allowing it to promote to Woodsman II, but that seemed too much.

Ranged combat wise, it loses the ability to deal collateral damage, but has the potential to get a much higher ranged attack power against single units, thanks to the Archery promotions. I also gave it a 2-square range, which adds another layer of strategy to deciding where to place them, since you want to put them somewhere where their full range won't be blocked by high terrain.

"What's their strike range, you ask? Let's put it this way: sagittars aim their bows using maps."
—Otak, Tin Street shopkeep

Originally I was going to give them a unique replacement for the Commander I, II, III line of promotions that increased their range as they leveled up - starting them with normal 1-square range, bumping it to 2 at Commander I, and possibly even up to 3 at Commander III (in my version I enabled Commander III for everyone, instead of just the Kuriotates). However, I discovered that there is currently no way to increase ranged combat attack range through promotions, which struck me as a bit odd.

I've also done fort commanders for the Sheaim, Bannor, and Chislev so far if you are interested in hearing those; perhaps in return you could share any ideas you have for a FC for the Lizardmen, Dural, or Archos, because those seem like they should have them, but I am completely stumped as to what they should be. XD

Valkrionn
Aug 20, 2009, 02:49 PM
I went with an archery theme, actually inspired by one of my favorite M:tG cards. The unit is called the Sagittar, and uses the Ljo Longbowman graphics instead of the regular FC graphics (I have zero skill at doing artwork, so...). Instead of the Siegecombat promo, it has a similar promo that does basically the same thing but additionally allows it to promote to the Archery promos. I also decided to have it start with Woodsman I; was considering allowing it to promote to Woodsman II, but that seemed too much.

Ranged combat wise, it loses the ability to deal collateral damage, but has the potential to get a much higher ranged attack power against single units, thanks to the Archery promotions. I also gave it a 2-square range, which adds another layer of strategy to deciding where to place them, since you want to put them somewhere where their full range won't be blocked by high terrain.

"What's their strike range, you ask? Let's put it this way: sagittars aim their bows using maps."
—Otak, Tin Street shopkeep

Originally I was going to give them a unique replacement for the Commander I, II, III line of promotions that increased their range as they leveled up - starting them with normal 1-square range, bumping it to 2 at Commander I, and possibly even up to 3 at Commander III (in my version I enabled Commander III for everyone, instead of just the Kuriotates). However, I discovered that there is currently no way to increase ranged combat attack range through promotions, which struck me as a bit odd.

I've also done fort commanders for the Sheaim, Bannor, and Chislev so far if you are interested in hearing those; perhaps in return you could share any ideas you have for a FC for the Lizardmen, Dural, or Archos, because those seem like they should have them, but I am completely stumped as to what they should be. XD

Sounds good... I didn't have any specific idea for them, although a Fawn/Treant/Guardian Vine was suggested. I think I'll use your version. :lol:

Commander 3 is used for Kuriotates and the Khazad... Or rather, the Legendary Influence promo it allows. The Khazad have Dwarven Commander 3. :lol: I just don't think EVERY civ should have two tiers of range on them... The Kuriotates because eventually I'd like the forts to replace settlements, and the Khazad to represent the fact that their forts are nearly cities in their own right. :lol: I could see adding it to a few others (Austrin, for their tracking and knowledge of the land, for example), but not everyone.

As for increasing range... <iAirRangeChange>1</iAirRangeChange>. I used it for the siege promotions.

As for Fort Commander UU's... I actually started a thread for people to post in, and it's generated quite a few ideas. :lol: You should post your own, and possibly use some other people have posted.

http://forums.civfanatics.com/showthread.php?t=332268

MaxAstro
Aug 20, 2009, 05:03 PM
Commander 3 is used for Kuriotates and the Khazad... Or rather, the Legendary Influence promo it allows. The Khazad have Dwarven Commander 3. :lol: I just don't think EVERY civ should have two tiers of range on them... The Kuriotates because eventually I'd like the forts to replace settlements, and the Khazad to represent the fact that their forts are nearly cities in their own right. :lol: I could see adding it to a few others (Austrin, for their tracking and knowledge of the land, for example), but not everyone.~shrugs~ Personal preference thing. I actually made fort commanders on the whole a fair bit stronger than they are in FF+ (they get the Commander promotions each 1 level earlier, and Influence gives +.30 XP rate in addition to +60 XP limit); on the flip side, I am considering either making Claim Fort have a gold cost, or giving fort commanders a gold-per-turn cost.

Ironically the thing that bothers me most about the legendary influence level is that it is not BFC shaped. XD I don't suppose there would be any easy way to "cut the corners" off the legendary influence range? It's probably a lot of coding for little return, but it really does bother me and I am kinda obsessive/compulsive about that kind of thing. :)

As for increasing range... <iAirRangeChange>1</iAirRangeChange>. I used it for the siege promotions.Interesting. That field doesn't seem to be listed in the dummy promotion that is supposed to have all fields; guess I should have checked the schema.

As for Fort Commander UU's... I actually started a thread for people to post in, and it's generated quite a few ideas. :lol: You should post your own, and possibly use some other people have posted.

http://forums.civfanatics.com/showthread.php?t=332268Cool, I'll check that out.

Valkrionn
Aug 20, 2009, 07:44 PM
I'm actually planning on giving them promotions granting free xp per turn. :lol:

And it bugs the crap out of me too. :lol: I just can't think of an easy way to set the cross...

odalrick
Aug 21, 2009, 01:26 AM
I just can't think of an easy way to set the cross...

You could look at the code for vitalize.

The purpose of the plotsInRange is to replace code like:

for iXLoop in range(iX-2, iX+3):
for iYLoop in range(iY-2, iY+3):
do_stuff(iXLoop, iYLoop)


with

for iXLoop, iYLoop in plotsInRange( iX, iY, 2 ):
do_stuff(iXLoop, iYLoop)


and automatically making it circleish shaped.

It doesn't ensure that the coordinate is on the map, so that has to be done in the loop. Vitalize seems to get by with a simple "not pPlot.isNone()", so I think the map normalises coordinates outside the map. I haven't done any extensive testing though.

def plotsInRange( centerX, centerY, maxRange, minRange=None ):
maxRangeSquared = (maxRange+.5)**2
if minRange is None:
minRangeSquared = -1
else:
minRangeSquared = (minRange+.5)**2
for offsetX in xrange( -maxRange, maxRange+1 ):
for offsetY in xrange( -maxRange, maxRange+1 ):
if minRangeSquared < offsetX**2 + offsetY**2 < maxRangeSquared:
yield ( centerX + offsetX, centerY + offsetY )