[Python] #Does pCity have BuildingClass?

phungus420

Deity
Joined
Mar 1, 2003
Messages
6,296
As the title of the thread says, How do I write this? To give an example, I'll show the code I'm working on right now

Code:
            #CityDistModifier = distance to capitol with Communication Tech and building bonuses
            cityDistModifier = plotDistance( pCity.getX(), pCity.getY(), capital.getX(), capital.getY())
            cityDistModifier = min([cityDistModifier, 100]) - 3
            if( not pCity.isConnectedTo(capital) ) :
                cityDistModifier = 2*cityDistModifier
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech) ) :
                cityDistModifier = 0.9*cityDistModifier
            else:
                cityDistModifier = 1.2*cityDistModifier

I want to add in another elif (above the first) to look and see if the city has a harbor. Something like this:
Code:
           #CityDistModifier = distance to capitol with Communication Tech and building bonuses
            cityDistModifier = plotDistance( pCity.getX(), pCity.getY(), capital.getX(), capital.getY())
            cityDistModifier = min([cityDistModifier, 100]) - 3
            if( not pCity.isConnectedTo(capital) ) :
                cityDistModifier = 2*cityDistModifier
[B]            #elif( pCityHasbuildingclass(Harbor) ) :
                #cityDistModifier = 0.8*cityDistModifier[/B]
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech) ) :
                cityDistModifier = 0.9*cityDistModifier
            else:
                cityDistModifier = 1.2*cityDistModifier
Look as I may, I have been unable to find an example of this type of call, and would really apreciate the help. This is my first programming, outside of simple XML edits, so I think I'm doing good, considering this is only my second day of writing any real code, let alone python specific code, but I've hit a brick wall here, and need help.

Also does anyone know where I could find a list of the tech names, and building types python will be using. They don't follow the standard naming conventions used in XML (which brings up another point, how do I make a call for a tech or building I've added in the XML, which isn't in the core game?)
 
You get info out of the XML using CyGlobalContext() or as it is abbreviated gc. Just call gc.getInfoTypeForString.
Code:
iTechMysty = gc.getInfoTypeForString("TECH_MYSTICISM")
You can do the same with Units/Buildings/Promotions/if it's in a XML File you can get it. I can't remember how to check for a building class but I know that getNumRealBuilding returns the number of a specific type that's in a city (oh and it only ever returns 1 or 0 because that's the most a city can have), so code like this will check for a harbor.
Code:
if pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_HARBOR")) > 0:
    cityDistModifier = 0.8*cityDistModifier
 
Thank you so much for your help. For the buildings, totally works, I can't use buildingclass for some reason, but that's OK. On techs, I'm having a problem. Now before getting to the CivDistModifier, certain data for the civs is pre loaded. Here is a sample of that code:

Code:
        # Gather some data on the civ that will effect every city
       hasNationalism = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iNationalismTech)
        hasLiberalism = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iLiberalismTech)
        hasSciMethod = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iSciMethodTech)
        hasWheel = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech)

Now try as I might, I can't get it to load Engineering. I got it to load the Wheel, but I think I might just have gotten lucky there. I've tried a bunch of different ways to write it. And I can't figure out why this doesn't work:

Code:
        # Gather some data on the civ that will effect every city
[B]        iEngineeringTech = gc.getInfoTypeForString("TECH_ENGINEERING")
        hasEngineering = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iEngineeringTech)[/B]
        hasNationalism = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iNationalismTech)
        hasLiberalism = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iLiberalismTech)
        hasSciMethod = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iSciMethodTech)
        hasWheel = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech)

I've been hammering on this, trying to get it to load engineering so I can use it in the CityDistModifier lines for about 4 hours now. No way I try to write it works (tried defining iEngineeringTech on the same line a whole bunch of different ways etc), so I'm coming back here to see if you or anyone else knows how to properly write it, so I can get this file to pull up weather or not the Civ in question has the tech. Also just defining iEngineeringTech works fine. I can leave that line in there, it's just when I put in the hasEngineering line that it breaks.

