1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Sample Python Code

Discussion in 'Civ4 - Modding Tutorials & Reference' started by Kael, Jan 8, 2006.

  1. Olleus

    Olleus Deity

    Joined:
    Oct 30, 2005
    Messages:
    6,478
    Location:
    England
    Incase anybody here wanted to know the game uses 1.5 as the square root of 2. And when using the getPathDistance function (which finds the passable distance between 2 plots) it does use pythagoras. Just a very inacurate value.
     
  2. The Butler

    The Butler Chieftain

    Joined:
    Oct 29, 2005
    Messages:
    18
    Hey I was wondering if anyone can help me im trying to get the hang on python and understand the concept but it hasn't twigged yet what I can and can't do and how to go about it so I was wondering if someone more knowledgeabla can help me out

    Upon reading forums and experimenting I've implemented a terraform mod into the mod i'm making that allows a workboat to turn a sea tile into a land tile

    Code:
    elif(iImprovement==lowerelev):
    			if(pPlot.getPlotType()==PlotTypes.PLOT_LAND):
    				numberofunits = pPlot.getNumUnits()
    				while(numberofunits > 0):
    					pPlot.getUnit(0).jumpToNearestValidPlot()
    					numberofunits = pPlot.getNumUnits()
    				pPlot.setPlotType(PlotTypes.PLOT_OCEAN, true, true)
    			else:
    				pPlot.setPlotType(PlotTypes.PLOT_LAND, true, true)
    				if(pPlot.getTerrainType()==gc.getInfoTypeForString("TERRAIN_DESERT") and pPlot.isRiver()):
                                            pPlot.setFeatureType(gc.getInfoTypeForString("FEATURE_FLOOD_PLAINS"), 0)
    			pPlot.setImprovementType(-1)
    (stolen from tywiggins terraform mod)

    upon completion of the terraform i'd like either a settler unit or a city to be built on the tile too.

    From reading I discovered that something like this
    Code:
    def onCityBuilt(self, argsList):
    	'For player 1, create a Warrior (index 17) in every city that is built'
    	city = argsList[0]
    	if city.getOwner() == 1:
    		city.getOwner().initUnit(17, city.getX(), city.getY(), UnitAITypes.NO_UNITAI)
    is responsible for creating a warrior in a city when it was built so what I want to know is how/is it possible to adapt this code and implement it into the above terraform code so that when a tile is improved a unit is created?

    Even better would be if when a tile is improved, in this case that means terraformed from an ocean to grass tile, a city is built. However I don't know where to start with city building.

    Thanks for your time reading and any help would be wonderful
     
  3. Kael

    Kael Deity

    Joined:
    May 6, 2002
    Messages:
    17,401
    Location:
    Ohio
    This thread is just for posting working code, please post questions in the creation and customization forum and Im sure people would be glad to help.
     
  4. Kael

    Kael Deity

    Joined:
    May 6, 2002
    Messages:
    17,401
    Location:
    Ohio
    In celebration of C.Rolands awesome "fire elemental" I give you the code I am using with it in Phase 2 (I call it a Pyre Zombie).

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


    Code:
    					
    		if pLoser.getUnitType() == gc.getInfoTypeForString('UNIT_PYRE_ZOMBIE'):
    			pPlot = pWinner.plot()
    			point = pPlot.getPoint()
    			for i in range(pPlot.getNumUnits()):
    				pUnit = pPlot.getUnit(i)
    				iRnd = CyGame().getSorenRandNum(30, "Bob") - 10
    				if pUnit.isHasPromotion('PROMOTION_MAGIC_RESISTANCE'):
    					iRnd = iRnd - 10
    				if pUnit.isHasPromotion('PROMOTION_FIRE_RESISTANCE'):
    					iRnd = iRnd - 10
    				if pUnit.isHasPromotion('PROMOTION_VULNERABLE_TO_FIRE'):
    					iRnd = iRnd + 10
    				if iRnd >= 1:
    					pUnit.setDamage(pUnit.getDamage() + iRnd, True)
    			CyEngine().triggerEffect(cf.FFHgetEffectInfo('EFFECT_ARTILLERY_SHELL_EXPLODE'),point)
    			CyAudioGame().Play3DSound("AS3D_UN_GRENADE_EXPLODE",point.x,point.y,point.z)
    What it does:

    When the Pyre Zombie is killed he explodes on the stack the winning unit is in. There is a explosion effect and sound that goes along with it. Damage is applied randomly and about 2/3 of the stack will take 0-20% damage from the explosion. This damage is modified by some of the promotions the units have.

    Use:

    Its really pretty contained code. This function is run out of onCombatResult in the CvEventManager.py file. I like it because its a good short sample that does a lot of interesting stuff and it shows how you can write your own functions to add some detail to game functions (in this case collateral damage) that may not do exactly what you want. I didn't like collateral for this effect because I only wanted it applied when the zombie died and I wanted it adjusted based on some promotions.

    Enjoy!
     
  5. naf4ever

    naf4ever Dread Lord

    Joined:
    Feb 8, 2003
    Messages:
    405
    Location:
    Southeast Washington State
    Wow that code rocks Kael.... BTW ive used the .getSorenRandNum() function before. What is really suppose to go in the place where you typed "bob"? And does it affect anything besides your own enjoyment?
     
  6. Olleus

    Olleus Deity

    Joined:
    Oct 30, 2005
    Messages:
    6,478
    Location:
    England
    'bob' is the name of the random number generated and is only used by the debug files. How exactly do you create new missions in python? I've heard of mods where a unit could be used to create another unit but how do you do this *cough* Kael-I-know-you-did-this *cough*
     
  7. Kael

    Kael Deity

    Joined:
    May 6, 2002
    Messages:
    17,401
    Location:
    Ohio
    And I think its always "Bob" in my code because The Great Apple listed a sample way way back and he called it "Bob" so now everyone has Bob in their code for no real reason. :)

    Making units is pretty easy, the hard part is what python event do you intercept to do it. I have some in onCombatresult (thats where defeated units are made into slaves, werewolves are created and defeated animals are captured).

    But for more user initiated summons I intercept in the promotion function. every turn I reset my spellcasters xp and level so they are set to level. Then they get to pick their "promotion". I intercept the promotion function, see which one they picked and perform some action based on which promotion/spell they picked. Then I strip the promotion away and start over next turn.

    The nice thing about the promotion method is the AI understands it. By changing the supposed effect of the promotion (for those of you wondering why the summon demon promotion gives +150% strength when it only lasts for millisecond) you can give the AI a clue as to which one it whould pick. So for example if it can fireball or summon a demon it will summon the demon.

    Here is the code:

    Code:
    
    		if iPromotion == gc.getInfoTypeForString('PROMOTION_SUMMON_DEMON'):
    			newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_DEMON'), pUnit.getX(), pUnit.getY(), UnitAITypes.NO_UNITAI)
    			pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_SUMMON_DEMON'), False)
    			cf.FFHApplySpellMods(newUnit, pUnit)
     
  8. Chinese American

    Chinese American Hamtastic Knight

    Joined:
    Aug 23, 2001
    Messages:
    432
    Location:
    Chinatown, USA
    For some reason the game doesn't have functions to return the number of turns left before a city advances to the next Culture or Great People level. But it's very easy to find that value and show it on your city's culture or GP bar. see attachments to see new culture and GP bars that show turns to completion.

    First open CvMainInterface.py (backup if necessary) and look for these strings:
    screen.setLabel( "CultureText",
    screen.setLabel( "GreatPeopleText",

    These are the labels you see on the city screen that say something like [Culture_Icon]: Poor ( +2/Turn ). We're gonna append the turns left.

    So we find the value for turns left for culture. Thus:
    PHP:
    ## FU edit start -- append Turns to Complete
                        
    iCulRate =  pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)
                        if ( 
    iCulRate ):
                            
    iCulNext pHeadSelectedCity.getCultureThreshold()
                            
    iCulNow pHeadSelectedCity.getCulture(pHeadSelectedCity.getOwner())
                            
    iCulTurns = (iCulNext-iCulNow+iCulRate-1)/iCulRate
                            szTurnsToComplete 
    " %d Turns" %(iCulTurns)
                            
    szBuffer szBuffer szTurnsToComplete
                            szTurnsToComplete 
    ""
    ## FU edit end
                        
    screen.setLabel"CultureText""Background"szBufferCvUtil.FONT_CENTER_JUSTIFY125yResolution 184, -1.3FontTypes.GAME_FONTWidgetTypes.WIDGET_GENERAL, -1, -)
    szBuffer holds the string that shows up on screen. We put together szBuffer + szTurnsToComplete.

    We do the same for Great People.

    PHP:
    ## FU edit start -- append turns to completion
                        
    iGPRate pHeadSelectedCity.getGreatPeopleRate()
                        if ( 
    iGPRate ):
                            
    iGPNext gc.getPlayerpHeadSelectedCity.getOwner() ).greatPeopleThreshold()
                            
    iGPNow pHeadSelectedCity.getGreatPeopleProgress()
                            
    iGPTurns = (iGPNext-iGPNow+iGPRate-1)/iGPRate
                            szTurnsToComplete 
    " %d Turns" %(iGPTurns)
                            
    szBuffer szBuffer szTurnsToComplete
                            szTurnsToComplete 
    ""
    ## FU edit end
                        
    screen.setLabel"GreatPeopleText""Background"szBufferCvUtil.FONT_CENTER_JUSTIFYxResolution 146yResolution 176, -1.3FontTypes.GAME_FONTWidgetTypes.WIDGET_GENERAL, -1, -)
    iCulTurns and iGPTurns have those equations so that we don't have to import math and use ceil function. With math.ceil, it would be iGPTurns = math.ceil(float(iGPNext-iGPNow)/iGPRate)
     

    Attached Files:

  9. Olleus

    Olleus Deity

    Joined:
    Oct 30, 2005
    Messages:
    6,478
    Location:
    England
    Someone should sticky this thread. I know I find it very usefull and its a nuissance to have to keep looking for it.
     
  10. Kael

    Kael Deity

    Joined:
    May 6, 2002
    Messages:
    17,401
    Location:
    Ohio
    Code:
    def startWar(iPlayer,i2Player):
    	iTeam = gc.getPlayer(iPlayer).getTeam()
    	i2Team = gc.getPlayer(i2Player).getTeam()
    	eTeam = gc.getTeam(iTeam)
    	if (eTeam.isAtWar(i2Team) == False and iTeam != i2Team):
    		eTeam.declareWar(i2Team, False)
    What it does:

    This is a very simple function, it literally just causes iPlayer to declare war on i2Player. Both of the players have to be passed to the function. The function checks to make sure they aren't already at war and that they aren't on the same team (which also keeps players from declaring war on themselves, a problem I had in early FfH versions).

    Use:

    It may seem werid to have such a simple function seperated out. But I found that as I made more and more functions that caused players to declare war on each other that it was very handy to have one function that did all the hard work. Also the fact that players don't declare war on player's teams declare war on teams was always confusing me and it seemed like I always made a mistake when I tried to rewrite these functions. Mostly because a "Team object" delcares war on a "Team int" instead of another team object.

    Note that the first player passed to the function declares war on the 2nd, which is significant when pacts and such are calculated.
     
  11. IVZanIV

    IVZanIV Warlord

    Joined:
    Jan 14, 2006
    Messages:
    285
    I second the sticky suggestion.
     
  12. 12monkeys

    12monkeys Prince

    Joined:
    Nov 24, 2003
    Messages:
    440
    Location:
    Germany, Europe
    I want to add my part to that thread with that function below. It is used in the next version of my Plot List Enhancements and calculates the heal factor of a unit. The heal factor is needed to calculate the number of turns a wounded units needs to get 100% healed.

    The function is called with only the unit to be examined as parameter.

    Here is the code:

    PHP:
    def getPlotHealFactor(pUnit):

        
    # heal rates for certain areas. They are usually stored in the GlobalDefines.XML but can't be read out with a standard API function.
        # So I placed them here as constants.
        
    ENEMY_HEAL_RATE                5
        NEUTRAL_HEAL_RATE            
    10
        FRIENDLY_HEAL_RATE            
    15
        CITY_HEAL_RATE                
    20

        
        
    # set/reset some variables
        
    pPlot pUnit.plot()
        
    iSameTileHealFactor         0
        iAdjacentTileHealFactor     
    0
        iBuildingHealFactor         
    0
        iSelfHealFactor             
    0
        iPromotionHealFactor         
    0
        iTileHealFactor             
    0
        iActivePlayer                 
    CyGame().getActivePlayer()
        
    pActivePlayer                 gc.getPlayer(iActivePlayer)
        
    iActivePlayerTeam             pActivePlayer.getTeam()
        
    eDomain                     gc.getUnitInfo(pUnit.getUnitType()).getDomainType()
        
        
    # a sea or air unit in a city, behaves like a land unit
        
    if pPlot.isCity():
            
    eDomain DomainTypes.DOMAIN_LAND

        
    # calculate the adjacent-tile heal-factor caused by other units (only the unit with the highest factor counts)
        
    for dx in range(-12):
            for 
    dy in range(-12):
                
    # ignore same tile. Adjacent-tile healing does not work on the same tile.
                
    if not (dx == and dy == 0):
                    
    pLoopPlot CyMap().plot(pPlot.getX()+dxpPlot.getY()+dy)
                    
    # loop through all units on the plot
                    
    for i in range(pLoopPlot.getNumUnits()):
                        
    pLoopUnit pLoopPlot.getUnit(i)
                        
    eLoopUnitDomain gc.getUnitInfo(pLoopUnit.getUnitType()).getDomainType()
                        
    # a sea or air unit in a city, behaves like a land unit
                        
    if ((eDomain == DomainTypes.DOMAIN_SEA) or (eDomain == DomainTypes.DOMAIN_AIR)) and pLoopPlot.isCity():
                            
    eLoopUnitDomain DomainTypes.DOMAIN_LAND
                        
    # adjacent-tile heal does only work if the units have the same domain type
                        
    if (eDomain == eLoopUnitDomain):
                            if (
    pLoopUnit.getTeam() == iActivePlayerTeam):
                                if (
    pLoopUnit.getAdjacentTileHeal() > iAdjacentTileHealFactor):
                                    
    iAdjacentTileHealFactor pLoopUnit.getAdjacentTileHeal()
        
        
    # calculate the same-tile heal-factor caused by other or same unit (only the unit with the highest factor counts)
        # the same-tile healing is also a kind of self-healing. Means : the promotion Medic I has also effect on the owner unit
        
    for i in range(pPlot.getNumUnits()):
            
    pLoopUnit pPlot.getUnit(i)
            
    eLoopUnitDomain gc.getUnitInfo(pLoopUnit.getUnitType()).getDomainType()
            
    # a sea or air unit in a city, behaves like a land unit
            
    if pLoopPlot.isCity():
                
    eLoopUnitDomain DomainTypes.DOMAIN_LAND
            
    # same tile heal does only work if the units are of the same domain type
            
    if (eDomain == eLoopUnitDomain):
                if (
    pLoopUnit.getTeam() == iActivePlayerTeam):
                    if (
    pLoopUnit.getSameTileHeal() > iSameTileHealFactor):
                        
    iSameTileHealFactor pLoopUnit.getSameTileHeal()
                    
        
    # only the highest value counts
        
    iTileHealFactor max(iAdjacentTileHealFactoriSameTileHealFactor)

        
    # calculate the self heal factor by the location and promotion
        
    iTeam pPlot.getTeam()
        
    pTeam gc.getTeam(iTeam)        
        
    iSelfHealFactor         NEUTRAL_HEAL_RATE
        iPromotionHealFactor     
    pUnit.getExtraNeutralHeal()
        if 
    pPlot.isCity():
            
    iSelfHealFactor         CITY_HEAL_RATE
            iPromotionHealFactor     
    pUnit.getExtraFriendlyHeal()
        
    elif (iTeam == iActivePlayerTeam):
            
    iSelfHealFactor         FRIENDLY_HEAL_RATE
            iPromotionHealFactor     
    pUnit.getExtraFriendlyHeal()
        
    elif (iTeam != TeamTypes.NO_TEAM):
            if (
    pTeam.isAtWar(iActivePlayerTeam)):
                
    iSelfHealFactor         ENEMY_HEAL_RATE
                iPromotionHealFactor     
    pUnit.getExtraEnemyHeal()
        
        
    # calculate the heal factor by city buildings
        
    if pPlot.isCity():
            if (
    pPlot.getTeam() == iActivePlayerTeam):
                
    pCity pPlot.getPlotCity()
                
    # loop for all buldings
                
    for iBuilding in range(gc.getNumBuildingClassInfos()):
                    
    # check if city has that building
                    
    if pCity.hasBuilding(iBuilding):
                        
    # sum up all heal rates 
                        
    iBuildingHealFactor += gc.getBuildingInfo(iBuilding).getHealRateChange()

        
    # return the sum of all heal factors
        
    return iTileHealFactor iBuildingHealFactor iSelfHealFactor iPromotionHealFactor    

    Lets step through the main parts :

    first few lines are used to set some variables and constants. Nothing special here:

    PHP:
        # heal rates for certain areas. They are usually stored in the GlobalDefines.XML but can't be read out with a standard API function.
        # So I placed them here as constants.
        
    ENEMY_HEAL_RATE                5
        NEUTRAL_HEAL_RATE            
    10
        FRIENDLY_HEAL_RATE            
    15
        CITY_HEAL_RATE                
    20

        
        
    # set/reset some variables
        
    pPlot pUnit.plot()
        
    iSameTileHealFactor         0
        iAdjacentTileHealFactor     
    0
        iBuildingHealFactor         
    0
        iSelfHealFactor             
    0
        iPromotionHealFactor         
    0
        iTileHealFactor             
    0
        iActivePlayer                 
    CyGame().getActivePlayer()
        
    pActivePlayer                 gc.getPlayer(iActivePlayer)
        
    iActivePlayerTeam             pActivePlayer.getTeam()
        
    eDomain                     gc.getUnitInfo(pUnit.getUnitType()).getDomainType()
    This one is quite important to know. A sea or air unit can be healed by a land unit, but only when its in a city. This leads to 2 major conclusions :
    - a sea unit with promotion Medic I (same tile heal +10%) located in a city can heal a land unit located in the city and can also heal a land unit with Medic II (adjacent tile heal + 10%) if the unit is on a cities adjacent tile.
    - a sea unit on the coast with Medic II can't heal a land unit on an adjacent tile.
    Due to that I set the units domain to DOMAIN_LAND when the units to be examined it is located in a city.
    PHP:
        # a sea or air unit in a city, behaves like a land unit
        
    if pPlot.isCity():
            
    eDomain DomainTypes.DOMAIN_LAND

    Next the adjacent tile heal is watched. A loop though all adjacent tiles for a friendly (own or teammate) unit which has a protmotion with adjacent tile heal. I don't look for the promotion itself, but for its effects on the heal factor with the function CyUnit.getAdjacentTileHeal(). This makes the function mod friendly.
    Two things to be mentioned :
    - the same tile is ignored, because the adjacent tile heal has no effect on the same tile!!!
    - if the adjacent plot is a city, also the air and sea units are considered.
    PHP:
        # calculate the adjacent-tile heal-factor caused by other units (only the unit with the highest factor counts)
        
    for dx in range(-12):
            for 
    dy in range(-12):
                
    # ignore same tile. Adjacent-tile healing does not work on the same tile.
                
    if not (dx == and dy == 0):
                    
    pLoopPlot CyMap().plot(pPlot.getX()+dxpPlot.getY()+dy)
                    
    # loop through all units on the plot
                    
    for i in range(pLoopPlot.getNumUnits()):
                        
    pLoopUnit pLoopPlot.getUnit(i)
                        
    eLoopUnitDomain gc.getUnitInfo(pLoopUnit.getUnitType()).getDomainType()
                        
    # a sea or air unit in a city, behaves like a land unit
                        
    if pLoopPlot.isCity():
                            
    eLoopUnitDomain DomainTypes.DOMAIN_LAND
                        
    # adjacent-tile heal does only work if the units have the same domain type
                        
    if (eDomain == eLoopUnitDomain):
                            if (
    pLoopUnit.getTeam() == iActivePlayerTeam):
                                if (
    pLoopUnit.getAdjacentTileHeal() > iAdjacentTileHealFactor):
                                    
    iAdjacentTileHealFactor pLoopUnit.getAdjacentTileHeal()
    Now we examine the friendly units on the same plot. More or less the same stuff as before. One thing to be mentioned here :
    - the same tile healing (as it is with the promotion Medic I) is also a self healing. Means : it has also effect on the promotions owner unit!!.
    PHP:
        # calculate the same-tile heal-factor caused by other or same unit (only the unit with the highest factor counts)
        # the same-tile healing is also a kind of self-healing. Means : the promotion Medic I has also effect on the owner unit
        
    for i in range(pPlot.getNumUnits()):
            
    pLoopUnit pPlot.getUnit(i)
            
    eLoopUnitDomain gc.getUnitInfo(pLoopUnit.getUnitType()).getDomainType()
            
    # a sea or air unit in a city, behaves like a land unit
            
    if pLoopPlot.isCity():
                
    eLoopUnitDomain DomainTypes.DOMAIN_LAND
            
    # same tile heal does only work if the units are of the same domain type
            
    if (eDomain == eLoopUnitDomain):
                if (
    pLoopUnit.getTeam() == iActivePlayerTeam):
                    if (
    pLoopUnit.getSameTileHeal() > iSameTileHealFactor):
                        
    iSameTileHealFactor pLoopUnit.getSameTileHeal()
    Because the two values adjacent tile heal factor and same tile heal factor are not summed up, we can only use the largest of both values.
    PHP:
        # only the highest value counts
        
    iTileHealFactor max(iAdjacentTileHealFactoriSameTileHealFactor)
    Next we are looking on the self healing factor. It is influenced by two factors : the territory (friendly, neutral or enemy) the unit is located on and several promotions which could increase this territory factor. Which territory the unit is currently on is determined by the plot's owner. If it's the player or a teammate we have friendly territory, if it's somebody we have war with it's enemy territory. Anything else is neutral.
    PHP:
        # calculate the self heal factor by the location and promotion
        
    iTeam pPlot.getTeam()
        
    pTeam gc.getTeam(iTeam)        
        
    iSelfHealFactor         NEUTRAL_HEAL_RATE
        iPromotionHealFactor     
    pUnit.getExtraNeutralHeal()
        if 
    pPlot.isCity():
            
    iSelfHealFactor         CITY_HEAL_RATE
            iPromotionHealFactor     
    pUnit.getExtraFriendlyHeal()
        
    elif (iTeam == iActivePlayerTeam):
            
    iSelfHealFactor         FRIENDLY_HEAL_RATE
            iPromotionHealFactor     
    pUnit.getExtraFriendlyHeal()
        
    elif (iTeam != TeamTypes.NO_TEAM):
            if (
    pTeam.isAtWar(iActivePlayerTeam)):
                
    iSelfHealFactor         ENEMY_HEAL_RATE
                iPromotionHealFactor     
    pUnit.getExtraEnemyHeal()
    Finally we are looking at the buildings which may have influence to the healing. Of course, this is only done when we are in a players or teammates city. Then we loop through all buildings in the city looking for the buildings influence on healing. Currently there is only one standard building doing so : the hospital.
    PHP:
        # calculate the heal factor by city buildings
        
    if pPlot.isCity():
            if (
    pPlot.getTeam() == iActivePlayerTeam):
                
    pCity pPlot.getPlotCity()
                
    # loop for all buldings
                
    for iBuilding in range(gc.getNumBuildingClassInfos()):
                    
    # check if city has that building
                    
    if pCity.hasBuilding(iBuilding):
                        
    # sum up all heal rates 
                        
    iBuildingHealFactor += gc.getBuildingInfo(iBuilding).getHealRateChange()
    Last thing is to sum up all the single heal factors and return the value.
    PHP:
        # return the sum of all heal factors
        
    return iTileHealFactor iBuildingHealFactor iSelfHealFactor iPromotionHealFactor    
    The value returned by this function can now be used to calculate the number of turns a unit needs to be 100% healed. An implemenation may be as follows:

    PHP:
    if (eUnitDomain == DomainTypes.DOMAIN_AIR):
        
    fCurrStrength     float(pUnit.airCurrCombatStr()*0.01)
        
    fMaxStrength     float(pUnit.airMaxCombatStr()*0.01)
    else:
        
    fCurrStrength     float(pUnit.baseCombatStr())*float(1.0-pUnit.getDamage()*0.01)
        
    fMaxStrength     float(pUnit.baseCombatStr())        

    iTurnsToHeal     int((fMaxStrength-fCurrStrength)/float(fMaxStrength*float(mt.getPlotHealFactor(pUnit))*0.01)+0.999# force to round up

    The python used here is very likly not the best possible. As many others here, I learnt python with civ4, allthough I have some years of experience as professional programmer. But this is 10 years away now.
    The knowledge about healing in civ4 I gained by try and error and lots of investigations and experiments with a random map and the world builder. There still may be some details about healing not covered by this function, but I think it offers a quite good overview about the civ4 healing details and some python basics.
     
  13. Kael

    Kael Deity

    Joined:
    May 6, 2002
    Messages:
    17,401
    Location:
    Ohio
    Thats an amazing contribution 12monkeys! Not only excellent code but a great example of how to implement a whole concept in python. Thanks for sharing it!
     
  14. IVZanIV

    IVZanIV Warlord

    Joined:
    Jan 14, 2006
    Messages:
    285
    12monkeys, if you set the domain of sea and air units to land while in a city, doesn't that mean that air units will not work as they were created ever again? Because air units by default stay in cities and bomb from there, but as land units, they can move, which is against the "city rule"... Sorry if that's wrong...
     
  15. IVZanIV

    IVZanIV Warlord

    Joined:
    Jan 14, 2006
    Messages:
    285
    Also, since it is here...

    This piece of code is so simple that I'm not sure if it's even worthy of putting here, but it was my first successful venture into Python, and I'm actually kind of proud of it. :crazyeye:

    Code:
    	def onLoadGame(self, argsList):
    #Displays the "Welcome Back!" Message when a saved game loads.
                            CyInterface().addImmediateMessage("Welcome back!","")
    #ENDLoadGame
    		return 0
    What it does:
    This code prints a simple message when the game is loaded, giving a "homely" feel. :D

    Use:
    Giving your code that extra touch of human emotion.
     
  16. naf4ever

    naf4ever Dread Lord

    Joined:
    Feb 8, 2003
    Messages:
    405
    Location:
    Southeast Washington State
    Trust me this is very useful. I started programming pretty much from scratch a month ago just so i could mod python civ files.. It took me a week just to figure out how to put up a message like yours. So hopefully you'll save someone else a week of time... heh.

    Heres another useful message contribution that can be used at any interrupt point. IVe found it invaluable when learning python and trying to figure out if my programs are actually working or not:
    Code:
    myResult = "whatever the heck your trying to test"
    
    CyInterface().addMessage(CyGame().getActivePlayer(),True,10,"%s" %(myResult),'',
    1,'',ColorTypes(8),-1,-1,True,True) 
    What it does: Prints a message thats based on a variable, in this case myResult.

    Use: If you got some long complex function that gives no python errors yet doesnt seem to be working it can be frustrating debugging it. This allows you to test if the result your trying to achieve is actually happening in the first place and if so what its value is. Especially good if you got some function that involves lots of math or got some loop error you are trying to track down.
     
  17. 12monkeys

    12monkeys Prince

    Joined:
    Nov 24, 2003
    Messages:
    440
    Location:
    Germany, Europe
    I don't change the unit itself. I just treat them in the code as land units, to simplify the handling. So there is no problem.
     
  18. IVZanIV

    IVZanIV Warlord

    Joined:
    Jan 14, 2006
    Messages:
    285
    Exact same thing for me, and I like it so much now, I don't feel like stopping. :mischief:

    Ah, ok, that makes sense. Thanks.
     
  19. mrkingkong

    mrkingkong Young Padawan

    Joined:
    Apr 19, 2005
    Messages:
    350
    Location:
    Between fantasy and reality
    Hey, which file do you write these codes into for them to actually do anything? Do you put them in the CvEventManager.py file only?

    This is very useful, iv learnt a lot so far but iv yet to program my first successful python event (mainly due to my fear it will all go badly wrong)

    mrkingkong
     
  20. TheLopez

    TheLopez Deity

    Joined:
    Jan 16, 2006
    Messages:
    2,525
    Location:
    Oregon

    naf4ever that is good but this gives you a lot more flexibility.
    Basically this is a file almost completely gutted except for the important code and example. Lets call this file CvFoo.py.

    Code:
    # Import statements
    # ...
    # ...
    
    # Global variables 
    # ...
    # ...
    
    # Change this to enable or disable debug messages
    g_bDebug = true
    
    LOG_ONLY = 1
    SCREEN_ONLY = 2
    LOG_AND_SCREEN = 3
    
    # Change to redirect the debug messages to the logs, screen or both.
    g_iDebugMessageTarget = LOG_ONLY
    
    class CvFoo:
    
    	def fooBar(self):
    
    		# Debug code - Start
    		if(g_bDebug):
    			self.printDebugMessage("Hello, World!")
    		# Debug code - End		
    
    		return iHangingBodyCount
    
    
    	# Prints the debug message to the logs, screen or both	
    	def printDebugMessage(self, strMessage):
    	
    		if(g_iDebugMessageTarget == LOG_ONLY):
    			CvUtil.pyPrint(strMessage)
    		elif(g_iDebugMessageTarget == SCREEN_ONLY):
    			CyInterface().addImmediateMessage(strMessage)
    		else:
    			CvUtil.pyPrint(strMessage)
    			CyInterface().addImmediateMessage(strMessage)
    
     

Share This Page