Python Wonders and their effects

So the Civilization names?

Like these:

CIVILIZATION_GRAN_COLOMBIA
CIVILIZATION_POLYNESIA
CIVILIZATION_SIAM
CIVILIZATION_SONGHAI
CIVILIZATION_ISRAEL
CIVILIZATION_IROQUOIS

Or something else? They all have a trait so named like TRAIT_IROQUOIS, TRAIT_AMERICA etc., and a TECH_IROQUOIS etc.

Is that what you're wanting?
 
Is that what you're wanting?
Yeah, thanks. I'll just need CIVILIZATION_GRAN_COLOMBIA for now, but who knows?

I'll do some last minute testing before sending you the first set of powers. Hopefully I can include a working Zulu power for you to test out also.
 
No, still no luck with:
Code:
pUnit.setMoves(pUnit.maxMoves() + iZuluMoves * gc.getDefineINT("MOVE_DENOMINATOR"))
or
Code:
pUnit.changeMoves(iZuluMoves * gc.getDefineINT("MOVE_DENOMINATOR"))
What am I still getting wrong? :confused:

edit: Mystery solved. :p CyUnit.setMoves() sets the units spent movement points for the game turn. So setting it to zero will give the unit back all its moves. This is all and that is all she wrote.

Therefore I believe that the Zulu power belongs to the domain of XML (or SDK) modding.
 
Ok, I think I found a way to do the Zulu power with Python by changing the Zulu player's team's extra land domain moves on the unitSelected callup. This would mean that every time a unit is selected in the game the code will check if its a Zulu unit and if it is - lookup whether or not it is a melee unit. If both checks clear the extra movement bonus is increased by one - otherwise it is reset to zero.

I guess almost every unit would be selected once per turn, or something, so the code for the Zulu power would be called equally as many times. Does anyone have an inkling on how much lag something like this would cause?

edit: No, still no luck. It seems that unitSelected isn't what I though it was. Because I can't get the callup to fire when I select a unit.

seasnake, I'll have to get back to you on this Python stuff tomorrow. Now I really have to get some shut-eye... :p
 
I thought about it today and it dawned on me that we could still use the code I've done for Arabia, but instead of increasing tile yields directly - and reverting them once tile ownership changes - we could use an unbuildable improvement. (Like a desert caravan, Bedouin encampment, or something. Thinking further about it these improvements could be dynamic and "migrate", so to speak.)

I actually think I'll test the validity of this idea with a Camp improvement or something. Then it will only be a matter of changing the improvement (changing the word "camp" to "caravan" or whatever in the settings for the module).

edit: It could also be cool if the Caravan improvement could mature into a Bedouin Encampment with time/work. And a Bedouin Encampment could spawn units under certain circumstances, like when the city is lost. (Then the improvements would be erased anyway, so they could turn into military units instead. I got my inspiration from the partisans event, obviously.)
 
Other power ideas:

Polynesia: Don't need open borders to move units through others' land
I'm not aware of any way to achieve this through CvEventManager, but there is a unitCannotMoveInto() method in the CvGameUtils module. It might be worth a try, although I know Rhye did this in the SDK with the Dutch UP in RFC. Speaking of which - is the Polynesian variety also restricted to seaborne units?

