• Civilization 7 has been announced. For more info please check the forum here .

Various call questions (Python)

phungus420

Deity
Joined
Mar 1, 2003
Messages
6,296
I have this code:
Spoiler :
Code:
            # Distance to capital City Distance modified by communication techs and structures
            cityDistModifier = ( plotDistance( pCity.getX(), pCity.getY(), capital.getX(), capital.getY()) )*0.4
            if( not pCity.isConnectedTo(capital) ) :
                cityDistModifier = (cityDistModifier + 1)*4
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLAirport)) > 0 ) :
                if( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iJetTech) ) :
                    cityDistModifier = (cityDistModifier - 6)*0.4
                else:
                    cityDistModifier = (cityDistModifier - 5)*0.6
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iRadioTech) ) :
                cityDistModifier = (cityDistModifier - 4)*0.7
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iRailRoadTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLHarbor)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 4)*0.7
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLCothon)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 4)*0.7
                else:
                    cityDistModifier = (cityDistModifier - 3)*1.2
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iAstronomyTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLHarbor)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)*1.2
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLCothon)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)*1.2
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLDLighthouse)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.7
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLTradePost)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.7
                else:
                    cityDistModifier = (cityDistModifier - 2)*2.2
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iEngineeringTech) and gc.getTeam(pPlayer.getTeam()).isHasTech(self.iHorsebackTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLHarbor)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*2.2
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLCothon)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*2.2
                else:
                    cityDistModifier = (cityDistModifier - 1)*2.5
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLHarbor)) > 0 ) :
                cityDistModifier = (cityDistModifier - 1)*2.5
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLCothon)) > 0 ) :
                cityDistModifier = (cityDistModifier - 1)*2.5
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLDLighthouse)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 1)*3
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLTradePost)) > 0 ) :
                    cityDistModifier = (cityDistModifier - 1)*3
                else:
                    cityDistModifier = cityDistModifier*3
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLDLighthouse)) > 0 ) :
                cityDistModifier = cityDistModifier*3
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDefs.sXMLTradePost)) > 0 ) :
                cityDistModifier = cityDistModifier*3
            else:
                cityDistModifier = cityDistModifier*3.6

            #cityDistModifier = adjusted for map size and normalized
            
            cityDistModifier = cityDistModifier - 1
            cityDistModifier = cityDistModifier/((( CyMap().getGridWidth()**2 + CyMap().getGridHeight()**2 )**0.5)*0.013)

Now this is the first code I've ever written. It's pretty messy, and also it's functionality isn't very expandible. It's stuck inside XML definitions, I'd like to improve it so that it can be applied to other mods, and also simplify it.

Basically instead of checking a city for various Buildings, and Checking the Civ for various techs I'd rather create a new variable: CivCommBonus which will check, and get bigger based on functions. For instance, the Minor tribes code doesn't call for the Tech Writing, it calls to see if the Civ has the ability to sign open borders, this is what I mean. The actual math and applying the new variable in a balanced way is yet to be determined, but that's not an issue. I'm good at math, hell finished derivitive Calc in way back in my high school softmore year, so I'm not worried about that part of the code.

What I need to know is how to make these specific calls:

-pCity getting +1 food on water tiles
-pCity getting %bonus to trade routes (what is the %bonus)
-pPlayer can build terrrain movement modifier feature (roads railroads): Determine that modifier
-pCity can Airlift
-pPlayer can trade over Ocean
-pCity has Culture% bonus (what is the % bonus)

As for determining the modifiers once I know the calls (terrain movement, %trade bonus, %culture) I think I can do this myself, or at lease figure it out. Mainly I need to know how to make the original call, that such things actually exist for pCity/pPlayer.
That's it, anyone know these calls? I'm pretty sure I can write the code myself no problem once I know how to make these 6 calls.
 
For changing plot-yields look at this wonder.

For Airlift: pCity.getMaxAirlift (). I guess, when it's bigger than 0 (or -1?), you can airlift.

Culture bonus: pCity.cultureGarrison (i guess).


For the calls in general: Look here or here.
 
Here's another BTS Python API.

Essentially, you want to inspect the CvTechInfos and check if the player has the tech. The simplest way is to loop over all techs each time you need to check. Once you get that working, you can do that once and store the tech IDs that interest you.

You'll need to apply the same logic to the CvBuildingInfos, CvRouteInfos, etc. to find the other effects you are interested in.