There is another part where the python checks for the tech, and It seems to work fine there. This is what I wrote, and I'm not seeing any problems (no way to know if it actually loads the tech info though, but I assume it is, because everything still works fine, and whenever there is failed code in the python, the RevIndex box doesn't show up)
Code:
        self.iNationalismTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), RevDefs.sXMLNationalism)
        self.iLiberalismTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), RevDefs.sXMLLiberalism)
        self.iSciMethodTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), RevDefs.sXMLSciMethod)
        self.iWheelTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), RevDefs.sXMLWheel)
        self.iEngineeringTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), iEngineeringTech = gc.getInfoTypeForString(TECH_ENGINEERING) )


Edit: I guess I just needed to go to sleep and come back and tackle it later. The key was the RevDefs.xMLNameTech line, that referenced another python file where the iNameTech were originally called. Still though, Why couldn't I define the iNameTech by itself in this file, why was it forced to go back to another list? I still would like to know why the workaround I posted above failed, if anyone knows.
 
You may have accidentally put the wrong type tag (sometimes the type tag is way different than what you think it should be).
 
In the second code block you define
Code:
iEngineeringTech = gc.getInfoTypeForString("TECH_ENGINEERING")
and then call
Code:
self.iEngineeringTech

In the last block
Code:
self.iEngineeringTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), [B]iEngineeringTech = gc.getInfoTypeForString(TECH_ENGINEERING)[/B] )
The bolded part is all wrong. First you shouldn't be setting an abttribute inside a function call. Second, that also isn't the place to put gc.getInfoTypeForString as it returns an integer and that argument needs to be a Tech Type Tag string.
 
You need to insert "self." in front of iEngineeringTech when you set it since that's how you access it in the second line:

Code:
[b]self.[/b]iEngineeringTech = gc.getInfoTypeForString("TECH_ENGINEERING")
hasEngineering = gc.getTeam(pPlayer.getTeam()).isHasTech(self.iEngineeringTech)
The second code part should read

Code:
self.iEngineeringTech = CvUtil.findInfoTypeNum(gc.getTechInfo,gc.getNumTechInfos(), "TECH_ENGINEERING")
Note that after this line runs, "self.iEngineeringTech" holds the info # for that tech and can be used in the code above. In other words, you can probably remove the first line in the first code block I posted.
 
So I thought I had this working, but it fails. Here is the sample code:

Code:
            # Distance to capital City Distance modified by communication techs and structures
            cityDistModifier = ( plotDistance( pCity.getX(), pCity.getY(), capital.getX(), capital.getY()) )*0.37
            if( not pCity.isConnectedTo(capital) ) :
                cityDistModifier = (cityDistModifier + 1)*3.7
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_AIRPORT")) > 0 ) :
                if( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iJetTech) ) :
                    cityDistModifier = (cityDistModifier - 6)*0.5
                else:
                    cityDistModifier = (cityDistModifier - 5)*0.7
            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("BUILDING_HARBOR")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_CARTHAGE_COTHON")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)
                else:
                    cityDistModifier = (cityDistModifier - 3)*1.4
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iAstronomyTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_HARBOR")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)*1.4
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_CARTHAGE_COTHON")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 3)*1.4
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_LIGHTHOUSE")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.7
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_VIKING_TRADING_POST")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.7
                else:
                    cityDistModifier = (cityDistModifier - 2)*1.9
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iEngineeringTech) and gc.getTeam(pPlayer.getTeam()).isHasTech(self.iHorsebackTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_HARBOR")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.9
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("CARTHAGE_COTHON")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 2)*1.9
                else:
                    cityDistModifier = (cityDistModifier - 1)*2.2
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_HARBOR")) > 0 ) :
                cityDistModifier = (cityDistModifier - 1)*2.5
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_CARTHAGE_COTHON")) > 0 ) :
                cityDistModifier = (cityDistModifier - 1)*2.5
            elif( gc.getTeam(pPlayer.getTeam()).isHasTech(self.iWheelTech) ) :
                if( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_LIGHTHOUSE")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 1)*2.5
                elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_VIKING_TRADING_POST")) > 0 ) :
                    cityDistModifier = (cityDistModifier - 1)*2.5
                else:
                    cityDistModifier = cityDistModifier*2.8
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_LIGHTHOUSE")) > 0 ) :
                cityDistModifier = cityDistModifier*2.8
            elif( pCity.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_VIKING_TRADING_POST")) > 0 ) :
                cityDistModifier = cityDistModifier*2.8
            else:
                cityDistModifier = cityDistModifier*3.3

            #cityDistModifier = adjusted for map size and normalized
            
            cityDistModifier = cityDistModifier - 2
            cityDistModifier = cityDistModifier/((( CyMap().getGridWidth()**2 + CyMap().getGridHeight()**2 )**0.5)*0.013)
            distMod = 1.0 + RevUtils.getCivicsDistanceMod( iPlayer )
            distMod *= self.distToCapModifier
            if( pCity.isGovernmentCenter() ) :
                distMod *= 0.5
            elif( pCity.getMaintenanceModifier() > 0 ) :
                # Decrease effect if city has courthouse
                distMod *= 0.75

I get pretty close to intended behavior, however it is not properly giving reduced values for the presence of buildings. I don't think it is in effect checking for the presence of the building types (lighthouse, harbor, airport). It's strange though, if I add a lighthouse or a harbor sometimes I'll get a reduction, but it's not as big of a reduction as it should be, and often times it's ignored (no reduction to the cityDistModifier if I drop a Harbor when the civ has Eng + Horse for instance).

Is there another way to see if a city has building other then the getRealNumBuilding method I'm using here? For the techs it loads the information from another file. I've added the buildingclasses in that file, but I don't know how to call for a city if it has that buildingclass with that. (I've defined them as sXMLBuildingclassname and using something like getRealNumBuilding(RevDef.sXMLBuildingclassname) doesn't work, in fact it totally breaks it).
 
getRealNumBuilding takes an iBuildingType as an argument. If you give it a string like sXMLBuildingclassname, then yes, it would break it. You would have to rap that string in gc.getInfoTypeForString().
 
Cool thanks. How do I make sure it's looking at a specific city? Would I use pCity.gc.getInfoTypeForString(RevDef.sXMLBuildingClassname) or is this incorrect syntax?
 
No, more like.
Code:
pCity.getNumRealBuilding(gc.getInfoTypeForString(RevDef.sXMLBuildingC lassname))
 
Thanks. That doesn't break it, so aparently it recognizes everything, but it's still not applying the building bonuses. Is there any other way to ask if a city has a building other then getNumRealBuilding? Thanks again, I like it set up like using the sXML tag better, now just gotta get it to work. I'll post this in the Revolution forums and see if Jdog can shed some light on it. If anyone has any ideas why this isn't working please let me know though.
 
getNumRealBuilding() is the way to check for buildings. Try placing a bunch of print statements throughout the function to see how it is executing and what the variables contain. The output will go to PythonDbg.log
 
I'm kind of a noob at this. How do I place a print statement?
 
Also, getNumRealBuilding() requires real building IDs--not building class IDs. You need to convert it to the correct building ID for that civilization using the player's CivInfo.

Or you can put each building class to check for as you've done above.
 
Doh! Good eye EmperorFool, passing a Class ID as a Buidling ID can have weird results. Guess I should accually read code before I cut and paste it, we'll chalk that up to it being early when I posted. :mischief:
 
Cool, it was a problem with using the Buildingclass instead of the building. Thanks. I wonder why it didn't work by calling the building from the XML directly, it's strange I had to predefine it in the RevDefs file, but that's OK. Thanks guys.

Dresden how do I set up a print statement like you suggested? I can see how this would be very useful in the future.
 
At its most basic a print statement is simply print("some message"). You can also use the Python % operator to insert values to check on variables. Here's a potential example from your code which is hopefully self-explanatory:

Code:
            if( pCity.isGovernmentCenter() ) :
                distMod *= 0.5
                print("%s is a Government Center. distMod = %f" %(pCity.getName(), distMod))
            elif( pCity.getMaintenanceModifier() > 0 ) :
                # Decrease effect if city has courthouse
                distMod *= 0.75
                print("%s is NOT a Government Center but has a courthouse. distMod = %f" %(pCity.getName(), distMod))

Most people use a separate wrapper function for their debug print statements (see pyPrint() in CvUtil.py for an example) in order to do things like add a common prefix, put in a timestamp, be able to globally enable/disable the printing, etc. But the regular old print() works too and makes for a simpler example.
 
Python fairy says, "The *= operator (along with its brethren +=, -=, /=, etc) performs in-place multiplication. 'x *= y' is the same as 'x = x * y' but is easier to type and read."
 
Back
Top Bottom