Glory and Greatness, Development Thread

seasnake

Conquistador
Joined
Apr 21, 2006
Messages
1,892
Location
California, United States
This is Glory and Greatness, the development thread for the mod. Seasnake and Baldyr are the authors, I'm handling XML and Artwork and Baldyr is handling Python.

Glory and Greatness has one simple goal, to be a really awesome version of the Civ IV BTS. This has gone through a few concepts, but thanks to awesome support from Baldyr, it currently looks like this: 40 civs with one leader only, each civ will have 1-2 UBs and 2-3 UUs, with a variety of civ-specific unique abilities. The 40 civs include the base 34 and the Iroquois (Native America is changed to Sioux), Gran Colombia, Israel, Songhai, Siam, and Polynesia.

This mod uses Blue Marble and Chuggi's Improved Leaders, and a modified version of GeoModder's Ethnic Citystyles and Varietas Delectat. There are also several small changes for balance sake/fun (E.G. spies now move two and Bureaucracy allows for unlimited Spy Specialists).

First thing's first, we're working on the Unique Civ Abilities. The following list is the first vision for how each civ could be different. What Baldyr and I are asking for, dear readers, is for people who are in the know to weigh in on this list. We need to talk about how we can accomplish these ideas, if they are good ideas to begin with, suggestions for better abilities, discussions on balance, etc. Forum feedback will be, we hope, a huge reason Glory and Greatness will truly be an excellent mod for an excellent game.

UPDATED 12/13/2010

America: We the People
Settlers start with Sentry and Morale -- XML
+1 Hammer from Town, Village -- XML
+1 Free Specialist per city -- XML

Arabia: The Caravan Road
+2 Food, +1 Gold from Desert -- Python/DLL
Mounted Units start with Hit and Fade (New promotion) -- XML
Merchants produce extra gold -- XML UPDATE 12/13

Aztec: The Triple Alliance
Gold for units killed based on experience of unit -- Python
Start Game with Source of Gems – XML
Double production of Barracks, Arsenal, Manufactuary -- XML

Babylon: The Code of Hammurabi
- 50 percent War Weariness -- XML
+ 50 percent Courthouse, Jail, Walls – XML
+ Start with 2 Sources of Silk

Byzantium: The Center of the World
Bonus Happiness in City -- XML
Citizens provide 1 extra hammer -- XML
- 20 percent time to train Gunpowder Units – DLL/Python

Carthage: The Shining City
+1 Gold from plots with 2 Gold -- XML
Double Production of Markets, Banks -- XML
Stronger Vassals -- Python

Celts: The Emerald Isle
- 20 percent time to train melee -- Python/DLL
Source of Bronze to Start -- XML
Can adopt Hereditary Rule to start the game -- Python/DLL

China: Art of War
+100 Percent Great General Appearance -- XML
+2 Culture Per Specialist -- XML
Can adopt Bureaucracy at the Start of the Game -- Python/Dll

Egypt: Children of the Nile
-33 percent cost for wonders -- XML
+1 food per farm -- XML
Start game with Pottery -- XML

England: The Sun Never Sets
Workshops +1 gold, +1 Hammer -- XML
Happiness from Monument, Radio Tower, Customs House -- XML
+1 Movement to Ships – Python/DLL

Ethiopia: The Dear Motherland
Workers build improvements 25 percent faster -- XML
Start with Dye -- XML
No Anarchy -- XML

France: Ancien Regime
+3 culture per city XML
Start with Wine XML
+ 10 percent combat bonus when fighting in enemy territory -- PYTHON/DLL

Gran Colombia: Live Free or Die
No Revolting in captured cities -- PYTHON
Pastures produce extra food and gold -- XML
-25 Experience needed for promotion -- XML

Germany: Furor Teutonics BUT DRAFTING
No Unahppiness for Drafting -- PYTHON
Tiles with four hammers earn one extra -- XML
50 percent chance on combat with Barbarians of capturing the unit and earning 25 gold -- PYTHON

Greece: Hellenic League
Can form defensive pacts to start the game -- XML
Scientist specialists add culture -- XML
+50 percent Great Person Points -- XML

Holy Roman Empire:
Start game with Great General -- XML
+ 100 percent Settler, Worker Production -- XML
Free Tech in the Classical and Renaissance Eras -- PYTHON UPDATE 12/13

Inca: The World Shakers
Start with Stone -- XML
+1 Food from Hill Terrain -- PYTHON
+25 percent science -- XML

India: Satyagraha
Cities Start with 2 population -- PYTHON
Extra food on city growth -- PYTHON
Can adopt Pacifism at start of game -- PYTHON/DLL

