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

Tying Unit and Building Availability to Civics choices

Hey Kael, thanks for the great tip. I am curious though, is there a def CanConstruct or CanBuild event? This would be a lot simpler because then I could define the single case in which a building or unit can be constructed-rather than all the cases in which it cannot! Another thing I was wanting to know is where you might go to discover if you have aqcuired a disabled tech. It doesn't seem to show up in the tech tree.
Again, guys, thanks for all your advice and assistance, my eventual 'thankyou' list is gonna be HUGE at this rate ;)!

Yours,
Aussie_Lurker.
 
Aussie_Lurker said:
Hey Kael, thanks for the great tip. I am curious though, is there a def CanConstruct or CanBuild event? This would be a lot simpler because then I could define the single case in which a building or unit can be constructed-rather than all the cases in which it cannot! Another thing I was wanting to know is where you might go to discover if you have aqcuired a disabled tech. It doesn't seem to show up in the tech tree.
Again, guys, thanks for all your advice and assistance, my eventual 'thankyou' list is gonna be HUGE at this rate ;)!

Yours,
Aussie_Lurker.

There is a Can event that matches both of the Cannot's. Its typically easier to use the Cannot because you let the comptuer do most of the work and just put in an additional check to fail it if everything else is good.

If you use the Can event you are assuming its okay to make except for your check.

So lets assume you want to make a civic required for a unit and you add a check in either function to make sure the civic is in place before you can build the unit.

If you add it to the can event, if you have the civic you will be able to make the unit. No matter what else exists. No matter if you don't have the resources required, no matter if you dont have the techs required. The only requirement to CanTrain will be the civic.

If you add the check to the cannot train then it will have to qualify for all other things before your check will take place.
 
Ahhh, thanks for that Kael, now I understand the value of approaching it from the CannotConstruct angle. I am going to try your approach tonight, and see if that works. I do have to say though that I am kind of liking this in-built 'redundancy' in the python code. i.e. there are multiple ways in which you can approach the same problem-makes it a bit easier for novices like me. Though I think I have done reasonably well just to have put in specialists that only appear under certain civics conditions!

Yours,
Aussie_Lurker.
 
You know, I didn't even know that that existed! Does seem a better method indeed. I think I'm going to have to move several of my functions over to doing it this way!

Except... why do it with religions? Surely if you do requiring certain religions in the XML then it shows up in the 'pedia, and in the mouseovers - which has got to be better?
 
The Great Apple said:
You know, I didn't even know that that existed! Does seem a better method indeed. I think I'm going to have to move several of my functions over to doing it this way!

Except... why do it with religions? Surely if you do requiring certain religions in the XML then it shows up in the 'pedia, and in the mouseovers - which has got to be better?

The games built in functions are lacking. So I can enable a unit for a religion. But I can't disable a unit for a religion (which is what the code I posted does) and let all the rest of religions (including no state religion) access it. Interrupting the CannotTrain function gives alot more control.
 
Kael said:
The games built in functions are lacking. So I can enable a unit for a religion. But I can't disable a unit for a religion (which is what the code I posted does) and let all the rest of religions (including no state religion) access it. Interrupting the CannotTrain function gives alot more control.
Ah right. I completely misread that code. :crazyeye:
 
It is kind of odd but I seem unable to find an instruction for CannotConstruct or CannotTrain, but can find their Can counterparts. Do you know why this might be Kael? Also, where in your script do you put the CannotTrain Command, or can it go anywhere-oh, and does it have to be in CvCustomEventManager.py? Sorry, but I really AM a novice when it comes to python I'm afraid!

Yours,
Aussie_Lurker.
 
Aussie_Lurker said:
It is kind of odd but I seem unable to find an instruction for CannotConstruct or CannotTrain, but can find their Can counterparts. Do you know why this might be Kael? Also, where in your script do you put the CannotTrain Command, or can it go anywhere-oh, and does it have to be in CvCustomEventManager.py? Sorry, but I really AM a novice when it comes to python I'm afraid!

Yours,
Aussie_Lurker.
This is exactly what I was thinking when I first read his code. They're in CvGameUtils.py (lines 130 and 145). I think you can just add the code into that file and it'll work.
 
The Great Apple said:
This is exactly what I was thinking when I first read his code. They're in CvGameUtils.py (lines 130 and 145). I think you can just add the code into that file and it'll work.

Thats correct. Just about all of the mods that comes with the game mess with the file so there are food examples too. The best is the American Revolution mod because it labels the variables passed to the functions in the Mods\American Revolution\Assets\Python\CvGameUtils.py file.
 
OK, I put the appropriate code under the CannotConstruct section of CvGameInterface.py, but am getting the following error message in my PythonErr log

Code:
ERR: Python function cannotConstruct failed, module CvGameInterface
Traceback (most recent call last):
  File "CvGameInterface", line 132, in cannotConstruct