Scandinavia (Vikings, renamed): Double income from pillaging improvements.
This could probably be done on unitPillage in the Event Manager. Otherwise there is always doPillageGold() in CvGameUtils. (I can't find any traces of how Rhye did his Viking UP though. Could it be a simple XML setting? :confused:)

Sioux (Native America): Bonus to fighting in plains.
There is a doCombat() method in the CvGameUtils. I'm a bit unsure what to do with it though. It might end up in a rather dirty hack. An automatic promotion could be the way to go here (if one can be designed to give terrain combat bonus).

Persia: All units one extra move during Golden Age
I guess the CyUnit.setMoves() method could achieve this, somehow. It wouldn't show up in the unit statistics though, but rather work in some confusing way where movements points aren't always subtracted when a unit moves. So this is another candidate for a SDK hack.

Another idea would be to increase the domain extra moves for Persia once a Golden Age starts, and reset them all once it is over. This means that it would be very possible to restrict this power to some domains only.

Inca: Free tech on reaching Classical, Renaissance and Modern Eras.
This should be somewhat easy to achieve by "conventional" Python scripting. I suppose that the human player gets to choose what tech is granted? (It might be as simple as to finish the current research project - or to simply grant whatever it is the player is researching.)

Rome: Extra movement on roads, -25 percent cost to build buildings already in the capital.
These are probably both SDK projects. (Unless they can be done with some clever XML settings.)

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.
Ok, thats one more taken care of then.

So I guess I will get to work on the Incas, the Persians and the Scandinavians once I get the time. For starters.
 
I thought about it today and it dawned on me that we could still use the code I've done for Arabia, but instead of increasing tile yields directly - and reverting them once tile ownership changes - we could use an unbuildable improvement. (Like a desert caravan, Bedouin encampment, or something. Thinking further about it these improvements could be dynamic and "migrate", so to speak.)
I think I basically got this to work, but one issue had cropped up: Changing tile ownership doens't trigger the code that sets/removes the improvements - only cities expanding their cultural level/reach. So there will be occasions when tile ownership changes but the improvements remain in place. The improvements will only be updated once one of the cities reach the next cultural level.

I don't know how bad this is, but it does seem a bit buggy. :p

The alternative would be to update all tiles on every turn, which seems sub-optimal. The inevitable lag could however be reduced by indexing and checking desert tiles only.

One possible solution could be to firstly index all desert tiles (either on initialization with the whole map) or dynamically by collecting the data on desert tiles whenever a city is founded. Or both - the code collecting data on the desert tiles surrounding new cities would access the global data for faster execution - and the code updating the improvements would access the list over near city desert tiles on every turn. So if there are 10 desert tiles withing reach of all the cities currently in play, then the code would only check those 10 tiles on each turn. Which doesn't seem like a huge cause for lag.

Should I try this approach instead?
 
Wow a lot to respond too:

On Arabia: I agree that limiting lag time is a big component, the game will be no fun if it doesn't run well and quickly. If you could limit the code to check just those tiles that would be awesome.

Scandinavia: I can figure this out, I can link this ability to the Viking Palace with a Tsentom wonder. Just work on Inca and Persia when it is convenient and I'll get the Scandinavians done tonight.

Zulu: The free promotion is working well, and it was easy. And it really makes the Zulu a nightmare to fight, which is pretty good.

Polynesia: Their Unique Units are both land based, one is a warrior replacement that moves 2 and the other is a Swordsman replacement that doesn't need Iron and has a huge bonus against Melee units.

Rome: Hmmm...I don't think the building bonus can be done by XML, but maybe the road bonus can. Isn't their a tech that gives extra movement on roads? If there is, than I can make Rome's unique tech do the same.

General Question: Is it possible to enable civic abilities in Python without having the civic itself, like rushing items with gold without having Universal Suffrage or being able to draft without Nationhood? Because if so, that would really open up some ideas for the game.

EDIT: ROME'S ROAD BONUS WAS QUITE EASY, ACTUALLY. TOOK LESS THAN ONE MINUTE TO FIGURE OUT. SURELY THIS IS A VICTORY FOR GOOD!
 
On Arabia: I agree that limiting lag time is a big component, the game will be no fun if it doesn't run well and quickly. If you could limit the code to check just those tiles that would be awesome.
I just realized there is a doPlotCulture() method in CvGameUtils. I'll try to hack into it in order to get my current code running, and get back to you.

Scandinavia: I can figure this out, I can link this ability to the Viking Palace with a Tsentom wonder. Just work on Inca and Persia when it is convenient and I'll get the Scandinavians done tonight.
Sure, but all that is really needed is probably two lines of code. (Compare the Japanese code you suggested to what I ended up using.) These unique palace fixes are really sub-optimal, to be honest. (If you have the code I could just use the call and the API method and add the power to my own module.)

General Question: Is it possible to enable civic abilities in Python without having the civic itself, like rushing items with gold without having Universal Suffrage or being able to draft without Nationhood? Because if so, that would really open up some ideas for the game.
The way Python scripting works, is that you fire some lines of code on some game event from the Event Manager. While there is a CyCity.hurry() method available - what "event" would force the city to whip/buy the current building project?

So unless there is something like cannotHurry() in CvGameUtils that can be edited to return True I don't think Python is the answer...
 
Good Morning!

Okay, I'll e-mail you the lines of code in GameUtils that make the pillage thing work.

I'm scouring XML for some options right now, and the very least i can make gold rushing cheaper as someone's power.

Working on the mod tonight and watching basketball, pretty good night so far.
 
Okay, I'll e-mail you the lines of code in GameUtils that make the pillage thing work.
Thanks. I figured out a really simple way of doing this:
Spoiler :
In CvGameUtils:
Code:
	def doPillageGold(self, argsList):
...
		[B]import GGPowers
		return iPillageGold * GGPowers.scandinavia(pUnit)[/B]
In GGPowers:
Code:
[B]def scandinavia(pUnit):
        return isCivPlayer("Scandinavia", pUnit.getOwner()) + 1[/B]
Disclaimer: I haven't had time to test this yet, so I might need to edit something. I'll include the finished code in the next version.

Beats having all that palace code running all of the time.

I'm scouring XML for some options right now, and the very least i can make gold rushing cheaper as someone's power.
You should also look in the CivIV Python API for useful stuff. If you find it, I will make it work for you. :D
 
I thought I'd have some fun with this, so I wrote a spanking new code for the Arabian power. (It may end up in a module of its own.) Unfortunately I might not have any time to test any of it before the weekend, but I though I'd share with you the new CityDesert class:
Spoiler :
Code:
class CityDesert:

        desertPlotDict = initPlotDict()

        def __init__(self, iPlot):
                self.ID = iPlot
                self.iX = Map.plotX(iPLot)
                self.iY = Map.plotY(iPlot)
                self.bActivated = False

        def getID(self):
                return self.ID

        def getCy(self):
                return Map.plotByIndex(self.ID)

        def getCoords(self):
                return (self.iX, self.iY)

        def getOwner(self):
                return self.getCy().getOwner()

        def checkOwner(self):
                return isCivPlayer("Arabia", self.getOwner())

        def isOwned(self):
                return self.checkOwner() != None

        def isActived(self):
                return self.bActivated

        def setActivated(self):
                self.bActivated = True

        def addCaravan(self):
                if not self.isActivated():
                        self.getCy().setImprovementType(eCaravan)
                        self.setActivated()

        def deleteCaravan(self):
                if not self.isActivated() and self.isCaravan():
                        self.getCy().setImprovementType(-1)

        def isCaravan(self):
                return self.getCy().getImprovementType() == eCaravan
I mostly opted for the Object-Oriented approach for kicks, but it will also enable me to write some additional features for the new Caravan improvements later. :D

I'm using scriptData to store pickled data (arrays of CityDesert instances, to be exact), by the way. I trust that no other Python code in the mod uses the CyGame and CyCity objects for this... :p (Because then there would be a conflict. :eek2:)
 
I thought I'd have some fun with this, so I wrote a spanking new code for the Arabian power. (It may end up in a module of its own.) Unfortunately I might not have any time to test any of it before the weekend, but I though I'd share with you the new CityDesert class:
Spoiler :
Code:
class CityDesert:

        desertPlotDict = initPlotDict()

        def __init__(self, iPlot):
                self.ID = iPlot
                self.iX = Map.plotX(iPLot)
                self.iY = Map.plotY(iPlot)
                self.bActivated = False

        def getID(self):
                return self.ID

        def getCy(self):
                return Map.plotByIndex(self.ID)

        def getCoords(self):
                return (self.iX, self.iY)

        def getOwner(self):
                return self.getCy().getOwner()

        def checkOwner(self):
                return isCivPlayer("Arabia", self.getOwner())

        def isOwned(self):
                return self.checkOwner() != None

        def isActived(self):
                return self.bActivated

        def setActivated(self):
                self.bActivated = True

        def addCaravan(self):
                if not self.isActivated():
                        self.getCy().setImprovementType(eCaravan)
                        self.setActivated()

        def deleteCaravan(self):
                if not self.isActivated() and self.isCaravan():
                        self.getCy().setImprovementType(-1)

        def isCaravan(self):
                return self.getCy().getImprovementType() == eCaravan
I mostly opted for the Object-Oriented approach for kicks, but it will also enable me to write some additional features for the new Caravan improvements later. :D

I'm using scriptData to store pickled data (arrays of CityDesert instances, to be exact), by the way. I trust that no other Python code in the mod uses the CyGame and CyCity objects for this... :p (Because then there would be a conflict. :eek2:)

I don't think so, I think it's good. Sorry to disappear but had a huge project that was due today, and now that it's done Friday and Saturday should be good days to get back to modding.
 
I've been mad busy too, but I would have some results for you over the weekend. :)
 
Okay, some updates:

first, i figured out how to make the Sumerian original power work, you just make their Unique Tech do the "ignoreimmigration" function, like Biology. Voila, the Sumerians can now build a farm in all of their land, which is the effect I wanted.

Also I'm not going to worry about the adopting civic early, because that doesn't feel like a lasting special power. Also, I found something better. Angkor Wat in the game changes your specialist yields for priests, and I realized I can do that for any civ with every specialist, so Korean Scientists will produce extra beakers, Chinese Spies will produce extra espionage, etc. I'm going to go through the list and come up with new ideas to better balance the civs.

Finally, looked at the API a little but it was a quick glance and I didn't understand much. I'll review it and see if I can learn something useful.
 
Finally, looked at the API a little but it was a quick glance and I didn't understand much. I'll review it and see if I can learn something useful.
CivIV employs classes as templates for various game objects. Like Civs, cities, units and so on. This is also why the API is organized in classes. What you need is the highlighted classes that start with Cy. Like CyPlayer, which contains all the methods available for Python modding affecting the various players in the game.

Now, something to realize about functions (and class methods) is that they always return (or yield) something. As the Python API reflects the C++ code in the SDK there is a category of methods that return "VOID" - basically a default None value. These are actually the useful ones, because all the other methods are used for fetching information about game objects. The VOID methods actually change the objects themselves! :eek2:

So basically what you can do is look through some of the classes like CyPlayer, CyTeam and CyCity and see what VOID methods are there. Once you find something interesting you could try to figure out a unique power around that. Like CyPlayer.changeCoastalTradeRoutes(), CyTeam.changeImprovementYieldChange() or CyCity.setBuildingHappyChange(). Albeit limited in its scope the API should spark an endless array of unique power ideas...

edit: I sent you the updated code complete with Scandinavian, Incan, Persian and Arab powers.
 
In case anyone wants to see where we are right now:
Spoiler :
PHP:
### Unique powers for Glory and Greatness mod, by Baldyr

from GGUtils import *
from GGCaravan import *

### constants

#iMoveDenominator = gc.getDefineINT("MOVE_DENOMINATOR")
setupDesertMap()

# settings

iMayanProbability = 25
iNetherlandsInterest = 3
iJapaneseProbability = 20
tIncanEras = (False, True, False, True, False, True, False)
iGermanProbability = 50
iGermanGold = 50
iOttomanProbability = 50
iOttomanGold = 50
iOttomanCulture = 100
tPersianDomains = (True, False, True, False) # land and sea only
iPersianMoves = 1

# eNums

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

### main functions - called from CvEventManager

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

def germany(pWinningUnit, pLosingUnit):
        """
        50 percent chance to capture barbarian units and get gold reward.
        """
        ePlayer = pWinningUnit.getOwner()
        if ( isCivPlayer("Germany", ePlayer)
             and pLosingUnit.getDomainType() == eLand
             and pLosingUnit.getOwner() == eBarbarian
             and isProbabilityPercent(iGermanProbability, "germany") ):
                captureUnit(ePlayer, pWinningUnit, pLosingUnit)
                grantGold(ePlayer, iGermanGold)

def inca(eTech, ePlayer):
        """
        Free Tech on reaching Classical, Renaissance and Modern Eras.
        """
        if not isCivPlayer("Inca", ePlayer): return
        player = tPlayer[ePlayer]
        player.getData()
        lIncanEras = player.data
        if not lIncanEras:
                lIncanEras = list(tIncanEras)
        eTechEra = gc.getTechInfo(eTech).getEra()
        ePlayerEra = player.CyPlayer.getCurrentEra()
        if lIncanEras[eTechEra] == True:
                lIncanEras[eTechEra] = None
        elif lIncanEras[ePlayerEra] == None:
                player.CyTeam.setHasTech(eTech, True, ePlayer, False, True)
                lIncanEras[ePlayerEra] = False
        player.storeData(lIncanEras)

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

def maya(pWinningUnit, pLosingUnit, ePlayer):
        """
        Enslave - 25 percent chance to get a Worker unit any time a land unit is defeated in combat.
        """
        if ( isCivPlayer("Maya", ePlayer)
             and pLosingUnit.getDomainType() == eLand
             and isProbabilityPercent(iMayanProbability, "maya")
             and pLosingUnit.getUnitType() >= eWarrior ):
                spawnUnit(ePlayer, pWinningUnit.getX(), pWinningUnit.getY())

def netherlands():
        """
        Receive 3 percent interest on gold reserves each game turn (rounded down).
        """
        for pPlayer in list(player.CyPlayer for player in getCivPlayers("Netherlands")):
                if not pPlayer.isAlive(): return
                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("Ottoman", args[1]):
                if isinstance(args[0], CyUnit):
                        ottomanCapture(*args)
                else:
                        ottomanCulture(*args)

def ottomanCapture(pWinningUnit, ePlayer, pLosingUnit):
        """
        5O percent chance to capture enemy ships and earn gold.
        """
        if pLosingUnit.getDomainType() == eSea and isProbabilityPercent(iOttomanProbability, "ottoman"):
                captureUnit(ePlayer, pWinningUnit, pLosingUnit)
                grantGold(ePlayer, iOttomanGold)

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

def persia(ePlayer):
        """
        All land and sea units gain one extra movement point during Golden Ages.
        """
        if not isCivPlayer("Persia", ePlayer): return
        iExtraMoves = iPersianMoves
        if not tPlayer[ePlayer].CyPlayer.isGoldenAge():
                iExtraMoves = - iExtraMoves
        for eDomain in range(DomainTypes.NUM_DOMAIN_TYPES):
                if tPersianDomains[eDomain]:
                        tPlayer[ePlayer].CyTeam.changeExtraMoves(eDomain, iExtraMoves)

def russia(pUnit, pPlot):
        """
        Enemy units in Russian territory take damage when either moving or fighting.
        """
        eUnitOwner, ePlotOwner = pUnit.getOwner(), pPlot.getOwner()
        if ( isCivPlayerAlive("Russia")
             and not eUnitOwner == ePlotOwner
             and isCivPlayer("Russia", ePlotOwner)
             and isAtWar(ePlotOwner, eUnitOwner) ):
                if pUnit.movesLeft() == 0:
                        pUnit.changeDamage(5, eBarbarian)

def scandinavia(pUnit):
        """
        Double Gold from pillaging.
        """
        return isCivPlayer("Scandinavia", pUnit.getOwner()) + 1

### assorted functions

def captureUnit(ePlayer, pWinningUnit, pLosingUnit):
        """
        Spawns a unit of the pLosingUnit type on the map tile of the pWinningUnit for ePlayer.
        """
        spawnUnit(ePlayer, pWinningUnit.getX(), pWinningUnit.getY(), pLosingUnit.getUnitType())
                            
def grantGold(ePlayer, iChange):
        """
        Grants iChange gold to ePlayer.
        """
        tPlayer[ePlayer].CyPlayer.changeGold(iChange)

def spawnUnit(ePlayer, iX, iY, eType=eWorker, iNum=1):
        """
        Spawn iNum units of the eType at the coordinates iX and iY for the ePlayer.
        """
        tPlayer[ePlayer].PyPlayer.initUnit(eType, iX, iY, iNum)
(The Arabian power is in a module of its own.)
 
2 Questions Baldyr:

Can you adjust training times of certain units in Python? Like say the Celts can train either Mounted Units, Melee, Ranged, Gun, with less cost in hammers than other civs? If so that could fill a gap in Unique Civ powers.

I'm toying with an idea of adding buildings to the game that take a raw resource and refine it into its productive state. Like Iron on the map would be changed to read as "Ore" and you would need a Forge to turn Ore into Iron to train Swordsmen. Than having a UU that doesn't require a resource is suddenly more valuable. It can all be done in XML (like corporations work like Standard Ethanol). My question: Do you think that's a good gameplay mechanic or unnecessary. I don't want the mod to introduce a lot of junk for junk's sake, but in my head this sounds like it could be a fun dynamic.

For example, Nuclear Plants could enrich Uranium, A Winery Building could turn grapes into Wine, a Refinery turns Oil into Fuel, etc.
 
Back
Top Bottom