Iroquois: People of the Longhouse
Extra health in city -- XML
+1 Food from Forest – PYTHON/XML?
+10 percent bonus to combat when fighting within own borders -- PYTHON/DLL

Israel: The Chosen People
+50 City Defense -- XML
+50 precent Espionage Production -- XML
Start Game with Great Prophet -- XML

Japan: Bushido
20 percent chance for a unit to fully heal after combat victory -- PYTHON
Units killed in borders add to city culture -- PYTHON
Discount to Gold Rushing -- XML

Khmer: The Gold Kingdom
No Unhappiness in Capital -- XML
Source of Ivory -- XML
Can chop Forest/Jungle to start game -- XML

Korea: Land of the Morning Calm
Extra Research from Scientist Specialist in Each City -- XML
Start Game with Caste System Unlocked -- XML
Barbarians cannot enter cultural borders -- XML

Mali: Reign of the Mansas
Mines +1 Gold -- XML
Double Production of Temples, Monasteries, Cathedrals -- XML
Can Select a Free Technology to start the game -- PYTHON

Maya: Kingdom of the Maize God
25 percent chance to enslave enemy units (get worker) -- PYTHON
World Map Centered – XML
Double Production of Observatory, Monument, Granary -- XML

Mongol: Empire of the Horde
Start with Source of Horse -- XML
Flank 1, Sentry promotions for horse units -- XML
- 50 percent city maintenance costs -- XML

Netherlands: The Merchant Republic
3 percent interest on gold reserves -- PYTHON
+ 100 Percent Gold from Trade Routes -- XML
Bonus production from Windmills -- XML

Ottomans: The Eternal State
Chance to capture enemy ships -- PYTHON
Siege Units start with Bombard, Collateral -- XML
Culture quick spread when capturing enemy cities -- PYTHON

Persia: Achaemenid Legacy
+100 GA length -- PYTHON
+1 movement for all units during a golden age -- PYTHON
Can have Vassals all game -- XML

Polynesia: Breath of Life
Extra hammer on Sea Tiles -- XML
Units don’t’ require open borders agreement – DLL
Priest specialists grant +1 experience to units trained in the city -- PYTHON

Portugal: Colonial Aspirations
Start game with Sailing -- XML
1 Extra Trade Route per city -- XML
Can train Naval Units in 20 percent less time -- PYTHON

Rome: The Glory of Rome
+25 percent production of buildings already built in the capital – PYTHON/DLL
Extra Movement on Roads -- XML
- 50 percent cost to upgrade units -- PYTHON

Russia: Mother Russia
Enemy units take damage when moving or attacking in Russian Cultural Borders – PYTHON
Spies produce extra espionage – XML
Armored Units have Combat 1, Drill 1 -- XML

Siam: Father Governs Children
Bonus Science and Hammers from trade routes -- XML
Start Game with source of Gold -- XML
Double production of Library, University, Theater -- XML
UU: Royal Elephant, Elephant Bombard
UB: Wat, Ho Trai

Sioux: People of the Plains
Mounted Units – 20 percent cost to train -- PYTHON
No Unhealthiness in Capital – XML
Units can heal in Enemy Territory -- PYTHON

Songhai: The River Warlord
Melee units start with Amphibious -- XML
Start game with Animal Husbandry -- XML
+ 100 percent War Weariness for enemies -- XML

Spain: The Golden Age
Extra gold from water tiles -- XML
Double Production of Spies, Missionaries, Explorers, Scouts -- XML
Extra Gold from Goody Huts -- PYTHON

Sumeria: Cradle of Civilization
Start with 2 Settlers -- XML
Can build farms anywhere -- XML
City Defender, Combat 1 for Melee, Archer, Gunpowder units -- XML

Vikings: Wrath of the Norsemen
Double Income from Pillage, no Pillage within borders -- PYTHON
All melee units have survival, city raider promotions – XML
Double production of Lighthouse, Harbor, Customs House -- XML

Zulu: Horns of the Bull
Can Upgrade outside borders -- PYTHON
Melee Units have extra movement – XML
Free Granary in every city -- XML

To clarify: Each civ has a unique Palace and a Unique Tech it starts the game with. So abilities can be based on their unique palace like a great wonder, or on tech (like the Mayans having the world centered).

NOTES: Arsenal and Manufactuary are new buildings necessary to train certain units, Manufactuary for Artillery and Tanks, Arsenal for Cannons and Ships of the line, etc. Hit and Fade is Tsentom's skirmisher promotion, renamed to "Hit and Fade" because I hate that in the civpedia you click on the promotion and get the Malinese UU. I've done my best to choose evocative names for abilities, but I'm aware that it doesn't always correlate too well with ability. Suggestions appreciated.
 
A very good and concise index! :goodjob: But maybe put the list of abilities into spoiler tags?

