[PYTHON] Multiple civs?

Sinapus

Defenestrated
Joined
Jun 12, 2002
Messages
872
Location
Houston, TX
I'm trying to puzzle out python and having problems comprehending it. Then again I've always been horrible with coding so that's not surprising, I'm better at adjusting values in existing code than actually creating it from scratch.

I'm attempting to find out if it's possible to have a python-scripted event affect the cities of every player in the game, including the barbarian player. Mainly to test a crazy idea I suggested for an event that does something horrible to every player in the game, affecting every city, but also to add bonuses or similar to every city.

Is there a way to run the setCulture, setFood and setPopulation or similar commands(?) on every city in the game, regardless of which civilization owns them? Some of the event python scripting seems to have a "loopCity" function that might allow it, but I have no idea how to run it. It also implies there's no simple "go to every city and do this" command available.

(...and if you're wondering why I specified those variables, perhaps I've been watching too many of the DoomDiscovery and HysteriaHistory Channels' disaster documentaries.)
 
Are you interested in ever learning how to do Python? Or is this one request the sum of your ambitions as a programmer? Are you sure about this?

Because it wouldn't be hard to make whatever you suggested - its probably something like 5-10 lines of code. But you still need to figure out where to put it, get the indentation levels in order, yada, yada...

If you only want the code - all of it - and clear instructions on where to put it - then I suggest you put your idea down in great detail. Because chances are that someone will just make it for you. Because its about 100 times quicker than to explain how you would go about programming Python without knowing anything about it, and trying to guide you through the entire process. Chances are that it would never be done.

But if you wanna be able to this yourself - and all the other cool ideas you might come up with - then someone would be able to get you started with Python instead. And only once you learn how to code for real would it make any sense to give you directions on how to implement your idea.

My 2 cents.

edit: I'm pretty tempted to do the code for you on the fly - just for the fun of it - but I'm fighting the urge. For now. :lol:
 
Are you interested in ever learning how to do Python? Or is this one request the sum of your ambitions as a programmer? Are you sure about this?

At the moment, it's just this idea. I'm thinking of two things: first some code to run from the python console on a game where the player civs are pretty well-developed and execute it to see how bad it would get and if it isn't too much of a game-breaker, a way to put it in the CvRandomEventInterface.py file. So the effect I want and then how to make that effect work in an event.

Because it wouldn't be hard to make whatever you suggested - its probably something like 5-10 lines of code. But you still need to figure out where to put it, get the indentation levels in order, yada, yada...

If you only want the code - all of it - and clear instructions on where to put it - then I suggest you put your idea down in great detail. Because chances are that someone will just make it for you. Because its about 100 times quicker than to explain how you would go about programming Python without knowing anything about it, and trying to guide you through the entire process. Chances are that it would never be done.

The initial idea was pretty specific: reduce every city's (regardless of which civilization owns it) population to 1, reduce every city's food storage totals to 0 and every city's culture to 0.

Think of it as a global pandemic from the hysterical disaster porn documentaries put out by some cable networks. I was trying to think of a way to make things as bad as possible for a civ without destroying cities and to make it possible to recover. I was also trying something that might be easier to execute instead of something more complex like randomly determining which buildings get destroyed in the chaos and destroying military units at random. I'd like to avoid that for now and stick with the initial idea. I'm figuring the "setPopulation" function would work best for the initial idea and can adjust the population reduction as needed.

If the initial idea can be executed from the python console, I can see what it looks like, game-wise and then work out a way to make the event work. Then either fine-tune the idea or run away screaming. :mischief:

But if you wanna be able to this yourself - and all the other cool ideas you might come up with - then someone would be able to get you started with Python instead.

Not sure this is a "cool" idea, since it involves killing off 90+ percent of the population in a game. :eek2:
 
Ok, you're definitely looking to do more than just add one ready-to-use game feature. You're looking to develop a mod, basically. First make sure you know your Python.

I think you should hook your code up in CvEventManager instead, probably in onBeginGameTurn. Then fire the code on random turns with:
Code:
if iGameTurn % gc.getGame().getSorenRandNum(iProbability, 'event') == 0:
(iProbability is of course the one in whatever chance of the event to take place.)

You should probably create your own Python module for testing and development. Then you can import the module in the Python console and run your code. Later you could just hook the finished work up in the Event Manager by importing the module and making a function call.

To loop all cities of all players you firstly import the PyHelpers module and use PyGame.getCivPlayerList(). (You need to add the Barbarian Civ to the list also.) Then you loop through all PyPlayer instances and use PyPlayer.getCityList() to get a list of PyCity instances for each. You loop these in order and use PyCity.GetCy() to retrieve the CyCity instance of the current city.

With each CyCity instance you can then invoke the methods CyCity.setFood(0), CyCity.setPopulation(1) and CyCity.setCulture(0).

Does any of the above mean anything to you? If you have a hard time following these instructions you might wanna read up on Python in general and Python modding in particular. You could check out my tutorial. (Basically all you need to know is covered in it.)

Just a tip: Don't waste time trying to do something you don't know how to do - invest that time in learning how to do it instead, and you get the job done in 1/10 of the time - learning time included. Plus you learn how to develop the rest of your mod.

Good luck! :king:

edit: I couldn't help myself. :rolleyes:
Spoiler :
Code:
from CvPythonExtensions import *
import PyHelpers
pyPlayers = PyHelpers.PyGame().getCivPlayerList()
eBarbarian = CyGlobalContext().getBARBARIAN_PLAYER()
pyBarbarian = PyHelpers.PyPlayer(eBarbarian)
pyPlayers = pyPlayers + [pyBarbarian]
for pyPlayer in pyPlayers:
        pyCities = pyPlayer.getCityList()
        for pyCity in pyCities:
                pCity = pyCity.GetCy()
                pCity.setPopulation(1)
                pCity.setFood(0)
                pCity.setCulture(0)
 
I guess the OP would find this link helpful ;).
:lol: Very much so. Too bad it makes little to no sense at first. I only deciphered it when I learned about classes. And I just realized what the iValues were the other day - fields of the class instances, obviously!
 
