Python Wonders and their effects

I actually have a wonder that does this already in the game, trans-siberian railroad, and it improves tundra tiles and camp resources and ocean resources. It's all Python from Tsentom's Ice Hotel wonder. I've played a game with this wonder and it hasn't caused any significant lag that I've experienced.
Ok, I'd like to look at it if you send the code to me. But chances are still that the tile bonuses are there for all eternity once they are set in place. I'll give it the benefit of a doubt though.

All I'm saying is that I will tell you what the limitations of any set of code will be, and give you the option to do something else instead. If you can afford the additional lag, of course.
I think so. I've got it set in my other mod so that if you have the civic Vassalage there is no revolt when the city is taken over. I think I know enough to edit that to rely on a Trait instead, like Trait_Colombia. But I've never tried it.
There should be no need for any of that. I'll have a look in the API for what is available for cities.
What I'm looking for is something where if you kill a barbarian unit, you have a chance of the unit joining your side and earning and immediate 10 gold to your treasury. So if I kill a barbarian warrior I have a 20 percent chance of getting a warrior unit. Applies to land units only.
Ok, I see no problems with any of this. (Also applies to the Mayans, which is basically the same thing.)
Looks good to me. Seems that tying the damage to trying to move through Russia is pretty much how Russian Winter worked.
I think that the last proposal in that thread is to damage all enemy units that either move or fight. Still sounds good?
Cool, I've got the python in place to make Ships move one farther per turn thanks to Tsentom's Seafaring trait (Englands UP), but I'm having trouble applying to other types of units (like Melee, etc.).
You could send me that code also.
I have several modcomps downloaded off the site, but almost all of them deal with EventManager.
Just to make it very clear: All CivIV Python is always connected to the Event Manager. Its optional whether or not you wanna keep all the code in that module or spread it around in other modules. It works all the same, and since I will be working on the powers its more convenient for both of us if we confine this part of the mod to a module of its own.

So the GGPowers module will "deal" with CvEventManager by function calls from the latter to the former. I'll explain what to do later.

So you can still send me the appropriate code from select Event Managers. :king:

I don't think I am capable of making any of these things as unique powers, rather I can use EventManager to tie these abilities to having a trait, building, etc.
There should be no need for any of that trait, promotion, building et cetera nonsense when doing Python. You don't need to tie anything to anything else like that. Instead, everything happens when "game events" take place. This is the difference between XML and Python modding, basically.

I can do Japan's UP not by creating a player-specific code, but by say using existing work done by other modders. In the Spoiler is an example of how I intend to create Japan's Units 20 percent chance to heal fully:
Ok, that makes little to no sense at all. I'll use something like this instead:
Code:
def japan(ePlayer, pUnit):
    if isCivPlayer(players["Japan"], ePlayer):
        if isProbabilityPercent(20):
            pUnit.setDamage(0, False)
isCivPlayer() and isProbabilityPercent() are helper function. The players is a dictionary data structure I created for your mod since there can be several players with the same Civ attribute. And both will be found in the GGUtils module, but don't worry about any of it.

So while I'm eager to look at any code you already have, chances are that I'm not gonna use it. It will just make it easier for me to get the job done.
 
Gran Colombia: No Revolting in Captured cities
About this - I'm not quite sure what you mean or how exactly it works (in-game). But I did find this method: CyCity.setOccupationTimer(). What if it was zeroed any time the Colombians acquired a city? Would this do what the request says?

Sumeria: Each city is a source of freshwater for farming purposes.
I haven't been able to find anything in the CyPlot class to do anything like this. There is a isFreshWater() method but that only return True/False and can't change the tile. But I guess adding a river on the city tile would do the trick, but that would actually display a river on the map. Which may not be what the request was.
 
How about The_J's Water Modcomp? But make the improvement buildable only if you have a tech that is unresearchable. Then build a well on top of the city. Perhaps scale the graphics down to make it invisible.
 