Code:
bCanTradeOverOcean = False
for i in range(gc.getNumTechInfos()):
    tech = gc.getTechinfo(i)
    if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
        if pPlayer.isHasTech(i):
            bCanTradeOverOcean = True
if bCanTradeOverOcean:
    ...
All the others seem to be in CvBuildingInfo (Class?). The one that seems odd is the route-enabling techs like The Wheel and Railroad. I see that CvRouteInfo has getTechMovementChange(int TechID). Maybe The Wheel returns 2 for RouteTypes.ROUTE_ROAD. You'll need to check the XML.
 
Code:
bCanTradeOverOcean = False
for i in range(gc.getNumTechInfos()):
    tech = gc.getTechinfo(i)
    if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
        if pPlayer.isHasTech(i):
            bCanTradeOverOcean = True
if bCanTradeOverOcean:
    ...
This would never work since CyPlayer has no isHasTech method. You need to set up an instance of CyTeam for that one.

To make it work replace pPlayer in above sample with pTeam.
("pTeam = gc.getTeam(pPlayer.getTeam())")
 
First off thanks for the help. I decided to work in order, starting with what would come first to affect the new variable CityDistCommBonus, this would be the ability to build roads (I'm dropping the lighthouse function).

I've hit a major stumbling block, which is kind of important to figure out a workaround. I can't figure out how the game decides that a Team can build a route. I've looked through the routeinfos.xml and techinfos.xml and they don't reference each other at all. I can't even start to write code to calculate the change to CityDistCommBonus if I can't first define that pTeam can build roads/railroads. How does the game allow a team to build routes, ie what if I wanted to change the tech req for roads/railroads, where is this defined (The way I've been looking going about doing this, I think I need to figure out this question, how can I tell the function to figure out if pTeam can build railroads, if I don't know how this is known)? If this is handled by the GameCore, actually that might be easier, lol. But what source code file do I need to look into?

For now I'll move onto another function, but I need to figure this one out, arguably the roads/railroad effect is the most important part of the function.

Edit: Work continues, the getCultureGarrisonValue() function doesn't works (breaks it). So I looked in the BuildingInfos.xml and remembered that culture modifiers are expressed in terms of commerce modifiers, so searched through that handy list EmperorFool posted and found these:

INT getCommerceModifier (INT i)
INT getCommerceRateModifier (CommerceType eIndex)
INT getTotalCommerceRateModifier (CommerceType eIndex)
VOID changeCommercePercent (CommerceType eIndex, INT iChange)

How do I use it to define the culture modifier (is this even the correct call)? something like pCity.getCommerceRateModifier(Culture)???

Edit2:

Found a call for routes on that list:

BOOL canBuildRoute ()
bool ()
Not sure how I can use this to define if pPlayer can build a specific route type though.
 
Ability to construct a route is controlled by BuildInfos (XML/Units). So it links to units, not to teams. So loop over BuildTypes to check if they make your route, then check the BuildInfos for the TechPrereq and anything else which may be relevant to see if the Team meets requirements.

And you are correct on how to consult the Culture Modifier, but you have to specify culture properly by fetching the Enum for it (should be something like CommerceTypes.COMMERCE_CULTURE, or maybe a gc.getInfoTypeFor("COMMERCE_CULTURE")
 
Ability to construct a route is controlled by BuildInfos (XML/Units). So it links to units, not to teams. So loop over BuildTypes to check if they make your route, then check the BuildInfos for the TechPrereq and anything else which may be relevant to see if the Team meets requirements.
I'm not sure how to do this. My knowledge of coding is from working on things in this forum, it is quite limited. In the past week I've been reading some tutorials available online about C++, but I haven't gotten past operators and classes... So setting up a loop is a little beyond me. I'm a pretty quick learner though, if you could explain it, and show an example I'll pick up on it. I'd never touched C++ before PoM's Advanced Combat modcomp, but I ended up producing some working code for it, I am very willing to learn.

And you are correct on how to consult the Culture Modifier, but you have to specify culture properly by fetching the Enum for it (should be something like CommerceTypes.COMMERCE_CULTURE, or maybe a gc.getInfoTypeFor("COMMERCE_CULTURE")
Thanks that worked.

Here is the code I have so far.
Code:
            # Distance to capital City Distance modified by communication techs and structures
            cityDistModifier = plotDistance(pCity.getX(), pCity.getY(), capital.getX(), capital.getY())
            cityDistModifier = ( 97*cityDistModifier )/(( CyMap().getGridWidth()**2 + CyMap().getGridHeight()**2 )**0.5)
            if( pCity.isConnectedTo(capital) ) :
                cityDistCommBonus = 31
                [I]#for (pTeam.getBestRouteBuildable) :
                     #cityDistCommBonus += ( 60 - pTeam.getFlatMovementCost()  )*3[/I]
                cityDistCommBonus += pCity.getTradeRouteModifier()
                cityDistCommBonus += pCity.getCommerceRateModifier(gc.getInfoTypeForString("COMMERCE_CULTURE"))
                bCanTradeOverOcean = False
                [I]#for i in range(gc.getNumTechInfos()):
                #tech = gc.getTechinfo(i)
                #if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
                    #if pTeam.isHasTech(i):
                        #bCanTradeOverOcean = True[/I]
                if bCanTradeOverOcean :
                    cityDistCommBonus += 50
                if (pCity.getMaxAirlift() > 1 ) :
                    cityDistCommBonus += 100
                cityDistModifier = cityDistModifier / ( 1 + ( cityDistCommBonus / 100 ) )


Getting the CultureModifier to work though caused me to stumble across a huge problem in the code. If a condition is met, the effect is passed on to all cities. How can I make it so that the variable cityDistCommBonus is applied to each city in it's own specific instance, dependant apon that particular city's conditions.
Edit: I tried starting the function like this, but it didn't work. It doesn't totally break things though (Really aggregious errors--comonly sytnax errors--causes a loss of interface), just destroys the RevIdx.
Code:
            for CityDistCommBonus in pCity :
                if( pCity.isConnectedTo(capital) ) :
                    ...
 
Where this code runs, pCity is a single CyCity. Where does it come from? What is the context of this code?
 
It's from Revolutions. It's revolution.py found in the Gameready folder of the Revolution python folder. I've had this problem with the code found in the OP. If you built a single harbor in one city, the bonus would be applied to all cities. I can't figure it out, the citydistancemodifier is obviously only applying on a city by city basis, as the value changes depending on how far the city is from the capitol. Anyway that was part of the reason I wanted to change the function of the code, and create a different variable which was then applied to the citydistance variable, so that I could fix that bug. Also just wanted to clean up the code, and make it useable by other mods. Having it pull specific values from the XML seemed like a poor jerry rig.

Edit: Nevermind, it's applying properly. I didn't realize jdog added in an era specific modifier to the CityDistance calculation. Of course now I realize that calling the culture isn't working.
 
Thanks alot for your help guys. Really close to having this done, just two bits left to figure out:

What's wrong with this code that EF posted:
Code:
                bCanTradeOverOcean = False
                #for i in range(gc.getNumTechInfos()):
                    #tech = gc.getTechinfo(i)
                    #if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
                        #if pTeam.isHasTech(i):
                            #bCanTradeOverOcean = True
                if bCanTradeOverOcean :
                    cityDistCommBonus += 50
Commented out the parts that break it, the non commented code doesn't break anything, so I assume it works.

Edit: Got it working yay:
cityDistCommBonus += 100 - (gc.getRouteInfo(pCity.plot().getRouteType()).getFlatMovementCost())*1.67

Still at a loss as to what's wrong with EFs code above though.

Edit: So I turned on Python exceptions and the problem is in this line:
if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
I tried this: gc.getInfoTypeForString(TERRAIN_OCEAN) also but it still says "global name 'TERRAIN_OCEAN' is not defined". Looked through TerrainInfos.xml and it is indeed TERRAIN_OCEAN, so I'm at a loss here.
 
You're using pTeam without giving it a value. Put

Code:
pTeam = gc.getTeam(pPlayer.getTeam())

before the first commented-out line (for i in range...).
 
That's not the problem:

When I turned on Python exceptions it refered me to this line:
if tech.isTerrainTrade(TerrainTypes.TERRAIN_OCEAN):
I tried this: gc.getInfoTypeForString(TERRAIN_OCEAN) also but it still says "global name 'TERRAIN_OCEAN' is not defined". Looked through TerrainInfos.xml and it is indeed TERRAIN_OCEAN, so I'm at a loss here.
 
I tried defining pTeam, but I still get the same Python exception related to TERRAIN_OCEAN not being defined (if I use gc... if I use terrain_types it says 'TERRAIN_OCEAN' has no atribute). This is really confusing too, because it clearly is TERRAIN_OCEAN in the XML.
 
It's all working now :)
 
I'm good, thanks guys, this is the code, everything works now:
Code:
            # Distance to capital City Distance modified by communication techs and structures
            cityDistModifier = plotDistance(pCity.getX(), pCity.getY(), capital.getX(), capital.getY())
            cityDistModifier = ( 97*cityDistModifier )/(( CyMap().getGridWidth()**2 + CyMap().getGridHeight()**2 )**0.5)
            cityDistCommBonus = 0
            pTeam = gc.getTeam(pPlayer.getTeam())
            bCanTradeOverCoast = False
            for i in range(gc.getNumTechInfos()):
                    tech = gc.getTechInfo(i)
                    if tech.isTerrainTrade(gc.getInfoTypeForString("TERRAIN_COAST")):
                        if pTeam.isHasTech(i):
                            bCanTradeOverCoast = True
            bCanTradeOverOcean = False
            for i in range(gc.getNumTechInfos()):
                    tech = gc.getTechInfo(i)
                    if tech.isTerrainTrade(gc.getInfoTypeForString("TERRAIN_OCEAN")):
                        if pTeam.isHasTech(i):
                            bCanTradeOverOcean = True
            if bCanTradeOverOcean :
                cityDistCommBonus += 50
            if( pCity.isConnectedTo(capital) ) :
                cityDistCommBonus = 31
                cityDistCommBonus += 100 - (gc.getRouteInfo(pCity.plot().getRouteType()).getFlatMovementCost())*1.67
                if( pCity.isCoastal(-1) ) :
                    if bCanTradeOverOcean :
                        cityDistCommBonus += 66
                    elif bCanTradeOverCoast :
                        cityDistCommBonus += 33
                cityDistCommBonus += pCity.getTradeRouteModifier()
                cityDistCommBonus += pCity.getCommerceRateModifier(CommerceTypes.COMMERCE_CULTURE)*1.1
                if (pCity.getMaxAirlift() > 0 ) :
                    cityDistCommBonus += 100
            cityDistModifier = cityDistModifier / ( 1 + ( cityDistCommBonus / 100 ) )
I do have one function I want to add to it though. But I can't find anything in the API that seems relevant. I'd like to make a call to see if the city could build a unit of domain type air, regardless of resources (basically still count redded out builds, just that a domain unit air is tech possible to build)
 
So the code is working great. Really apreciate the help, especially that API link, very useful.

Now that I have it functional, I want it to show some information to the player. For instance, this code is now making the harbor give an equal bonus to the city distance penalty, as it is giving to trade route yield. I'd like this to show up on the harbor information. How can I do this, while still keeping the function tied to the effect, and not the specific building? I don't want to write display information for the specific building, I would like text to show up whenever there is a non 0 number in traderoutemodifier for any building. I can compile a new gamecore or whatever as necessary, though I'd prefer to keep it in the same file (revolution.py), that's not essential. I just have no idea where to start on how to get text to show up, let alone how to piggy back it onto an XML that already has text displayed.

Probably a simple way to do this would be to see the code that assigns the text for the bunus commerce yeild on a harbor. Anyone know where that is?

Also with python exceptions turned on I keep getting a pop up saying "Can't find Enum "CIV_HOLY_ROMAN". Now because this mod is built from the Wolfshanze mod, the holy roman empire has been removed. What is the Enum? And where can I find it's reference in Python or the SDK so I can squash this bug. It seems to not effect anything, but still rather get rid of any exceptions that occur.
 
I assume you mean the text that's shown when you hover over a building in the city screen or civilopedia? If so, that's in CvGameTextMgr.cpp. The easiest way to find such things is to search in the XML using a find program for the actual text displayed. That will tell you the XML text key. Then search the CPP and/or Python files for that XML text key to see where it's used.

I have all the XML and Python files in a single "Core Assets" Eclipse project so I can search them quickly. Then I use the "find in files" command in VS2005 if I'm working in the SDK.

As for the Holy Roman thing, I bet it's in an XML file somewhere rather than Python.
 
I have all the XML and Python files in a single "Core Assets" Eclipse project so I can search them quickly. Then I use the "find in files" command in VS2005 if I'm working in the SDK.

As for the Holy Roman thing, I bet it's in an XML file somewhere rather than Python.
That sounds increadibly useful. Could you give me a brief explanation of how I set this up? The only thing I've done so far with VS2005 is compile the gamecore. I have no familiarity with it. But man, being able to type in NAME_OF_OBJECT and have it search all xml files and find all references would be so awesome; I really want to know how to do this.
 
Top Bottom