I'll get to analyzing this stuff once I get the chance. Right now my hands are pretty full.

To clarify: Each civ has a unique Palace and a Unique Tech it starts the game with. So abilities can be based on their unique palace like a great wonder, or on tech (like the Mayans having the world centered).
Just to clarify: I don't think we need to use the unique Palaces or Techs for triggering/enabling any Python code. Because I already wrote a helper function for identifying the Civs. But I guess those are still needed for some XML based effects, so I won't complain any further about this. :p

And yes, I do think this will be a bang-up mod! :king: All design credit belongs to you however - I'm just the code monkey. :lol:
 
Ok, these are my preliminary verdicts on the abilities not doable in with XML settings:
+2 Food, +1 Gold from Desert
If we use the custom DLL released by Asaf, then this is possible to do with CyPlayer.setExtraTerrainYield().
Gold for units killed based on experience of unit
This would be possible to do with the unitKilled event callback.
+ Start with 2 Sources of Silk
You mean like bonuses on the map, somewhere in the vicinity of the starting location? :confused: It should be possible to do on the GameStart event callback.
Spoiler :
We need to define what plots types are priority though, so that we get reasonable results. Also how far away from the starting location those tiles can be located. (It would probably be fun to create a code that firstly looks for suitable tiles within the BFC of the capital to be. But if none are found, then increase the search area in layers until such plots are found.)

- 20 percent time to train Gunpowder Units
- 20 percent time to train melee
Can train Naval Units in 20 percent less time
Mounted Units – 20 percent cost to train
These should be possible to do with the getUnitCostMod callback (CvGameUtils) but enabling the callback will in itself cause some lag, because the code will be evaluated every single time the game checks for units costs...
Stronger Vassals
Meaning, for example? :confused:
Can adopt Hereditary Rule to start the game
Can adopt Bureaucracy at the Start of the Game
Can adopt Pacifism at start of game
I've done this before with the canDoCivic callback (CvGameUtils) - adds lag (but then again does all Python).
+1 Movement to Ships
This can be done with CyTeam.changeExtraMoves()
+ 10 percent combat bonus when fighting in enemy territory
This one I'm not sure how to implement. It wouldn't be reasonable to check all units every turn to see whether or not they are on unfriendly ground and give them a temporary combat boost. Perhaps something can be added to the SDK to enable this as a XML tag (somewhere) - or to expose some SDK function to Python. Any ideas, anyone?
No Revolting in captured cities
This one I already did.
Spoiler :
Code:
def colombia(pCity, ePlayer, bConquest):
        """
        No Revolting in Captured cities.
        """
        if bConquest and isCivPlayer("Gran Colombia", ePlayer):
                pCity.setOccupationTimer(0)
No Unahppiness for Drafting
While it seems possible to affect the unhappiness from drafting with CyCity.changeConscriptAngerTimer() it would be rather cumbersome to constantly check all cities with CyCity.getConscriptAngerTimer(). The problem being the lack of a game event that creates a call to Python on conscription.

Any ideas? (Making a new XML tag would probably be an option.)
50 percent chance on combat with Barbarians of capturing the unit and earning 25 gold
Did it already.
Spoiler :
Code:
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)
Free Tech in the Classical and Renaissance Eras
Also done.
Spoiler :
Code:
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)
Cities Start with 2 population
Very doable on the cityBuilt event callback.
Extra food on city growth
It should be possible to intersect the game on the cityGrowth event and add the food with CyCity.changeFood().
Code:
+1 Food from Forest
I have no real idea on this. It seems straight forward enough, but there doesn't seem to be anything in the SDK either. So it would probably require something new being added to the SDK.
20 percent chance for a unit to fully heal after combat victory
Done.
Spoiler :
Code:
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)
Units killed in borders add to city culture
Adding culture point to map plots would be more straight forward than to figure out what city should get it. Its Japanese units dying within own borders, then? :confused:
Can Select a Free Technology to start the game
As described in another thread, this is very doable with CyPlayer.chooseTech(). But it really only works for the human player, so a Mali AI would need something else to get the job done. Adding CyPlayer.AI_chooseFreeTech() to the Python API would do the trick, but is not entirely necessary.
25 percent chance to enslave enemy units (get worker)
Yep.
Spoiler :
Code:
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())
3 percent interest on gold reserves
Indeed.
Spoiler :
Code:
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)))
Chance to capture enemy ships
Spoiler :
Code:
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)
Culture quick spread when capturing enemy cities
Spoiler :
Code:
def ottomanCulture(pCity, ePlayer, bConquest):
        """
        Spread culture in conquered cities.
        """
        if bConquest:
                pCity.changeCulture(ePlayer, iOttomanCulture, True)