Yeah, the Sumeria power might not be a good candidate for a Python solution.
 
Ah, my reply got deleted! Here it is again.

Yes, pCity.setOccupationTimer(0) is the key, it means cities are immediately on your side when conquered. Very nice. I'll think on what to do about Sumeria, maybe a different power is needed?
 
I'll think on what to do about Sumeria, maybe a different power is needed?
I'll look into CvGameUtils before ruling anything out though. There is a canBuild() method that seems to be moddable in a way that checks whether or not there is a sumerian city adjacent to the tile. And if it is, the method returns True.

Does anyone know if canBuild() even has to do with tile improvements? :confused: There is a iBuild variable but I don't know what it is referencing.

Other than that, I'm actually done with all powers except Arabia (but including Sumeria). I'll have to test everything first, though. :p
Spoiler :
Code:
### Unique powers for Glory and Greatness mod, by Baldyr.

from CvPythonExtensions import *
import PyHelpers
from GGUtils import *

# constants

gc = CyGlobalContext()
Game = CyGame()
Map = CyMap()

iMayanProbability = 25
iNetherlandsInterest = 3
iJapanProbability = 20
iGermanProbability = 50
iGermanGold = 50
iOttomanProbability = 50
iOttomanGold = 50
iOttomanCulture = 100
iZuluMoves = 1

eBarbarian = gc.getBARBARIAN_PLAYER()
eLand = getIndex("Domain", "Land")
eSea = getIndex("Doman", "Sea")
eFarm = getIndex("Improvement", "Farm")
eMelee = getIndex("UnitCombat", "Melee")
eWarrior = getIndex("Unit", "Warrior")
eWorker = getIndex("Unit", "Worker")

# functions - called from CvEventManager

def arabia():
        "Bonus food and commerce from Desert Tiles"

def colombia(pCity, ePlayer, bConquest):
        """
        No Revolting in Captured cities.
        """
        if bConquest and isCivPlayer(players["Colombia"], ePlayer):
                pCity.setOccupationTimer(0)

def germany(pUnit, ePlayer, pyPlayer):
        """
        50 percent chance to capture barbarian units and earn gold.
        """
        if ( isCivPlayer(players["Germany"], ePlayer)
             and pUnit.getDomain() == eLand
             and pUnit.getOwner() == eBarbarian
             and isProbabilityPercent(iGermanPropability, "germany") ):
                pyPlayer.initUnit(pUnit.getUnitType(), pUnit.getX(), pUnit.getY())
                pyPlayer.changeGold(iGermanGold)

def japan(ePlayer, pUnit):
        """
        20 percent chance for a unit to heal fully after combat victory.
        """
        if isCivPlayer(players["Japan"], ePlayer) and isProbabilityPercent(iJapanProbability, "japan"):
                pUnit.setDamage(0, False)

def maya(pUnit, ePlayer, pyPlayer):
        """
        Enslave - 25 percent chance to get a Worker unit any time a land unit is defeated in combat.
        """
        if ( isCivPlayer(players["Maya"], ePlayer)
             and pUnit.getDomain() == eLand
             and isProbabilityPercent(iMayanPropability, "maya")
             and pUnit.getUnitType() >= eWarrior ):
                pyPlayer.initUnit(eWorker, pUnit.getX(), pUnit.getY())

def netherlands():
        """
        Receive 3 percent interest on gold reserves each game turn (rounded down).
        """
        for pPlayer in getCivPlayerInstances(players["Netherlands"]):
                pPlayer.setGold(int(pPlayer.getGold() * ((iNetherlandsInterest + 100) / 100.0)))

def ottoman(*args):
        """
        Redirects the calls to the appropriate sub-function depending on what event triggered the original callup.
        """
        if isCivPlayer(players["Ottomans"], args[1]):
                if isinstance(args[0], CyUnit):
                        ottomanCapture(*args)
                else:
                        ottomanCulture(*args)
                
