[MOD] MagisterModmod

They are equal to mines with regards to yields, and provide a bit of health on top. I'd say Lumbermills are much better than they are in unmodded BtS just from the fact that they come so early. I always keep some forests with Lumbermills around just for the health.
At the beginning yes, forest with lumber mill adds 2 hammers just as mine. However mines get extra hammer with Arete and Blasting powder, while lumber mills fall behind. The same applies to workshops. The health factor is nice tradeoff for not getting bonus hammers from chopping, but it can hardly compare to simply getting less hammers. I think simply one extra hammers for lumbermills at i.e. machinery wouldn't be bad idea.
 
Did you consider an upgrade to lumber mills? Currently they just add one hammer on top of existing forests and enable river commerce.... and thats it. No bonuses from tech, no bonuses from civics. They are completely worthless, maybe with the exception with river adjacent ancient forests - maybe. This makes cutting your forests for hammers asap a no brainer as preserving them has no value.

I'm thinking I may boost their yields at Machinery, but also add an event where lumbermills on ancient forests can cause angry treants to rise against you.
They are equal to mines with regards to yields, and provide a bit of health on top. I'd say Lumbermills are much better than they are in unmodded BtS just from the fact that they come so early. I always keep some forests with Lumbermills around just for the health.


If you want to get more entries for the Civilopedia, Refsteel of Realms Beyond has written quite a few entries for the Erebus in the Balance mod. You can probably get some from the mod or from their designated thread.
When it comes to pedia entries, I only to include only material that is indisputably canon. Unless the material was written by or explicitly endorsed by Kael I'm not going to borrow it. (I made a couple exceptions for the entry on the blue dragon and on the Children of the One religion, but that is basically just flushing out incidents that were already known.)

It seems that all new cities now start with 2 population. I absolutely hate that. Where can i mod it back ?

It is in CvEventManager.py under onCityBuilt, in what is line 5237 in my current version (although probably a bit different in yours as I have made some changes since the last release). You can undo this by deleting or commenting out this line.
Code:
    def onCityBuilt(self, argsList):
        'City Built'
        city = argsList[0]
        pPlot = city.plot()
        iPlayer = city.getOwner()
        pPlayer = gc.getPlayer(iPlayer)
        iCiv = pPlayer.getCivilizationType()
        city.setPopulation(2)

I believe I made it this way because I did not like the slow growth of the early game, but the free food I have since given all the palaces may fix that issue. I think I'll play a few games with that line commented out to see whether I want to keep it or not.
 
I'm thinking I may boost their yields at Machinery, but also add an event where lumbermills on ancient forests can cause angry treants to rise against you.
That sounds nice. Have you thought about my suggestions with regards to towns and civics yet?
 
@MagisterCultuum

Thank you very much. I like slower starts myself, playing with toned down research and End of winter. The food bonus from palace is nice, but two pops on each city were way too much.

Glad to hear about lumbermills. An event for normal forests that destroys the lumbermill and degrades to new forest unless you have acess to nature mana would help if you fear a lumermill spam.
 
I'm thinking that the method of automatically giving Malakim priests the Eremite promotion in deserts is rather inefficient code that could be slowing the game down. I also have a slight suspicion, although no real confidence, that it could be contributing to some of the frequent unexplained crashes.

What would you think if I change it to work like this:

The Eremite promotion would be applied each turn to all disciples in any city with a Desert Shrine building. It would also still be given to any Empyrean unit that enters the tile of the Mirror of Heaven.

When the unit is not on the Mirror of Heaven or in a city with a Desert Shrine, the promotion would remove itself unless the tile is an unimproved desert without freshwater and without any other units present.

The promotion would also grant access to the Evangelist (as an alternate prereq to Divine, so first tier disciples could purchase it the same as full priests) and Spirit Guide promotions, and increase Desert combat strength as well as spell strength and passive xp gain.
 
Hey everyone i went through the entire forum looking to see if anyone else has this issue. I attempted to download this modmod and my anitvirus is saying that it is full of nasty things. Did anyone else get this problem and more importantly is it there another place i can download it form incase its simply the website attaching malware to the file?
 