+100 GA length
Should be possible to do with the goldenAge event callback.
+1 movement for all units during a golden age
Spoiler :
Code:
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)
Priest specialists grant +1 experience to units trained in the city
Should be possible to do on the unitCreated event callback.
+25 percent production of buildings already built in the capital
Should be possible with the getBuildingCostMod callback (CvGameUtils) but would cause lag.
- 50 percent cost to upgrade units
I'm guessing getUpgradePriceOverride (CvGameUtils).
Enemy units take damage when moving or attacking in Russian Cultural Borders
Spoiler :
Code:
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)
Units can heal in Enemy Territory
Might be possible but I'm not seeing any clear-cut Python implementations at the moment. Could get rather messy in any case.
Extra Gold from Goody Huts
The goodyReceived event callback.
Double Income from Pillage, no Pillage within borders
While I already did this the latter part needs to be implemented.
Can Upgrade outside borders
canUpgradeAnywhere callback in CvGameUtils?

All of the above could of course be done with some SDK hack or another. If someone wants to do all these in C++ then that would cause less lag. :p
 
I thought I might as well reveal what code is already done for this mod. This is the GGUtils module:
Spoiler :
PHP:
### Helper functions and assorted classes for the Glory and Greatness mod, by Baldyr

from CvPythonExtensions import *
import cPickle as pickle
import PyHelpers

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

### helper functions

def getAdjacentTiles(iX, iY):
        """
        Used for looping - yields a pair of x and y coordinates (integers) at a time
        corresponding to all adjacent map tiles.
        """
        for x in range(iX - 1, iX + 2):
                for y in range(iY - 1, iY + 2):
                        if x != iX and y != iY:
                                yield x, y
                                
def getBFC(iX, iY):
        """
        Used for looping - yields one valid city radius plot index value (integer) at a
        time.
        """
        for x in range(iX - 2, iX + 3):
                for y in range(iY - 2, iY + 3):
                        if Map.plot(x, y).isCityRadius() or not Map.plot(iX, iY).isCity():
                                yield Map.plotNum(x, y)

def getCivPlayers(name):
        """
        Used for looping - yields one CivPlayer class instance at a time.
        """
        for player in players.get(name, []):
                yield player

def getCombatType(pUnit):
        """
        Returns the UnitCombatTypes enumerated value (integer) for pUnit.
        """
        return gc.getUnitInfo(pUnit.getUnitType()).getUnitCombatType()

def getIndex(category, entry):
        """
        Returns the enumerated index value (integer) of the specified entry belonging to
        the specified category, as specified by the XML.
        """
        key = category + "_" + entry.replace(" ", "_")
        return gc.getInfoTypeForString(key.upper())

def isAtWar(ePlayer, eRival):
        """
        Returns True if ePlayer's team is at war with eRival's team.
        """
        return tPlayer[ePlayer].CyTeam.isAtWar(tPlayer[eRival].team)

def isCivPlayer(name, ePlayer):
        """
        Returns True if the player corresponding to the ePlayer argument is present in
        the list of CivPlayer class instances.
        """
        for eCurrent in list(player.ID for player in getCivPlayers(name)):
                if ePlayer == eCurrent:
                        return True
        return False

def isCivPlayerAlive(name):
        """
        Returns True if any of the players supplied with the list of CivPlayer class
        instances is alive.
        """
        for pPlayer in list(player.CyPlayer for player in getCivPlayers(name)):
                if pPlayer.isAlive():
                        return True
        return False

def isCivPlayerCulture(name, pPlot):
        """
        Returns True if pPlot has culture by any player with the name civilization
        attribute.
        """
        for ePlayer in list(player.ID for player in getCivPlayers(name)):
                if pPlot.isWithinCultureRange(ePlayer):
                        return True
        return False

def isCivPlayerOwned(name, pPlot):
        """
        Returns True if pPlot is owned by any player with the name civilization attribute.
        """
        for ePlayer in list(player.ID for player in getCivPlayers(name)):
                if pPlot.getOwner() == ePlayer:
                        return True
        return False

def isHasMet(name, pTeam):
        """
        Returns True if pTeam has met any member of a team with the name civilization
        attribute.
        """
        for eTeam in list(player.team for player in getCivPlayers(name)):
                if pTeam.isHasMet(eTeam):
                        return True
        return False

def isProbabilityPercent(iPercent, debug=""):
        """
        Returns True in iPercent cases out of 100. The debug message argument is optional.
        """
        return Game.getSorenRandNum(100, debug) < iPercent