def ottomanCapture(pUnit, ePlayer, pyPlayer):
        """
        5O percent chance to capture enemy ships and earn gold.
        """
        if pUnit.getDomain() == eSea and isProbabilityPercent(iOttomanPropability, "ottoman"):
                pyPlayer.initUnit(pUnit.getUnitType(), pUnit.getX(), pUnit.getY())
                pyPlayer.changeGold(iOttomanGold)

def ottomanCulture(pCity, ePlayer, bConquest):
        """
        Spread culture in conquered cities.
        """
        if bConquest:
                pCity.changeCulture(ePlayer, iOttomanCulture, True)

def russia(pUnit, pPlot, bCombatResult):
        """
        Enemy units in Russian territory take damage when either moving or fighting.
        """
        eUnitOwner, ePlotOwner = pUnit.getOwner(), pPlot.getOwner()
        if ( isCivPlayerAlive(players["Russia"])
             and not isCivPlayer(players["Russia"], eUnitOwner)
             and isCivPlayer(players["Russia"], ePlotOwner)
             and isAtWarCivPlayer(players["Russia"], eUnitOwner) ):
                if bCombatResult:
                        for pCurrentUnit in list(pPlot.getUnit(i) for i in range(pPlot.getNumUnits())):
                                if pCurrentUnit.getOwner() == eUnitOwner:
                                        pCurrentUnit.setDamage(pCurrentUnit.getDamage() + 5, eBarbarian)
                else:
                        if pUnit.movesLeft() == 0:
                                pUnit.setDamage(pUnit.getDamage() + 5, eBarbarian)

def zulu(pUnit, pyPlayer):
        """
        Extra movement for melee units built.
        """
        if ( isCivPlayer(players["Zulu"], pyPlayer.GetCy())
             and gc.getUnitInfo(pUnit.getUnitType()).getUnitCombatType() == eMelee ):
                pUnit.setMoves(pUnit.maxMoves() + iZuluMoves)
Nothing is tested yet and the GGUtils module (which has about as many lines of code) is required for any of this to work. I'll post both once I'm done testing everything.
 
Ah, fresh water really isn't enabling Farm building, but rather enhances the :food: yield from the Farm. Ok, then my idea is broken, I guess. :rolleyes:
 
I'll look into CvGameUtils before ruling anything out though. There is a canBuild() method that seems to be moddable in a way that checks whether or not there is a sumerian city adjacent to the tile. And if it is, the method returns True.

Does anyone know if canBuild() even has to do with tile improvements? :confused: There is a iBuild variable but I don't know what it is referencing.

Other than that, I'm actually done with all powers except Arabia (but including Sumeria). I'll have to test everything first, though. :p
Spoiler :
Code:
### Unique powers for Glory and Greatness mod, by Baldyr.

from CvPythonExtensions import *
import PyHelpers
from GGUtils import *

# constants

gc = CyGlobalContext()
Game = CyGame()
Map = CyMap()

iMayanProbability = 25
iNetherlandsInterest = 3
iJapanProbability = 20
iGermanProbability = 50
iGermanGold = 50
iOttomanProbability = 50
iOttomanGold = 50
iOttomanCulture = 100
iZuluMoves = 1

eBarbarian = gc.getBARBARIAN_PLAYER()
eLand = getIndex("Domain", "Land")
eSea = getIndex("Doman", "Sea")
eFarm = getIndex("Improvement", "Farm")
eMelee = getIndex("UnitCombat", "Melee")
eWarrior = getIndex("Unit", "Warrior")
eWorker = getIndex("Unit", "Worker")

# functions - called from CvEventManager

def arabia():
        "Bonus food and commerce from Desert Tiles"

def colombia(pCity, ePlayer, bConquest):
        """
        No Revolting in Captured cities.
        """
        if bConquest and isCivPlayer(players["Colombia"], ePlayer):
                pCity.setOccupationTimer(0)