Hey everyone i went through the entire forum looking to see if anyone else has this issue. I attempted to download this modmod and my anitvirus is saying that it is full of nasty things. Did anyone else get this problem and more importantly is it there another place i can download it form incase its simply the website attaching malware to the file?

Just disable your antivirus for a few minutes, it's a false positive. I downloaded it from moddb.com with no problems:

http://www.moddb.com/games/civilization-iv/downloads/magister-modmod-archive
 
I believe some anti-virus programs consider almost any executable to be suspect unless it is from a well known source. I've never had any issue with the program I used to make the installer, but if you feel more comfortable not using an exe then you could opt for the manually copying the files from the archive version instead.
 
I believe some anti-virus programs consider almost any executable to be suspect unless it is from a well known source. I've never had any issue with the program I used to make the installer, but if you feel more comfortable not using an exe then you could opt for the manually copying the files from the archive version instead.
So im going through my files and through this forum and your instructions are unclear on how to manually install the file. I have created a copy of FfH2 and dropped the files in the .zip inside of the copied FfH2 and renamed the file Magistermodmod but when i play it it seems broken and incomplete. You said you had difficulty using steam as you play on disc. Your .exe also tried to send the file somewhere else so there is little hope of that going well. Please assist.
 
So im going through my files and through this forum and your instructions are unclear on how to manually install the file. I have created a copy of FfH2 and dropped the files in the .zip inside of the copied FfH2 and renamed the file Magistermodmod but when i play it it seems broken and incomplete. You said you had difficulty using steam as you play on disc. Your .exe also tried to send the file somewhere else so there is little hope of that going well. Please assist.

"Before installing, you should make you that you have a clean installation of Fall from Heaven 2 version 0.41o (actually, patch m or n should be fine too) or of the latest version of Tholal's More Naval AI modmod installed under the name Fall from Heaven 2. The installer will need to copy most of my modmod's necessary files from that location. It will not change any files there, but will install under a directory named Magister Modmod for FfH2."

I just did a manual install, and it works. This is how i did it:
1. Installed the base game Fall from Heaven 2 with the version 2.041n
2. Installed the patch Fall from Heaven 2 with the version 2.041o
3. Made a copy of the basegame fodler.
4. Renamed the copyfolder of the basegame into "Magister Modmod for FfH2". Exact foldername is important!
5. Extracted the content of the changes zipfile into this folder. Not a empty folder, over the data of the basegame. Integrate and Overwrite.
5. Mod works.

Hope that helps.
 
Last edited:
Did that and it worked perfectly. So far im highly impressed with MagisterCultuum's work. The worldbuilder had me for a bit but when i could river edit with ease i yelled out "you stop that!" in exclamation with how easy this became. Gold star to the both of you cat thank you enough.
 