that might be, but from what the OP said, i guess he can already program ;).
I got the opposite impression. :p Only being able to change values was all I could do at first - and that was hardly programming! :lol:

You need to know about import, assignment, conditional and iteration statements - otherwise its not really meaningful programming... Also being able to use function calls and understand what return statements are is the bare minimum for practical use of Python. And with CivIV Python you're actually using classes and methods. That stuff makes little sense before you know the more advanced stuff, in my experience.

But luckily this knowledge is readily available for anyone who is interested. :goodjob:
 
I got the opposite impression. :p Only being able to change values was all I could do at first - and that was hardly programming! :lol:

Indeed. Most of my computer experience is as a help desk analyst, which is mainly helping the caller find the "any" key. (Okay, I sometimes have to troubleshoot further, but little or no coding is involved.) Outside of work, I've done my own hardware upgrades, but again, little coding.

I have been going through the API, which is where I found those variables I mentioned. Had little idea how they were put together and you've given me a hint on how that works.

I've also been going through your TUTORIAL thread, though that was mainly at work so I was usually distracted by calls every few minutes or so, which makes absorbing it a bit difficult sometimes. Maybe next "weekend" (my days off are during the regular workweek) I can try puzzling it out. Or next few weekends. O_o;;

Thank you for the info. I'll have to see if it's a game-breaker or just a real big challenge next chance I get.
 
Ok, you're definitely looking to do more than just add one ready-to-use game feature. You're looking to develop a mod, basically. First make sure you know your Python.

I think you should hook your code up in CvEventManager instead, probably in onBeginGameTurn. Then fire the code on random turns with:
Code:
if iGameTurn % gc.getGame().getSorenRandNum(iProbability, 'event') == 0:
(iProbability is of course the one in whatever chance of the event to take place.)

You should probably create your own Python module for testing and development. Then you can import the module in the Python console and run your code. Later you could just hook the finished work up in the Event Manager by importing the module and making a function call.

Perhaps, but if I was going to simulate a disease spreading rapidly across the globe, I'd probably have to put limiting variables, like flight (or, since I'm using Rise of Mankind A New Dawn one of the more advanced flight techs) ability, openess of borders (the UN Resolution force open borders can become a worldkiller) and a few other things, maybe an airport building on every landmass with a city. Maybe pick one of the ultra-advanced medical techs the obsolete tech.

Plus, I only want this to happen once, not be a recurring thing so a random event with the appropriate flags seemed more logical.
 
Plus, I only want this to happen once, not be a recurring thing so a random event with the appropriate flags seemed more logical.
You can have any conditions you want, so just go for it. But I still doubt you need to make your own "random event" - just make sure the code only fires once. In the Event Manager:
Code:
if [B]not bFired[/B] and bCondition1 and bCondition2 and bCondition3:
    bFired = True
    #add your event code or function call here
(bFired has to be assigned a False value at the __main__ level however.)