def germany(pUnit, ePlayer, pyPlayer):
        """
        50 percent chance to capture barbarian units and earn gold.
        """
        if ( isCivPlayer(players["Germany"], ePlayer)
             and pUnit.getDomain() == eLand
             and pUnit.getOwner() == eBarbarian
             and isProbabilityPercent(iGermanPropability, "germany") ):
                pyPlayer.initUnit(pUnit.getUnitType(), pUnit.getX(), pUnit.getY())
                pyPlayer.changeGold(iGermanGold)

def japan(ePlayer, pUnit):
        """
        20 percent chance for a unit to heal fully after combat victory.
        """
        if isCivPlayer(players["Japan"], ePlayer) and isProbabilityPercent(iJapanProbability, "japan"):
                pUnit.setDamage(0, False)

def maya(pUnit, ePlayer, pyPlayer):
        """
        Enslave - 25 percent chance to get a Worker unit any time a land unit is defeated in combat.
        """
        if ( isCivPlayer(players["Maya"], ePlayer)
             and pUnit.getDomain() == eLand
             and isProbabilityPercent(iMayanPropability, "maya")
             and pUnit.getUnitType() >= eWarrior ):
                pyPlayer.initUnit(eWorker, pUnit.getX(), pUnit.getY())

def netherlands():
        """
        Receive 3 percent interest on gold reserves each game turn (rounded down).
        """
        for pPlayer in getCivPlayerInstances(players["Netherlands"]):
                pPlayer.setGold(int(pPlayer.getGold() * ((iNetherlandsInterest + 100) / 100.0)))

def ottoman(*args):
        """
        Redirects the calls to the appropriate sub-function depending on what event triggered the original callup.
        """
        if isCivPlayer(players["Ottomans"], args[1]):
                if isinstance(args[0], CyUnit):
                        ottomanCapture(*args)
                else:
                        ottomanCulture(*args)
                
def ottomanCapture(pUnit, ePlayer, pyPlayer):
        """
        5O percent chance to capture enemy ships and earn gold.
        """
        if pUnit.getDomain() == eSea and isProbabilityPercent(iOttomanPropability, "ottoman"):
                pyPlayer.initUnit(pUnit.getUnitType(), pUnit.getX(), pUnit.getY())
                pyPlayer.changeGold(iOttomanGold)

def ottomanCulture(pCity, ePlayer, bConquest):
        """
        Spread culture in conquered cities.
        """
        if bConquest:
                pCity.changeCulture(ePlayer, iOttomanCulture, True)

def russia(pUnit, pPlot, bCombatResult):
        """
        Enemy units in Russian territory take damage when either moving or fighting.
        """
        eUnitOwner, ePlotOwner = pUnit.getOwner(), pPlot.getOwner()
        if ( isCivPlayerAlive(players["Russia"])
             and not isCivPlayer(players["Russia"], eUnitOwner)
             and isCivPlayer(players["Russia"], ePlotOwner)
             and isAtWarCivPlayer(players["Russia"], eUnitOwner) ):
                if bCombatResult:
                        for pCurrentUnit in list(pPlot.getUnit(i) for i in range(pPlot.getNumUnits())):
                                if pCurrentUnit.getOwner() == eUnitOwner:
                                        pCurrentUnit.setDamage(pCurrentUnit.getDamage() + 5, eBarbarian)
                else:
                        if pUnit.movesLeft() == 0:
                                pUnit.setDamage(pUnit.getDamage() + 5, eBarbarian)

def zulu(pUnit, pyPlayer):
        """
        Extra movement for melee units built.
        """
        if ( isCivPlayer(players["Zulu"], pyPlayer.GetCy())
             and gc.getUnitInfo(pUnit.getUnitType()).getUnitCombatType() == eMelee ):
                pUnit.setMoves(pUnit.maxMoves() + iZuluMoves)
Nothing is tested yet and the GGUtils module (which has about as many lines of code) is required for any of this to work. I'll post both once I'm done testing everything.