class CivPlayer:

        """
        Each instance contains references to IDs and various class instances associated
        with the player corresponding to the ePlayer argument.
        """
        
        def __init__(self, ePlayer):
                self.ID = ePlayer
                self.CyPlayer = gc.getPlayer(ePlayer)
                self.civilization = self.CyPlayer.getCivilizationType()
                self.team = self.CyPlayer.getTeam()
                self.CyTeam = gc.getTeam(self.team)
                self.PyPlayer = PyHelpers.PyPlayer(ePlayer)
                self.data = self.getData()

        def getScriptData(self):
                return self.CyPlayer.getScriptData()

        def getData(self):
                scriptData = self.getScriptData()
                if scriptData:
                        self.data = pickle.loads(scriptData)
                else:
                        self.data = None

        def setScriptData(self):
                self.CyPlayer.setScriptData(pickle.dumps(self.data))

        def setData(self, data):
                self.data = data

        def storeData(self, data):
                self.setData(data)
                self.setScriptData()

# sets up player arrays

lPlayers = range(Game.countCivPlayersEverAlive())
tCivilizations = ("Holy Rome", "Byzantium", "Portugal", "Celt", "Arabia", "Gran Colombia", "Germany", "Inca", "Japan", "Maya", "Netherlands", "Ottoman", "Persia", "Russia", "Scandinavia")
players, lSorted = dict(), list()
tPlayer = tuple(CivPlayer(ePlayer) for ePlayer in lPlayers)
for name in tCivilizations:
        for player in list(tPlayer[ePlayer] for ePlayer in lPlayers):
                if player.civilization == getIndex("Civilization", name) and not player in lSorted:
                        lSorted.append(player)
                        if name in players:
                                players[name].append(player)
                        else:
                                players[name] = [player]
 
This would be possible to do with the unitKilled event callback.

i have a mod that does this, it's the Salvager Trait. The Mod changes the CvEventManager thus:

Spoiler :

def onCombatResult(self, argsList):
'Combat Result'
pWinner,pLoser = argsList
playerX = PyPlayer(pWinner.getOwner())
unitX = PyInfo.UnitInfo(pWinner.getUnitType())
playerY = PyPlayer(pLoser.getOwner())
unitY = PyInfo.UnitInfo(pLoser.getUnitType())

###Salvager Trait START###

iTrait = gc.getInfoTypeForString("TRAIT_SALVAGER")
iWinner = gc.getPlayer(pWinner.getOwner())
if (iWinner.hasTrait(iTrait)):
cost = unitY.getProductionCost()
gold = cost/15
playerX.changeGold(gold)

###Salvager Trait END###



You mean like bonuses on the map, somewhere in the vicinity of the starting location? It should be possible to do on the GameStart event callback.

no, I just mean in the XML for the Babylon palace I'll type give it BONUS_SILK under the free bonus line and give 2 types. Sort of like how Hollywood does hit movies.

Meaning, for example?

Tsentom (may his name be praised in song) scripted that out in Python, again in the event manager. It's from his Influential Trait:

Spoiler :

def onBeginPlayerTurn(self, argsList):
'Called at the beginning of a players turn'
iGameTurn, iPlayer = argsList

## Inf Trait Start ##

pPlayer = gc.getPlayer(iPlayer)
iTeam = pPlayer.getTeam()
pTeam = gc.getTeam(iTeam)
iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_CARTHAGE')

if (pPlayer.hasTrait(iTrait)):