AFAIK random events (the BtS feature) are done in C++ with settings in XML and with interface in Python. It would hardly be worth the effort... You can just add your own popup message instead. (Covered in the tutorial, also.)
 
AFAIK random events (the BtS feature) are done in C++ with settings in XML and with interface in Python. It would hardly be worth the effort... You can just add your own popup message instead. (Covered in the tutorial, also.)

On the other hand, why recreate everything that the random events already do for you?
 
On the other hand, why recreate everything that the random events already do for you?
What exactly are you proposing then? Please exemplify.
 
I'm proposing that it may be a good plan to use the existing event system instead of recreating chunks of it in Python. Just using the existing event stuff to trigger the event would be easier and less error prone than coding all of the checks himself if the desired condition(s) that trigger it are already part of the event trigger XML. If the event is triggered by a player, the player gets a pop-up. If the event is triggered by an AI the player(s) see the message set to be shown for everybody. In your system, what does the player see if the conditions happen for an AI or different player? You'd have to specifically program something - something that is already programmed for you if you use the event system.

The actual effect of the event would still have to be in python since I doubt that the desired effects are present in the in the existing event XML data.

You said:
Code:
if not bFired and bCondition1 and bCondition2 and bCondition3:
    bFired = True
    #add your event code or function call here
Well, those bCondition1, etc., values do not check the conditions and create themselves - you have to code what they are and it all has to be checked every turn when it can happen (which is why you should really put the "not bFired" check in a different "if" statement that contains the whole rest of the thing so you don't check the conditions anymore after it has happened, if going with the manual Python method instead of the event method). On the other hand, if you use the existing event trigger stuff then the conditions do, in some sense, just check themselves - you don't have to code the checks yourself (and the checks are done in the DLL rather than in Python, which is going to be a little faster).

Which is all just the long version of "if the existing event system can do it, why recreate part of that system in Python?"
 
I've never even looked closer at the present event system as I thought it would involve both C++, Python and XML to use it. Is there a guide or something available for this? (To have the event system fire custom Python code from XML settings, that is.)

Regarding my conditional statement example, I believe that with the setup I proposed (several conditions separated by and logical operators) isn't going to check every boolean if one fails. So if bFired == True then bCondition1 and the others won't even be processed. Having separate if statements isn't necessary - but could possible make the code easier to read.
 
Events don't involve C++. The existing events are mostly XML with some having Python for various purposes. The event trigger XML entries have 4 different Python calls that can be used, the XML values for each specify the name of the function in the CvRandomEventInterface.py file that is called (3 CanDo type functions and a callback that is called when the trigger is triggered). The event XML entries also have 4 Python function name fields (a CanDo, a help text generator, an expiration check, and a callback that is run when the event happens that is used by the regular BtS events to implement additional effects that there are no specific XML tags for).

There are multiple references, including Solver's Guide to Event Modding in BtS.

As for the condition nesting, I was thinking of conditions that are not single statements - like things that would require looping over cities or players to count things or check for various situations (perhaps a plague only starts when each player has a city that has at least 2 points of unhealthiness above its health total and the total unhealthiness points from all cities of all players added together is above some threshold). You could put the conditions into a separate function that returns a True or False and call the function in the "if", I suppose. There is always more than one way to do things.
 
Oh, man. I was completely in the dark about how the random events actually work.
 
Still here. Middle of my work week. I did manage to test the script. Ran into an error, but I forgot to initiate logging so I'll have to do that again. All I can tell is that when I removed:

pCity.setCulture(0)

From the script and reran it it worked fine. (If you call mass death "fine" but that was what it was supposed to do.) Again, I'll have to activate logging and find out what error it's giving.

The effects were not quite what I expected. Production and commerce were down because there weren't as many people working the tiles, but I controlled multiple holy cities and Civ Jewellers (which seems to give a profit when spread) and had spread them around so money wasn't quite the problem. However the turn before I ran the script I'd had to set my tax rate higher, but then I realized things like Civic maintenance was based on population. As of now as the population increases I'm watching the gpt levels go down.
 
Oh, my bad. Of course you have to specify what culture you set. :rolleyes:
Change it to: pCity.setCulture(pCity.getOwner(), 0, True)

The last parameter is bPlots (according to the API) so I guess you can set it to False if you don't want all borders to shrink also.
 
Hmm. Okay, I'll have to try it later. Got embroiled in a minor war with Genghis Khan... and one of my defensive vassals is tossing nukes all over the Mongol Empire. Not quite what I want at the moment.

:eek:
 
Top Bottom