[Module + Modular Python] Improved Terraforming

westamastaflash

Lord Commander
Joined
Nov 1, 2007
Messages
933
Modular Terraforming

View attachment TerraformingSpells.zip v 1.1
Changes for 1.1:
- Fixed python loading
- Fixed lizardmen scorch
- Cleaned up to use less functions per odalrick's suggestion


I built this module based on odalrick's Vitalize 2.1 code with some modifications of my own.

It is entirely modular, using odalrick's modular python mod (i used v4 but it should be forward compatible, in theory).

Install odalrick's modular python, then drop the TerraformingSpells folder into your Modules/NormalModules subdirectory and away you go!

How it works:
Vitalize and Scorch now get two additional spells to work at increased ranges, requiring Spell Extension I for the surrounding tiles, and Spell Extension II for a fat cross. The additional spells take longer to cast as well.

The Lizard races upgrade to marshes as the vitalize endpoint.
The Doviello cannot scorch Tundra. The Illians cannot scorch Snow.
 
Does this really work? I'd have thought you'd run into the same problem as your fortress code with gc.getInfoTypeForString called before the xml is read.

I changed my version to avoid that (codefragment):
Spoiler :
Code:
[B]baseVitalizeUpgrades = None
civSpecificVitalize = None[/B]
def initVitalizeCache():
    '''
    Initialize the vitalize cache.
    Need to ensure that this function isn't called until the xml is loaded.
    '''
    global baseVitalizeUpgrades
    global civSpecificVitalize
    baseVitalizeUpgrades = dict( ( gc.getInfoTypeForString( start_terrain ), gc.getInfoTypeForString( end_terrain ) )
                                for start_terrain, end_terrain in [
                                    ('TERRAIN_SNOW', 'TERRAIN_TUNDRA'),
                                    ('TERRAIN_TUNDRA', 'TERRAIN_PLAINS'),
                                    ('TERRAIN_DESERT', 'TERRAIN_PLAINS'),
                                    ('TERRAIN_PLAINS', 'TERRAIN_GRASS'),
                                    ('TERRAIN_MARSH', 'TERRAIN_GRASS'),
                                    ('TERRAIN_OCEAN', 'TERRAIN_COAST'),
                                    ] )
    civSpecificVitalize = dict()
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_ILLIANS')] = dict( ( gc.getInfoTypeForString( start_terrain ), gc.getInfoTypeForString( end_terrain ) )
                                for start_terrain, end_terrain in [
                                    ('TERRAIN_TUNDRA', 'TERRAIN_SNOW'),
                                    ('TERRAIN_DESERT', 'TERRAIN_SNOW'),
                                    ('TERRAIN_PLAINS', 'TERRAIN_SNOW'),
                                    ('TERRAIN_GRASS', 'TERRAIN_SNOW'),
                                    ('TERRAIN_MARSH', 'TERRAIN_SNOW'),
                                    ('TERRAIN_BURNING_SANDS', 'TERRAIN_SNOW'),
                                    ('TERRAIN_BROKEN_LANDS', 'TERRAIN_SNOW'),
                                    ('TERRAIN_FIELDS_OF_PERDITION', 'TERRAIN_SNOW'),
                                    ('TERRAIN_OCEAN', 'TERRAIN_COAST'),
                                    ] )
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_MAZATL')] = dict( baseVitalizeUpgrades )
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_MAZATL')].update( dict( ( gc.getInfoTypeForString( start_terrain ), gc.getInfoTypeForString( end_terrain ) )
                                for start_terrain, end_terrain in [
                                    ('TERRAIN_GRASS', 'TERRAIN_MARSH'),
                                    ('TERRAIN_MARSH', 'TERRAIN_MARSH'),
                                    ] ) )
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_CUALLI')] = dict (civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_MAZATL')])
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_MALAKIM')] = dict( baseVitalizeUpgrades )
    civSpecificVitalize[gc.getInfoTypeForString('CIVILIZATION_MALAKIM')].update( dict( ( gc.getInfoTypeForString( start_terrain ), gc.getInfoTypeForString( end_terrain ) )
                                for start_terrain, end_terrain in [
                                    ('TERRAIN_DESERT', 'TERRAIN_DESERT'),
                                    ] ) )
[I]    # Delete upgrades to the same terrain, id est marsh to marsh
    for key in baseVitalizeUpgrades.keys():
        if key == baseVitalizeUpgrades[key]:
            del baseVitalizeUpgrades[key]
    for civUpgrades in civSpecificVitalize.values():
        for key in civUpgrades.keys():
            if key == civUpgrades[key]:
                del civUpgrades[key][/I]

@spell
def reqVitalize(caster):
    pPlot = caster.plot()
    if pPlot.getOwner() != caster.getOwner():
        return False
    if pPlot.isWater():
        return False
    pPlayer = gc.getPlayer( caster.getOwner() )
[B]    if baseVitalizeUpgrades is None:
        initVitalizeCache()[/B]
    vitalizeUpgrades = civSpecificVitalize.get( pPlayer.getCivilizationType(), baseVitalizeUpgrades )
    if not pPlot.getTerrainType() in vitalizeUpgrades:
        return False
    return True

@spell
def spellVitalize(caster):
    map = CvPythonExtensions.CyMap()
[B]    if baseVitalizeUpgrades is None:
        initVitalizeCache()[/B]
    grass = gc.getInfoTypeForString( 'TERRAIN_GRASS' )
    plains = gc.getInfoTypeForString( 'TERRAIN_PLAINS' )
    desert = gc.getInfoTypeForString( 'TERRAIN_DESERT' )
    floodPlains = gc.getInfoTypeForString('FEATURE_FLOOD_PLAINS')
    pPlayer = gc.getPlayer( caster.getOwner() )
    vitalizeUpgrades = civSpecificVitalize.get( pPlayer.getCivilizationType(), baseVitalizeUpgrades )
    for x,y in plotsInRange( caster.getX(), caster.getY(), getSpellRange( caster )+1 ):
        pPlot = map.plot(x,y)
        if not pPlot.isNone() and pPlot.getOwner() == caster.getOwner():
            terrain = pPlot.getTerrainType()
            if terrain in vitalizeUpgrades:
                pPlot.setTerrainType( vitalizeUpgrades[terrain], True, True )
            # From here on terrain refers to what pPlot was before the upgrade
            if terrain == desert and pPlot.getFeatureType() == floodPlains and terrain != pPlot.getTerrainType():
                pPlot.setFeatureType(-1, -1)
            if pPlot.getTerrainType() == grass and pPlot.isHills() and pPlot.isCity():
                pPlot.setTerrainType( plains, True, True )

The bold parts and of course the entire initVitalizeCache relate to caching the upgrade dicts.

The italic parts in initVitalizeCache remove "upgrades" to the same terrain type, which most importantly disallows casting the spell when all it does is "upgrade" tiles to the same terrain.


Finally, I noticed that you have a few functions like this:
Code:
@spell
def spellVitalize3(caster):
	doSpellVitalize(caster, 2)

You could instead just put doSpellVitalize(caster, 2) in the xml. It works for most but not all python tags.

Edit: It must of course be doSpellVitalize(pCaster, 2).
 
You're right, I didn't test for that. Will re-upload with it fixed. I also had tried using doSpellVitalize(caster, 2) but it was being weird (might have been the first bug).
 
You're right, I didn't test for that. Will re-upload with it fixed. I also had tried using doSpellVitalize(caster, 2) but it was being weird (might have been the first bug).

Well, the version I posted wouldn't have worked either. It must be pCaster, refering to a local variable in CvSpellInterface.cast.
 
Top Bottom