Hey Magister, wanted to say that I love your Magistermodmod for ffh2. Thanks for creating it. I was wondering if you wouldn't mind sending me the code/Python for the assume true form and shapeshift abilities prior to the October update. It had recently been changed so that those spells would wipe abilities granted by form that gibbon had changed into. So that he wouldn't have channeling 1,2,3 as an ogre. While that does end up granting him tons of promotions, I like that aspect of his abilities and wanted to weaken him in other ways to compensate. So if you could send me or just post/attach the python (it's in the cyspellinterface right?) from before then I could just replace it in my game. Thanks!
 
I am playing as Arturus Thorne(Khazad). I have researched necessary techs to enter peaks(Ways of the wise, Earth Mother), and I have Arete selected. Yet I am unable to take any of my workers to peaks because they don't have mountaineer promotion. And I can't even promote them even thou they have 4/2 XP. Am I missing something?

EDIT: So I think there is a bug definatly "in the works". I build another "batch" of workers, ten to be exact, and only one worker(lucky #9) had the "ability" to promoto to mountaineering. All the previous 8 workers cannot protomo mountaineering, only "extra move" and tinkering are available. Worker #10 wasen't able promoto mountaineering either.
 
Last edited:
I'm thinking of scaling the amount of mana required for free spell spheres.

Thematically it would make the most sense to scale it based on the total number of casters in the world, but I think that code would be too messy and inefficient. I'm thinking of basing it instead on map size, your team percent of the total world population, and/or the percentage of the map that you control.

What you do think of those ideas?


I am playing as Arturus Thorne(Khazad). I have researched necessary techs to enter peaks(Ways of the wise, Earth Mother), and I have Arete selected. Yet I am unable to take any of my workers to peaks because they don't have mountaineer promotion. And I can't even promote them even thou they have 4/2 XP. Am I missing something?

EDIT: So I think there is a bug definatly "in the works". I build another "batch" of workers, ten to be exact, and only one worker(lucky #9) had the "ability" to promoto to mountaineering. All the previous 8 workers cannot protomo mountaineering, only "extra move" and tinkering are available. Worker #10 wasen't able promoto mountaineering either.
The Arete promotion requires that the unit itself have the Runes of Kilmorph religion, in addition to the player having the Runes of Kilmorph State Religion.
 
The Arete promotion requires that the unit itself have the Runes of Kilmorph religion, in addition to the player having the Runes of Kilmorph State Religion.
Yes but how do you explain the fact that I had build 8 workers(same city, in a row), that could not promote to mountaineering, but suddenly #9 could and then again #10 couldn't? And when I checked the units they all had the same promotions, there was nothing different about worker #9 that I could see. Also when I but my units to sleep/defend/skipturn the game freezes for several seconds, depends of how many units are on the plot, so far I've had freezes that have lasted up to 30sec. Also it doesn't matter if you are putting only one unit in the stack to sleep it still takes the same amount of time. I also think that what ever this "freeze" is, is contributing to 'end turn' times significantly. My 'end turn' times are now around 3-6 minutes, but then can drop to few seconds suddenly for few turns. And then there is the fact that the game still moves the screen to a unit that has already used its moves for that turn. These 'end turn' times seem ridiculously long since there aren't really that many units on the map, the map is only 'huge' size and even the savefile is only roughly 2mb big. I mean I've played games in Magister and on other mods where the map is WAY bigger(mods that allow bigger than huge), has heck a lot of units and the savefile size is somewhere around 10mb. Maybe you and Tholal should see if you can do some optimization.
STILL love this mod and I hope you keep working on it =)
 
Hey Magister, wanted to say that I love your Magistermodmod for ffh2. Thanks for creating it. I was wondering if you wouldn't mind sending me the code/Python for the assume true form and shapeshift abilities prior to the October update. It had recently been changed so that those spells would wipe abilities granted by form that gibbon had changed into. So that he wouldn't have channeling 1,2,3 as an ogre. While that does end up granting him tons of promotions, I like that aspect of his abilities and wanted to weaken him in other ways to compensate. So if you could send me or just post/attach the python (it's in the cyspellinterface right?) from before then I could just replace it in my game. Thanks!

Yes, the code is in CvSpellInterface.py


It took me a while to find because I had deleted the old versions from my laptop and was not sure which external harddrive I had used to back it up, but here it is.


Spoiler :
Code:
def reqShapeShift(pCaster, eSpell=-1):
    iTeam = pCaster.getTeam()
    lAnimal = [gc.getInfoTypeForString('UNITCOMBAT_ANIMAL'), gc.getInfoTypeForString('UNITCOMBAT_BEAST')]
    iCaster = pCaster.getUnitType()
    iX = pCaster.getX()
    iY = pCaster.getY()
    for iiX in xrange(iX-1, iX+2, 1):
        for iiY in xrange(iY-1, iY+2, 1):
            pPlot = CyMap().plot(iiX, iiY)
            if pPlot.isNone():continue
            for i in xrange(pPlot.getNumUnits()):
                pUnit = pPlot.getUnit(i)
                if pUnit.getTeam() == iTeam:
                    continue
                if pUnit.isOnlyDefensive():
                    continue
                if not pUnit.isAlive():
                    continue
                if pUnit.isImmuneToMagic():
                    continue
                if pUnit.isAvatarOfCivLeader():
                    continue
                if pUnit.getUnitCombatType() in lAnimal:
                    continue
                iUnit = pUnit.getUnitType()
                info = gc.getUnitInfo(iUnit)
                if info.isAbandon():#It would be wasteful to change into a unit that would prompty abandon you
                    continue
                if info.isObject():#Should not duplicate equipment
                    continue
                if iUnit == iCaster:#No use shape shifting if it will have no real effect
                    for iProm in xrange(gc.getNumPromotionInfos()):
                        if pUnit.isHasPromotion(iProm) and not pCaster.isHasPromotion(iProm):
                            infoP = gc.getPromotionInfo(iProm)
                            if infoP.isGraphicalOnly():
                                continue
                            if infoP.isEquipment():
                                continue
##                            if infoP.isRace():
##                                continue
                            if infoP.getAIWeight() > -1:
                                return True
##                    else:
##                        continue
                elif pCaster.isHuman():
                    return True
                elif pCaster.baseCombatStr() < pUnit.baseCombatStr():
                    return True
                elif pCaster.baseCombatStrDefense() < pUnit.baseCombatStrDefense():
                    return True

    return False

def spellShapeShift(pCaster, eSpell=-1):
    lPermanent = [    gc.getInfoTypeForString('PROMOTION_CHANGELING'),
            gc.getInfoTypeForString('PROMOTION_MIMIC'),
            gc.getInfoTypeForString('PROMOTION_HERO'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_DEFENSE'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_DEFENSE2'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_STRENGTH'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_STRENGTH2')
            ]
    pPlot = pCaster.plot()
    sName = pCaster.getNameNoDesc()
    if len(sName) == 0:
        sName = pCaster.getName()
    lAnimal = [gc.getInfoTypeForString('UNITCOMBAT_ANIMAL'), gc.getInfoTypeForString('UNITCOMBAT_BEAST')]
    iX = pCaster.getX()
    iY = pCaster.getY()
    pPlayer = gc.getPlayer(pCaster.getOwner())
    iCaster = pCaster.getUnitType()
    iResistMax = 95
    iBestValue = -1000000000000
    pBestUnit = -1
    if not pPlayer.isHuman():
        iResistMax = 20
    iTeam = pPlayer.getTeam()
    eTeam = gc.getTeam(iTeam)
    for iiX in xrange(iX-1, iX+2, 1):
        for iiY in xrange(iY-1, iY+2, 1):
            pPlot = CyMap().plot(iiX, iiY)
            if pPlot.isNone():continue
            for i in xrange(pPlot.getNumUnits()):
                pUnit = pPlot.getUnit(i)
                iValue = 0
                if pUnit.getTeam() == iTeam:
                    continue
                if pUnit.isOnlyDefensive():
                    continue
                if not pUnit.isAlive():
                    continue
                if pUnit.isImmuneToMagic():
                    continue
                if pUnit.isAvatarOfCivLeader():
                    continue
                if pUnit.getUnitCombatType() in lAnimal:
                    continue
                iUnit = pUnit.getUnitType()
                info = gc.getUnitInfo(iUnit)
                if info.isAbandon():#It would be wasteful to change into a unit that would prompty abandon you
                    continue
                if info.isObject():#Should not duplicate equipment
                    continue
                if iUnit != iCaster:#No use shape shifting if it will have no real effect
                    iValue += pUnit.baseCombatStr() * 10
                    iValue += pUnit.baseCombatStrDefense() * 10
                    iValue += pUnit.getMoves() * 10
                    iValue += pUnit.getLevel() * 10#Presumably, higher levels units would tend to have better promotions
                    iValue += info.getAIWeight()

                for iProm in xrange(gc.getNumPromotionInfos()):
                    if pCaster.isHasPromotion(iProm):continue
                    if pUnit.isHasPromotion(iProm):
                        infoP = gc.getPromotionInfo(iProm)
                        if infoP.isGraphicalOnly():
                            continue
                        if infoP.isEquipment():
                            continue
##                        if infoP.isRace():
##                            continue
                        iValue += infoP.getAIWeight()

                if iValue > iBestValue:
                    iBestValue = iValue
                    pBestUnit = pUnit

    if pBestUnit != -1:
        iUnit = pCaster.getScenarioCounter()
        if not -1 < iUnit < gc.getNumUnitInfos():
            iUnit = pCaster.getUnitType()
            pCaster.setScenarioCounter(iUnit)
        iReligion = pCaster.getReligion()
        newUnit = pPlayer.initUnit(pBestUnit.getUnitType(), iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.NO_DIRECTION)
        for iProm in xrange(gc.getNumPromotionInfos()):
            if gc.getPromotionInfo(iProm).isEquipment():
                newUnit.setHasPromotion(iProm, False)
            elif pBestUnit.isHasPromotion(iProm):
                newUnit.setHasPromotion(iProm, True)
        cf.makeMortal(newUnit)
        #I'm not sure why I have to make both of these units illusions in order to prevent Sluagh creation, but I do
        pCaster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_REFLECTION'), True)
        newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_REFLECTION'), True)
        newUnit.setScenarioCounter(iUnit)

        info = gc.getUnitInfo(pCaster.getUnitType())
        info2 = gc.getUnitInfo(pBestUnit.getUnitType())
        for iProm in xrange(gc.getNumPromotionInfos()):
            if pCaster.isHasPromotion(iProm):
                if iProm in lPermanent:continue
                if info.getFreePromotions(iProm) and not info2.getFreePromotions(iProm):
                    pCaster.setHasPromotion(iProm,False)

        newUnit.convert(pCaster)
        newUnit.setReligion(iReligion)
        newUnit.setName(sName)
        iArt = pBestUnit.getUnitArtStyleType()
        if iArt != -1:
            newUnit.setUnitArtStyleType(iArt)
        CyInterface().addMessage(pCaster.getOwner(), True, 25, CyTranslator().getText("TXT_KEY_MESSAGE_SHAPE_SHIFT", (pCaster.getNameNoDesc(),)), 'AS2D_FEATUREGROWTH', 1, 'Art/Interface/Buttons/Units/Gibbon.dds', ColorTypes(8), iX, iY, True, True)

        newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_REFLECTION'), False)
##        gc.getGame().decrementUnitClassCreatedCount(newUnit.getUnitClassType())
##        gc.getGame().decrementUnitCreatedCount(iUnit)

def helpShapeShift(lpUnits, eSpell=-1):
    lPermanent = [    gc.getInfoTypeForString('PROMOTION_CHANGELING'),
            gc.getInfoTypeForString('PROMOTION_MIMIC'),
            gc.getInfoTypeForString('PROMOTION_HERO'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_DEFENSE'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_DEFENSE2'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_STRENGTH'),
            gc.getInfoTypeForString('PROMOTION_HEROIC_STRENGTH2')
            ]
    iHN = gc.getInfoTypeForString('PROMOTION_HIDDEN_NATIONALITY')
    szBuffer = ''
    pCaster = lpUnits[0]
    pPlot = pCaster.plot()
    lAnimal = [gc.getInfoTypeForString('UNITCOMBAT_ANIMAL'), gc.getInfoTypeForString('UNITCOMBAT_BEAST')]
    iX = pCaster.getX()
    iY = pCaster.getY()
    pPlayer = gc.getPlayer(pCaster.getOwner())
    iTeam = pPlayer.getTeam()
    eTeam = gc.getTeam(iTeam)
    iResistMax = 95
    if not pPlayer.isHuman():
        iResistMax = 20
    for pCaster in lpUnits:
        if pCaster.canCast(eSpell, True):
            iBestValue = -1000000000000
            pBestUnit = -1
            iCaster = pCaster.getUnitType()
            sName = pCaster.getNameNoDesc()
            if len(sName) == 0:
                sName = pCaster.getName()
            for iiX in xrange(iX-1, iX+2, 1):
                for iiY in xrange(iY-1, iY+2, 1):
                    pPlot = CyMap().plot(iiX, iiY)
                    if pPlot.isNone():continue
                    for i in xrange(pPlot.getNumUnits()):
                        pUnit = pPlot.getUnit(i)
                        iValue = 0
                        if not pUnit.isAlive():
                            continue
                        if pUnit.getTeam() == iTeam:
                            continue
                        if pUnit.isOnlyDefensive():
                            continue
                        if pUnit.isImmuneToMagic():
                            continue
                        if pUnit.isAvatarOfCivLeader():
                            continue
                        if pUnit.getUnitCombatType() in lAnimal:
                            continue
                        iUnit = pUnit.getUnitType()
                        info = gc.getUnitInfo(iUnit)
                        if info.isAbandon():#It would be wasteful to change into a unit that would prompty abandon you
                            continue
                        if info.isObject():#Should not duplicate equipment
                            continue
                        if iUnit != iCaster:#No use shape shifting if it will have no real effect
                            iValue += pUnit.baseCombatStr() * 10
                            iValue += pUnit.baseCombatStrDefense() * 10
                            iValue += pUnit.getMoves() * 10
                            iValue += pUnit.getLevel() * 10#Presumably, higher levels units would tend to have better promotions
                            iValue += info.getAIWeight()

                        for iProm in xrange(gc.getNumPromotionInfos()):
                            if pCaster.isHasPromotion(iProm):continue
                            if pUnit.isHasPromotion(iProm):
                                infoP = gc.getPromotionInfo(iProm)
                                if infoP.isGraphicalOnly():
                                    continue
                                if infoP.isEquipment():
                                    continue
##                                if infoP.isRace():
##                                    continue
                                iValue += infoP.getAIWeight()
                        if iValue > iBestValue:
                            iBestValue = iValue
                            pBestUnit = pUnit

            if pBestUnit != -1:
                szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_CHANGE_A_TO_B", (sName, pBestUnit.getName(), ))

                info = gc.getUnitInfo(pBestUnit.getUnitType())
                info2 = gc.getUnitInfo(pCaster.getUnitType())

                lAddPromotions = []
                lRemovePromotions = []
                for iProm in xrange(gc.getNumPromotionInfos()):
                    if iProm in lPermanent:continue
                    if pCaster.isHasPromotion(iProm):
                        if info2.getFreePromotions(iProm):
                            lRemovePromotions.append(iProm)
                    elif pBestUnit.isHasPromotion(iProm):
                        infoP = gc.getPromotionInfo(iProm)
                        if not (infoP.isGraphicalOnly() or infoP.isEquipment() or infoP.isRace() or infoP.getAIWeight() < 0):
                            lAddPromotions.append(iProm)
                if not pCaster.isHasPromotion(iHN):
                    lAddPromotions.append(iHN)
                lAddPromotions = list(set(lAddPromotions))
                lRemovePromotions = list(set(lRemovePromotions))
                for iProm in lAddPromotions:
                    if iProm in lRemovePromotions:
                        lAddPromotions.remove(iProm)
                        lRemovePromotions.remove(iProm)

                iCount = len(lAddPromotions)
                if iCount > 0:
                    sList = ''
                    while len(lAddPromotions) > 0:
                        iProm = lAddPromotions.pop(0)
                        infoProm = gc.getPromotionInfo(iProm)
                        sList += infoProm.getDescription()
                        if len(lAddPromotions) > 0:
                            if len(lAddPromotions) == 1:
                                sList += " and "
                            else:
                                sList += ", "
                    szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_ADDS", ( )) + sList

                iCount = len(lRemovePromotions)
                if iCount > 0:
                    sList = ''
                    while len(lRemovePromotions) > 0:
                        iProm = lRemovePromotions.pop(0)
                        infoProm = gc.getPromotionInfo(iProm)
                        sList += infoProm.getDescription()
                        if len(lRemovePromotions) > 0:
                            if len(lRemovePromotions) == 1:
                                sList += " and "
                            else:
                                sList += ", "
                    szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_REMOVES", ( )) + sList

    return szBuffer


Code:
def reqAssumeTrueForm(pCaster, eSpell=-1):
    iUnit = pCaster.getScenarioCounter()
    if not -1 < iUnit < gc.getNumUnitInfos():
        return False
    if iUnit == pCaster.getUnitType():
        return False
    return True

def helpAssumeTrueForm(lpUnits, eSpell=-1):
    szBuffer = ''
    for pCaster in lpUnits:
        if pCaster.canCast(eSpell, True):
            iUnit = pCaster.getScenarioCounter()
            if -1 < iUnit < gc.getNumUnitInfos():
                szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_CHANGE_A_TO_B", (pCaster.getName(), gc.getUnitInfo(iUnit).getDescription(), ))

                lAddPromotions = []
                lRemovePromotions = []
                info = gc.getUnitInfo(pCaster.getUnitType())
                info2 = gc.getUnitInfo(iUnit)
                for iProm in xrange(gc.getNumPromotionInfos()):
                    if pCaster.isHasPromotion(iProm):
                        if info.getFreePromotions(iProm) and not info2.getFreePromotions(iProm):
                            lRemovePromotions.append(iProm)
                        infoProm = gc.getPromotionInfo(iProm)
                        if infoProm .getAIWeight() < 0:
                            lRemovePromotions.append(iProm)
                        if infoProm.isRace():
                            lRemovePromotions.append(iProm)
                    elif info2.getFreePromotions(iProm):
                        lAddPromotions.append(iProm)
                lAddPromotions = list(set(lAddPromotions))
                iCount = len(lAddPromotions)
                if iCount > 0:
                    sList = ''
                    while len(lAddPromotions) > 0:
                        iProm = lAddPromotions.pop(0)
                        infoProm = gc.getPromotionInfo(iProm)
                        sList += infoProm.getDescription()
                        if len(lAddPromotions) > 0:
                            if len(lAddPromotions) == 1:
                                sList += " and "
                            else:
                                sList += ", "
                    szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_ADDS", ( )) + sList

                lRemovePromotions = list(set(lRemovePromotions))
                iCount = len(lRemovePromotions)
                if iCount > 0:
                    sList = ''
                    while len(lRemovePromotions) > 0:
                        iProm = lRemovePromotions.pop(0)
                        infoProm = gc.getPromotionInfo(iProm)
                        sList += infoProm.getDescription()
                        if len(lRemovePromotions) > 0:
                            if len(lRemovePromotions) == 1:
                                sList += " and "
                            else:
                                sList += ", "
                    szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_REMOVES", ( )) + sList



    return szBuffer

def spellAssumeTrueForm(pCaster, eSpell=-1):
    iUnit = pCaster.getScenarioCounter()
    newUnit = gc.getPlayer(pCaster.getOwner()).initUnit(iUnit, pCaster.getX(), pCaster.getY(), UnitAITypes.UNITAI_ATTACK, DirectionTypes.NO_DIRECTION)
    pCaster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_REFLECTION'), True)

    info = gc.getUnitInfo(pCaster.getUnitType())
    info2 = gc.getUnitInfo(iUnit)

    cf.makeMortal(pCaster)
    cf.makeMortal(newUnit)
    bKill = False
    if pCaster.isDelayedDeath():
        bKill = True
    newUnit.convert(pCaster)
##    newUnit.setMadeAttack(True)
##    newUnit.setHasCasted(True)
##    gc.getGame().decrementUnitClassCreatedCount(newUnit.getUnitClassType())
##    gc.getGame().decrementUnitCreatedCount(iUnit)

    for iProm in xrange(gc.getNumPromotionInfos()):
        if pCaster.isHasPromotion(iProm):
            if info.getFreePromotions(iProm) and not info2.getFreePromotions(iProm):
                newUnit.setHasPromotion(iProm,False)
            infoProm = gc.getPromotionInfo(iProm)
            if infoProm.getAIWeight() < 0:
                newUnit.setHasPromotion(iProm,False)
            if infoProm.isRace():
                newUnit.setHasPromotion(iProm,False)
    newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_REFLECTION'), False)
    if bKill:
        newUnit.kill(True, -1)
    return newUnit



Are Homesteads any use outside of the Grigori's capital city?
The main benefit of Homesteads is that when hostile units enter them they can generate defenders. They function much like Ancient Forests but for the Grigori instead of FoL players. The units are Weak, limited duration versions of whatever would be conscripted in the nearest city. It is more likely near the capital, a Grigori Tavern, or an Adventurers Guild. (The benefit from those buildings do stack.)

The improvement is otherwise just a Farm that can also grant access to bonuses usually connected by Pastures.
 
The main benefit of Homesteads is that when hostile units enter them they can generate defenders. They function much like Ancient Forests but for the Grigori instead of FoL players. The units are Weak, limited duration versions of whatever would be conscripted in the nearest city. It is more likely near the capital, a Grigori Tavern, or an Adventurers Guild. (The benefit from those buildings do stack.)

That's a very cool and very fitting feature, but it sure would be nice if the game would tell you about it.
 
Back
Top Bottom