Baldyr, you're amazing! How do you propose testing it out? You want to mail me the files or should I post a beta on megaupload or something and send you the link and you can merge and test that way? Awesome work. I'll try to think up something new for Arabs and Sumeria.

If you have time, I have a few ideas for some other nations I can send you to include in this for other civs.
 
Baldyr, you're amazing!
Thank you, but lets celebrate once we're done. :lol:
How do you propose testing it out?
My plan was for me to test out the Python code independently from your mod, as I put everything in self-contained modules. I'm only gonna check that the code fires as intended and produces no exceptions. Play-testing is another thing altogether, and I trust you can manage this on your own. Things will need tweaking and actual game situations will produce unforeseen issues that need to be taken care of. But we'll get there, eventually.
I'll try to think up something new for Arabs and Sumeria.
I could actually give the Arabs a try if you like. But only after I've completed the rest - the hard part is still ahead of me. Debugging, man! :p
If you have time, I have a few ideas for some other nations I can send you to include in this for other civs.
Post any further ideas here so that we can discuss/evaluate them first.
 
Question: Will all Russia players be immune to the "Russian Winter" power (of other Russia players). The current code only affects non-Russia players, but this might not be what you want... (At this stage it can easily be changed though.)

Edit: I'm testing the Russian power right now and one issues has come up: Units with more than one movement point are spared the damage if they don't spend the last movement point. Good or bad, depends on whether or not you will view this as a feature or a bug. :p I think it can be "fixed" though, but I'll just hand over the design decision to you.
 
Unfortunately I'm not having any luck with the Zulu power. I was under the impression that the movement points of a unit could be changed with CyUnit.setMoves() but nor this or CyUnit.changeMoves() seem to do anything at all. :confused:

This would probably be a candidate for a XML mod then. Like have some promotion granting movement to units that is only available to the Zulu. Or something.
 
I'm done testing the code I have, unfortunately I couldn't get the Zulu power working, leaving you with yet another one missing. :rolleyes: While I await some information over e-mail I thought I'd revisit the Arabian power, which I have skipped for now.

So, you wanna add tile yields for desert tiles owned by any Arabian player, right? 2 Commerce and 2 Food per tile, if I'm not mistaken? (The actual settings will be easy to tweak later in any case.)

My idea for a Python script for this is to hook up to every game event that deals with cities, like cityFounded, cityAcquired, cityRaized, cultureExpansion and so on. I'm gonna basically have the same code check and adjust all desert tiles around any city whenever any such event takes place. This should cause less lag than to, say, loop through all tiles on every game turn to make sure everything is up-to-date.

Maybe I can also make it faster still by automatically excluding cities with no desert tiles within reach, like by maintaining an array of desert cities - or by storing a value in each CyCity object making it either valid or invalid in this context. Because the actual tiles won't change during game play, right? So it will always be the same desert tiles that need to be checked? I'm thinking I could basically "cache" these tiles, somehow. Like store the plot IDs of all none-desert tiles in some data structure and check any tile against this instead of going through all tiles within reach of a city every time. (Tiles already in the array will be excluded from any further checks.)

In short: This ought to be fun. :D

edit: I think I did it - now I have to test it. All ideas above included, so it shouldn't cause too much lag. :rolleyes:
 
A few quick notes, I'll do a more extensive post about 2 hours from now:

Russia is to only affect enemy units if possible.

Great news on the Arab power, glad to hear it.

Sure, I can link it to the Zulu trait, that all melee get Morale promotion. Probably good too because then you couldn't do something like take a Move 3 Impi and give it the morale promotion in addition. It's what I ended up doing with the America Settler and it would be great.

I will post the other ideas later in a more extensive post, but still great work so far.
 
A few quick notes, I'll do a more extensive post about 2 hours from now:
That will probably be past my bedtime, but I'll be up for a quickie before work... :p

