4. Guide to Python in Civ IV: Python In Civ IV

There are other ways to simplify the calling of certain classes and functions. One way is through aliasing a function call, especially to certain complex calls. In CIV you will often have object/class calls that go 4 or 5 or more objects deep, and typing "CyGlobalContext().getPlayer(1).getUnit(0).getDamage()" over and over again gets tedius - fast. But there is a solution. You can substitute part of this string with a simpler call if you so choose. You can make it as simple as you want. For example, you can assign the previous call to a single term - "Damage". To do this you simply say "Damage = CyGlobalContext().getPlayer(1).getUnit(0).getDamage()". Every time you say "Damage" thereafter it will make that entire long reference call. Note what I said about object references a while back. Python doesn't actually assign the value of that term to "Damage", but it tells the program that variable "Damage" to POINT to the value of that long term. Again, this may not be significant for those who aren't familiar with reference calls and OOP, but for those who are, the differences between this and normal assignment is pretty obvious.

While the value of that long term is equal to an integer value (the damage of that particuar) unit, you can assign simpler names to object and class calls as well. For example, you can assign the unit object (CyGlobalContext().getPlayer(1).getUnit(0)) to "Unit" through "Unit = CyGlobalContext().getPlayer(1).getUnit(0)". You can then do things like "Unit.getDamage()" or "Unit.getName()" or other functions that the unit class/object possesses. You can also use a combination of these terms to cover a wider variety of things.

For example, this is something I like to do a lot in the Python console in games just to make things easier to work with:

gc = CyGlobalContext()
Player = gc.getPlayer(1)
Unit = Player.getUnit(0)
Damage = Unit.getDamage()

This does the exact thing as above, only it also allows me to use GC, Player and Unit independently of the single "Damage" I had above. With the above code I could now do something simple like "Unit.getName()" and it will give me the name of that unit - rather than having to to use CyGlobalContext().getPlayer(1).getUnit(0).getName(). Quite a bit of the CIV code does things along these lines, and if you take a look you'll see there's usually a gc (CyGlobalContext) in most every file. After getting some experience using them, it's quite useful in cutting down on all the stuff you have to read and type. However, it can be kind of tricky to keep track of all that's being done, and a lot may look alien at first.

Here's an example of a wrapper class (Player.py in the py folder) that Jesse wrote. As he and Gramps explained elsewhere the wrapper grabs the big long code and puts it into smaller and more manageable sections.

gc = CyGlobalContext()

class PyPlayer:
    "CyPlayer Helper Functions - Requires Player ID to initialize instance"
    def __init__(self, playerID):
        " Called whenever a new PyPlayer instance is created "
        self.ID = playerID
        self.player = gc.getPlayer(self.ID)

    def isNone(self):
        "boolean - Is the CyPlayer Instance Valid?"
        return self.player.isNone()

Here you can see "gc" takes the place of "CyGlobalContext()" and Jesse creates the PyPlayer class. The class inputs a single argument, the Player's ID. On the initialization of the class, the player's ID is stored in an instance variable ID (accessed in the class through "self.ID") and the actual player OBJECT is stored in self.player by using a GlobalContext function that grabs a player based upon what ID you feed it.

The isNone() function then takes the self.player object and returns whether or not the player is valid (exists) through Player.isNone(), a function in the Player object.

To call this class you would first import the Player file, then call the class and its functions. To call the isNone() function above you would use the command "Player.PyPlayer(0).isNone()" - where Player is the imported file, PyPlayer(0) is the wrapper class from above and its single input argument, and isNone() is the function that is being requested. It could be done the same way by the command: "CyGlobalContext().getPlayer(0).isNone()", it's just that the first is shorter, which is why Jesse wrote the wrapper classes to begin with. ;)


1. Guide to Python in Civ IV: Introduction
2. Guide to Python in Civ IV: Basic Python
3. Guide to Python in Civ IV: Classes in Python
4. Guide to Python in Civ IV: Python in Civ IV
5. Guide to Python in Civ IV: Iteration (Looping)
6. Guide to Python in Civ IV: Civ IV Function Assignment
7. Guide to Python in Civ IV: Creating a Unit in Civ IV
8. Guide to Python in CIV: Class Reference (by Locutus)
9. Further Class Reference (by Solver)

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License