for iPlayer in range(gc.getMAX_PLAYERS()):
ppPlayer = gc.getPlayer(iPlayer)
if ( (ppPlayer.isAlive()==true) and (ppPlayer.isBarbarian()==false) ):
if ( gc.getTeam(ppPlayer.getTeam()).isVassal(iTeam) == true ):
iGold = ppPlayer.getGold( )
if ppPlayer.getGold( ) >= 5000:
ppPlayer.changeGold( 50 )
if ppPlayer.getGold( ) < 5000:
if ppPlayer.getGold( ) >= 50:
ppPlayer.changeGold( iGold//50 )
else:
ppPlayer.changeGold( 1 )

ppPlayer.changeCombatExperience( +1 )

## Inf Trait End ##

def onEndPlayerTurn(self, argsList):
'Called at the end of a players turn'
iGameTurn, iPlayer = argsList



While it seems possible to affect the unhappiness from drafting with CyCity.changeConscriptAngerTimer() it would be rather cumbersome to constantly check all cities with CyCity.getConscriptAngerTimer(). The problem being the lack of a game event that creates a call to Python on conscription.

Here is from the Nationalist trait, again (i merged a lot of Mods into my last mod, Rise of Empires). It works pretty well, but maybe you know something more elegant.

Spoiler :

def onModNetMessage(self, argsList):
'Called whenever CyMessageControl().sendModNetMessage() is called - this is all for you modders!'

iData1, iData2, iData3, iData4, iData5 = argsList

## Nationalist code start

if(iData1 == 1): ## Change Conscript Angry Time
pPlayer = gc.getPlayer(iData2)
pCity = pPlayer.getCity(iData3)
pCity.changeConscriptAngerTimer(iData4)

## Nationalist code end

print("Modder's net message!")

CvUtil.pyPrint( 'onModNetMessage' )

...

## Nationalist code start

player = gc.getPlayer(iPlayer)
iTimeLeft = pCity.getConscriptAngerTimer()

if player.hasTrait(gc.getInfoTypeForString('TRAIT_GERMAN')) and iTimeLeft > 0:
CyMessageControl().sendModNetMessage(1, iPlayer, pCity.getID(), -iTimeLeft, 0)
##pCity.changeConscriptAngerTimer(iTimeLeft * -1)

## Nationalist code end



Adding culture point to map plots would be more straight forward than to figure out what city should get it. Its Japanese units dying within own borders, then?

YUP. It's a take on Tsentom's wonder, Terracotta Army.

Spoiler :

## Terracotta Start ##

iPlayer = unit.getOwner()
pPlayer = gc.getPlayer(iPlayer)
pPID = pPlayer.getID()

b_Terra = gc.getInfoTypeForString("BUILDING_PALACE_JAPAN")
obsoleteTech = gc.getBuildingInfo(b_Terra).getObsoleteTech()

if ( gc.getTeam(pPlayer.getTeam()).isHasTech(obsoleteTech) == false or obsoleteTech == -1 ):
for iCity in range(pPlayer.getNumCities()):
ppCity = pPlayer.getCity(iCity)
if ppCity.getNumActiveBuilding(b_Terra) == true:
iX = unit.getX()
iY = unit.getY()
for iiX in range(iX-1, iX+2, 1):
for iiY in range(iY-1, iY+2, 1):
pPlot2 = CyMap().plot(iiX,iiY)
if pPlot2.isCity():
pCity = pPlot2.getPlotCity()

pPID = pPlayer.getID()
pCC = pCity.getCulture(pPID)
pCC = int( (unit.getExperience()))
pCity.changeCulture(pPID, pCC, true)

estiEnd = CyGame().getEstimateEndTurn()
if ( estiEnd >= 1000 ):
pCC2 = int(8)
pCity.changeCulture(pPID, pCC2, true)
elif ( estiEnd >= 700 ):
pCC2 = int(4)
pCity.changeCulture(pPID, pCC2, true)
elif ( estiEnd >= 400 ):
pCC2 = int(2)
pCity.changeCulture(pPID, pCC2, true)
elif ( estiEnd >= 300 ):
pCC2 = int(1)
pCity.changeCulture(pPID, pCC2, true)
elif ( estiEnd < 300 ):
pCC2 = int(1)
pCity.changeCulture(pPID, pCC2, true)

## Terracotta End ##

if (not self.__LOG_UNITKILLED):
return
CvUtil.pyPrint('Player %d Civilization %s Unit %s was killed by Player %d'
%(player.getID(), player.getCivilizationName(), PyInfo.UnitInfo(unit.getUnitType()).getDescription(), attacker.getID()))



But quite possibly there's a much easier way to do this, maybe though this will help with some of that.

I'm guessing getUpgradePriceOverride (CvGameUtils).

Tsentom's Strategic Trait has this feature, but it has one minor detail, it overrides attached great generals so that Great General units will have to pay, albeit half cost, for unit upgrades. So maybe this helps:

Spoiler :

def getUpgradePriceOverride(self, argsList):
iPlayer, iUnitID, iUnitTypeUpgrade = argsList

## Str Trait Start ##

pPlayer = gc.getPlayer(iPlayer)
pUnit = pPlayer.getUnit(iUnitID)

iPrice = gc.getDefineINT("BASE_UNIT_UPGRADE_COST")
iPrice += (max(0, (pPlayer.getUnitProductionNeeded(iUnitTypeUpgrade) - pPlayer.getUnitProductionNeeded(pUnit.getUnitType()))) * gc.getDefineINT("UNIT_UPGRADE_COST_PER_PRODUCTION"))

if ((not pPlayer.isHuman()) and (not pPlayer.isBarbarian())):
pHandicapInfo = gc.getHandicapInfo(gc.getGame().getHandicapType())
iPrice = iPrice * pHandicapInfo.getAIUnitUpgradePercent() / 100
iPrice = iPrice * max(0, ((pHandicapInfo.getAIPerEraModifier() * pPlayer.getCurrentEra()) + 100)) / 100

iPrice = iPrice - ((iPrice * pUnit.getUpgradeDiscount()) / 100)

iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_ROME')

if (pPlayer.hasTrait(iTrait)):
iPrice = ((gc.getDefineINT("BASE_UNIT_UPGRADE_COST"))/2)
iPrice += (((max(0, (pPlayer.getUnitProductionNeeded(iUnitTypeUpgrade) - pPlayer.getUnitProductionNeeded(pUnit.getUnitType()))) * gc.getDefineINT("UNIT_UPGRADE_COST_PER_PRODUCTION")))/2)

if ((not pPlayer.isHuman()) and (not pPlayer.isBarbarian())):
pHandicapInfo = gc.getHandicapInfo(gc.getGame().getHandicapType())
iPrice = ((iPrice * pHandicapInfo.getAIUnitUpgradePercent() / 100)/2)
iPrice = ((iPrice * max(0, ((pHandicapInfo.getAIPerEraModifier() * pPlayer.getCurrentEra()) + 100)) / 100)/2)

iPrice = ((iPrice - ((iPrice * pUnit.getUpgradeDiscount()) / 100))/2)

return iPrice

## Str Trait End ##




Might be possible but I'm not seeing any clear-cut Python implementations at the moment. Could get rather messy in any case.

Might be for the best then if I just made it so that units got a promotion like Medic I. No need to complicate things too much.

I've downloaded several of the Tsentom Traits and Wonders, as well as work done by other people, which is one the bases upon which I'm trying select this Unique Powers. I'm happy to e-mail you more, but it often seems you have a solution that is much cleaner.

The big one will be the forest improvement for the Iroquois, if we can't do that we'll need to come up with something else fast, that one is sort of the Iroquois bread and butter ability.

As always awesome work so far.
 
The first civ is done: America.

America now has the B-17, which replaces the bomber and combines longer range with a heavier payload. The new American Building is the Town Hall, a Courthouse replacement that gives 3 beakers to the city.

Look at the screenshots, you'll see the civpedia page, the new building and unit, the american palace (looking like the Capitol Building in DC), and the abilities in action (the free specialist and the town producing two hammers).
 

Attachments

  • Civ4ScreenShot0022.JPG
    Civ4ScreenShot0022.JPG
    187.5 KB · Views: 102
  • Civ4ScreenShot0023.JPG
    Civ4ScreenShot0023.JPG
    245.4 KB · Views: 103
  • Civ4ScreenShot0024.JPG
    Civ4ScreenShot0024.JPG
    133.3 KB · Views: 88
seasnake, could you please put all the code you posted into
Code:
 tags, because Python becomes nigh unreadable without the indentation. (Its not just for formatting the code - it actually determines what line of code belongs to the body of what statement.)

The Nationalist code seemed weird to me - I've never looked into CyMessageControl... :p What is a Mod Net Message? :confused:

edit: I think I figured out the conscription anger timer thing. The key is using the CityDoTurn event callback. So Germany is in the bag, then. :D

edit2: If I understand this correctly, the Carthaginian vassal boost should basically be +1 combat experience counted towards the next GG and some additional gold (1-50 depending on the current state of the treasury) on every turn. This is it?

edit3: The Terracotta Army wonder code only seems to be effective when the unit is adjacent to any city. So the extra culture goes to that city. Would you like to increase the range? Should this only work inside Japanese territory?
 
I have to agree with baldyr, you need to put your indentations in. I call it defining parent tags (authough I'm sure there is a much better name for it)

thought I would check this out as it came up in my own discussion thread!
 
edit: Added another method to the wish-list. The follow-up post is also updated.

We need to compile a list of SDK changes requests for Asaf's consideration. Looking at the index of all the abilities I would like these methods to be available in the Python API:
Spoiler :
CyPlayer.AI_chooseFreeTech()
CyPlayer.setExtraFeatureYield( eYieldType, iExtraYield )
CyTeam.setExtraForeignCombat( iCombatBonus )
CyTeam.setExtraDomesticCombat( iCombatBonus )
CyTeam.setUnitsCanHealInForeignTerritory( bEnable )

All but the first one might as well be made available as new XML tags - there is no benefit from running these methods on the GameStart event callback instead of loading the settings with Civ4CivilizationInfos.xml.

seasnake, you could take a look at the change log of Asaf's custom DLL for ideas for new/replacement abilities. Included are new Python methods:
Spoiler :
CyPlayer.changeCityDefenseModifier(int iChange)
CyPlayer.changeWarWearinessModifier(int iChange)
CyPlayer.changeDistanceMaintenanceModifier(int iChange)
CyPlayer.changeNumCitiesMaintenanceModifier(int iChange)
CyPlayer.setCitiesCultureStrengthModifier(int iValue)
CyPlayer.setExCitiesCultureStrengthModifier(int iValue)
CyCity.changeExtraDefense(int iChange)
 
seasnake, could you please put all the code you posted into
Code:
 tags, because Python becomes nigh unreadable without the indentation. (Its not just for formatting the code - it actually determines what line of code belongs to the body of what statement.)
[/QUOTE]

Argh!  In preview it LOOKED good.  Okay, I'll indent everything ... I'll a post when a note when that one is edited.
 
Make sure to copy-paste the code again - not to try and indent the code manually, line by line.

Also, its a good thing that you post the code you already found/used. Looking at sample code for these things makes it obvious what should - and shouldn't - be done. I'll write everything up from scratch anyway (copy-paste is not programming :p) and most of the time the code can be made to be more efficient in the process. But more than often there really is no point in re-inventing the wheel, is there? (I do however insist on fixing things, even if they aren't technically broken. :rolleyes:)
 
You realize that you need to use the
Code:
 tags, right? Because otherwise the BB will just delete all that indentation once you post the code.

edit: And you don't need to fix that post if it is causing you issues. But you should make a habit of using the code tag in the future whenever you're posting code (Python, XML or other). I think I already have what I need.
 
We need to compile a list of SDK changes requests for Asaf's consideration. Looking at the index of all the abilities I would like these methods to be available in the Python API:
Spoiler :
CyPlayer.AI_chooseFreeTech()
CyPlayer.setExtraFeatureYield( eYieldType, iExtraYield )
CyTeam.setExtraForeignTerritoryCombat( iCombatBonus )
CyTeam.setUnitsCanHealInForeignTerritory( bEnable )

All but the first one might as well be made available as new XML tags - there is no benefit from running these methods on the GameStart event callback instead of loading the settings with Civ4CivilizationInfos.xml.

I'll take a look at it some time later this week (hopefully).
I have a few things I need to do first, but I don't mind adding these to the DLL.

Can you just give a short description for each, just to make sure we're on the same page?
 
edit: Post has been rewritten.

I'll take a look at it some time later this week (hopefully).
I have a few things I need to do first, but I don't mind adding these to the DLL.
:goodjob:

Can you just give a short description for each, just to make sure we're on the same page?
CyPlayer.AI_chooseFreeTech()
This is supposedly already in the SDK (CvPlayerIA) and needs to be exposed to Python.

CyPlayer.setExtraFeatureYield( eYieldType, iExtraYield )
This should work like setExtraTerrainYield() and seExtraPlotTypeYield().

CyTeam.setExtraForeignCombat( iCombatBonus )
Should give a combat bonus to all units on unfriendly territory.

CyTeam.setExtraDomesticCombat( iCombatBonus )
Should give a combat bonus to all units in friendly territory.

CyTeam.setExtraForeignUnitHealRate( iValue )
Adds to the healing rate of units in hostile territory.

All methods might as well belong to the CyPlayer class. I just figured that some of them would be more convenient to put in CyTeam, but I really wouldn't know.
 
CyPlayer.setExtraFeatureYield() will be used to make any plot with the Forest feature yield extra food.
And food from desert for Arabia. I noticed that they also get "gold" from desert. No plot normally yields gold, since gold is not a yield type. They yield commerce, which becomes gold (or research, culture, or espionage) based on the slider settigns. If gold is what is really wanted, that could be difficult since there is no way to display it in the normal plot yield displays...
 
And food from desert for Arabia.
Nope, Desert is a TerrainType not a FeatureType, so the Arabian ability is handled with another one of Asaf's methods.

I noticed that they also get "gold" from desert. No plot normally yields gold, since gold is not a yield type. They yield commerce, which becomes gold (or research, culture, or espionage) based on the slider settigns. If gold is what is really wanted, that could be difficult since there is no way to display it in the normal plot yield displays...
I'm guessing it should read "commerce" (as in "little gold coin icon").
 
Oops. I don't know why, but I was thinking flood plains.
Aha, double-misunderstanding, then. :p (Its Flood Plains and not Desert that gives the extra yields, right?)

Then we urgently need Asaf's new DLL!
 
Scratch that. This is the Iroquois ability and it actually calls for a domestic combat bonus. So it would be something like CyTeam.setExtraDomesticCombat().

Domestic for the Iroquois, but in Enemy territory for France. Sort of duplicating the effect of the V Foreign Legion but for all troops of France.

And food from desert for Arabia. I noticed that they also get "gold" from desert. No plot normally yields gold, since gold is not a yield type. They yield commerce, which becomes gold (or research, culture, or espionage) based on the slider settigns. If gold is what is really wanted, that could be difficult since there is no way to display it in the normal plot yield displays...

Right, commerce. Sorry for the misunderstanding.
 
Top Bottom