Russia is to only affect enemy units if possible.
Just to clarify - the Russian power affects all enemy unit except those who belong to the Russian denomination (the same or other). So the question is: Should the units of Russia #1 take damage in Russia #2 territory when they are at war with each-other? Or does the Russian power make ones own units immune to the "winter" (of other Russians)?

Great news on the Arab power, glad to hear it.
Its a bit rough going, actually. It turns out that several things just aren't working the way I expected them to... But I haven't given up on it yet. :king:

edit: Ok, now I've hit a hurdle that I don't believe I can overcome. The only way to affect the tile yields with Python seems to be CyGame.setPlotExtraYield() and it doesn't quite do what it advertises. Because it will only add yields - not set them to any value. So passing it iExtraYield=2 will increase the tile yield by 2 - not set the tile yield to 2. And iExtraYield=0 will do nothing, nor will iExtraYield=-2.

So I'm basically stuck trying to revert the yield changes dynamically as Arab cities and tiles are lost... Would it be kosher to just leave those increase yields in place, like forever? :eek2:
 
Response to your latest followed by other Python Powers:

Russia 2 should take damage in Russia 1 if 2 is at war with 1. The simulation here is enemies seeking to take the fight into Russia.

Hmmm, I don't know about the Arab Power. I think it would be a problem in that it just means a civ can target Arab Desert cities and enjoy their bonuses. So probably not the best idea to do anything permanent.

Other power ideas:

Polynesia: Don't need open borders to move units through others' land
Scandinavia (Vikings, renamed): Double income from pillaging improvements.
Sioux (Native America): Bonus to fighting in plains.
Persia: All units one extra move during Golden Age
Inca: Free tech on reaching Classical, Renaissance and Modern Eras.
Rome: Extra movement on roads, -25 percent cost to build buildings already in the capital.

Sumeria's new power will be similar to the Great Wall: No barbarian entry into their land. This can be accomplished through XML on their Palace building. I'm not sure what to do about Arabia at that moment.

Anyway, good night then and we'll talk during the week.

P.S. Is there a way to prevent people from doing things like Setting up unrestricted leaders? IF so that would be very useful.
 
Polynesia's is in RFC.

Vikings can just be a trait.

Persia seems too weak compared to the Zulu power.

Rome's first half is done in RFC.

The second one is probably something like getbuilding (iCapital) or whatever.
 
Unfortunately I'm not having any luck with the Zulu power. I was under the impression that the movement points of a unit could be changed with CyUnit.setMoves() but nor this or CyUnit.changeMoves() seem to do anything at all. :confused:

The movement value itself is a multiple of 12 (or 20, forgot it), that's probably the problem here. 1 full movement poin will not be generated by changeMoves(1), rather by (12).
 
Polynesia's is in RFC.

Vikings can just be a trait.

Persia seems too weak compared to the Zulu power.

Rome's first half is done in RFC.

The second one is probably something like getbuilding (iCapital) or whatever.

Yeah, Vikings is done with the Nomadic Trait on this site, I can probably blend that. So Baldyr, I'll do Scandinavia, I think I've got a pretty clean way.

Persia gets Double length of Golden Ages, Extra movement during golden ages and can have vassals at the start of the game. It's just I can do the others, it's the extra movement during Golden Age is the big key.
 
I'll look into the new powers tonight, if I have the time. In the meanwhile I would need all the CivilizationTypes tags for your mod, like CIVILIZATION_ARABIA - they are used for identifying what players have which powers. I guess I only really need the ones that are new/changed, like Grand Colombia. Because then I will be able to send you the work that I already tested.
 
The movement value itself is a multiple of 12 (or 20, forgot it), that's probably the problem here. 1 full movement poin will not be generated by changeMoves(1), rather by (12).

Try 60.

Well, it's actually the MOVE_DENOMINATOR value defined in GlobalDefines.xml, so instead of adding a fixed value you should look up that value and add it to get an extra move: gc.getDefineINT("MOVE_DENOMINATOR").
 
Top Bottom