AttributeError
: 
'CyPlayer' object has no attribute 'getCivic'

Is it because I have the code in the wrong place?

Yours,
Aussie_Lurker.
 
Aussie_Lurker said:
OK, I put the appropriate code under the CannotConstruct section of CvGameInterface.py, but am getting the following error message in my PythonErr log

Code:
ERR: Python function cannotConstruct failed, module CvGameInterface
Traceback (most recent call last):
  File "CvGameInterface", line 132, in cannotConstruct
AttributeError
: 
'CyPlayer' object has no attribute 'getCivic'

Is it because I have the code in the wrong place?

Yours,
Aussie_Lurker.

It's probably because it should be getCivics rather than getCivic :mischief:
 
OK, so now I have a NEW problem :(. Changed getCivic to getCivics, and am now getting THIS error:

Code:
ERR: Python function cannotConstruct failed, module CvGameInterface
Traceback (most recent call last):

  File "CvGameInterface", line 125, in cannotConstruct

  File "CvGameUtils", line 154, in cannotConstruct

NameError: global name 'pPlayer' is not defined

To help you out, this is what I have typed in the .py file

Code:
def cannotConstruct(self,argsList):
		pCity = argsList[0]
		eBuilding = argsList[1]
		bContinue = argsList[2]
		bTestVisible = argsList[3]
		bIgnoreCost = argsList[4]

		if eBuilding == gc.getInfoTypeForString('BUILDING_SLAVE_MARKET'):
                            if pPlayer.getCivics() == gc.getInfoTypeForString('CIVIC_TRIBALISM'):
                                    return True

                if eBuilding == gc.getInfoTypeForString('BUILDING_SLAVE_MARKET'):
                            if pPlayer.getCivics() == gc.getInfoTypeForString('CIVIC_SERFDOM'):
                                    return True
		    
		return False

I am truly starting to believe that Python is one of the most UNFRIENDLY types of coding language around-given the extreme difficulty I have had with doing such a relatively simple thing (i.e. If player has civic A, then can build improvement A, otherwise can't)
Anyway, I am begging you guys for more help here. I am doing everything as I have been instructed, but it STILL won't work :cry:

Yours,
Aussie_Lurker.
 
Well, looking at your code - it's right. You have not defined pPlayer.

Try:
Code:
	ePlayer = pCity.getOwner()
	pPlayer = gc.getPlayer(ePlayer)
(From Kael's code above)

I find python a very nice coding language. C++ is evil.
 
This, I believe, will be my first post. I have been the shy person in the back of the forums that has read almost all the discussions, and does not voice any oppinion or information he might have. Today however, I can not keep to myself any longer. So please fellow Civ4 fanatics, accept me.
Anyway, to get to the point. I have no idea how to code Python, but instead of making a thread discussing how I do not know how to code it, I will post here. My goal in Python is similar to Aussie's. I need to have Civic unique units that unly become avliable with the certain technology, which enables the Civic, which will enable the unit. This is my for my own mod, which is in the proccess of creation, and I need help similar to Aussies.
So far I have taken the code submitted by Aussie (thanks man), and stuck it into, what I believe is, the right .py file (CvGameUtils.py). After the usual XML errors, informing me of my broken XML files and such, my game completely crashes. I might be missing some code in CvGameInterface, but I do not know what code needs to go where.. and I did alter some of Aussie's code. If I knew how to make those clever boxes, I would submit my changes.


if eBuilding == gc.getInfoTypeForString('UNITCLASS_WARLOCK'):
if pPlayer.getCivics() == gc.getInfoTypeForString('CIVIC_NONMAG'):
return True

I dont know what any of the coding does, but that is what I changed in Aussie's code trying to connect it to the XML somehow. I believe I have to change eBuilding maybe to eUnitBuild (or whatever the command is), and maybe instead of a whole UNITCLASS, maybe just UNIT.
Any help is appreciated. I know this is Aussies thread, and he deserves the help before I do, but be aware there is utter Python newbs out there that can benefit from this thread. My goal in my mod is to have 5 civics to chose a unique unit, depending on time period and the technology you have researched. Also, there will be 5 more civics which will give youa superior unit that not only needs one of the previous 5 civics, but resources, and technology. Again, thank you for starting this thread, and if you read this, thank you for that too ;)

-
Ron
 
Well, going from Kael's earlier post, you want eUnit and not eBuilding-hope that helps. The problem I am having though is that it is telling me that getCivics() conflicts with the C++ values??
For the time being, however, I am abandoning the Python side of my modding, and will instead focus on XML.
By the way Cyruss, if you download Altova XMLSpy, and edit your XML files using this tool, you will find broken XML's become a thing of the past!

Yours,
Aussie_Lurker.

EDIT: My last action was to switch back to trying to make the Slavery civic grant the Slavery tech (might come in useful for making a pre-existing building disappear). The code reads like this:

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

                ePlayer = gc.getPlayer(iPlayer)
                eTeam = gc.getTeam(ePlayer.getTeam())

                if(ePlayer.getCivics == gc.getInfoTypeForString('CIVICS_SLAVERY')):
                        eTeam.setHasTech == gc.getInfoTypeForString(('TECH_SLAVERY'), True, iPlayer, False, True)
                else:
                        eTeam.setHasTech == gc.getInfoTypeForString(('TECH_SLAVERY'), False, iPlayer, False, False)

and I am getting back the following PythonErr log

Code:
Traceback (most recent call last):

  File "CvEventInterface", line 23, in onEvent

  File "CvCustomEventManager", line 29, in handleEvent

  File "CvEventManager", line 164, in handleEvent

  File "CvCustomEventManager", line 99, in onBeginPlayerTurn

NameError: global name 'argslist' is not defined

Can either Kael or Great Apple tell me why this might be?

(p.s. Cyruss, in order to print code in the 'neat little box', either click on the # symbol above the text box-or type Code and /Code in square brackets-and insert the code in between the boxes.

Yours,
Aussie_Lurker.
 
Code:
def onBeginPlayerTurn(self, argsList):
                'Called at the beginning of a players turn'
                [B]self.parent.onBeginPlayerTurn(self, argsList);[/B]
                iGameTurn, iPlayer = argslist

                ePlayer = gc.getPlayer(iPlayer)
                eTeam = gc.getTeam(ePlayer.getTeam())

                if(ePlayer.getCivics == gc.getInfoTypeForString('CIVICS_SLAVERY')):
                        eTeam.setHasTech == gc.getInfoTypeForString(('TECH_SLAVERY'), True, iPlayer, False, True)
                else:
                        eTeam.setHasTech == gc.getInfoTypeForString(('TECH_SLAVERY'), False, iPlayer, False, False)

I have no idea what the bolded line is, or why it is ended with a semi-colon. It looks like you are trying to call another function but the semi-colon isn't right.

Also you dont use == when setting things equal, thats only used to check things in if statements. The correct usage would be something like:

Code:
eTeam.setHasTech(gc.getInfoTypeForString('TECH_SLAVERY'), False, iPlayer, False, False))
 
also I think your getting a simple casesensitivity mismatch, argsList != argslist

I am wondering why you need to go into CannotConstruct, wont giving and taking away a Tecnoloy ever time you change Civics take care of everything?

You might also want a "Wiper" function that will remove everything a player owns that they nolonger have the tec for. Two versions one for buildings and one for Units firing imediatly after Tec Aquired so if you have changed Civics it would wipe out all of the old units and Buildings that required the old Civic. Everything else could be done in XML such as create a tecnology for every Civic choice and giving thouse Tecs as Pre-requiste to buildings.

Also to give a player a free building upon adopting a Civic another function could fire on TecAquired which would look at the Buildings that required the recivied Tec, if the Buildings has a cost of 0 it places the building in all your Cities imediatly. Again once a general function of this type is made all the configuring for individual Mods can be done in XML.
 
What everybody else said. With the error messages, the last few lines are always the ones that actually tell you something.

Also...

the format for getCivics is getCivics(CivicOptionType) - allowing you to check which of an option the player has. You earlier were using isCivic(CivicType) which returns a true or false (depending if the player is using the civic probably)

@Kael:
Unless I'm mistaken, the bolded line will call the default events that happen with the event onBeginPlayerTurn if using a custom event manager. Though it shouldn't have the semicolon...

@Cyruss
Welcome to CFC [party]:band::dance::beer::wavey:! You can do the clever boxes by surrounding the code in code tags. For example: [CODE]Here is some code.[/CODE]

As for the code you posted. I think it's mostly wrong (sorry!). Basically, as somebody else said you don't really want eBuilding, and also the getCivics line is wrong in the same way Aussie's is wrong.


EDIT: I've just been poking around on the Python webbie, and it would appear semicolons are fine to use - but not needed, unless you want to do more than one thing on each line.
 
I haven't tested this, but if I was to write this I would make it look like the following:

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

                ePlayer = gc.getPlayer(iPlayer)
                eTeam = gc.getTeam(ePlayer.getTeam())

                if(ePlayer.getCivics(gc.getInfoTypeForString('CIVICOPTIONS_LABOR')) == gc.getInfoTypeForString('CIVICS_SLAVERY')):
                        eTeam.setHasTech(gc.getInfoTypeForString(('TECH_SLAVERY'), True, iPlayer, False, True)
                else:
                        eTeam.setHasTech(gc.getInfoTypeForString(('TECH_SLAVERY'), False, iPlayer, False, False)
 
Hi Kael,

Is this CannotTrain function the one located in CvGameInterface.py and CvGameUtils.py? Does it work? When will this func be called? very before player open the city window or small building list? I try to use another CannotConstruct func to disable building, but didn't see it take effect? Could you bring me more details please?
 
Top Bottom