PyScenario: Beta version release

Baldyr

"Hit It"
Joined
Dec 5, 2009
Messages
5,530
Location
Sweden
IMPORTANT! PyScenario is only supported for the RFC Epic/Marathon mod-mod. Plans to port it to the official version of Rhye's and Fall of Civilization or to other mods are suspended.

Also note that PyScenario scripts for Beta v1 are no longer supported! See the FAQ section of the documentation for how to run old scripts with the new version. There is no up-to-date change log or no guide for converting old scripts.


Download the current Beta version via the link below! No new versions are currently planned, but please report any bugs or other errors anyway in this thread!
Current version (2011-09-03): Beta 2.2 for Beyond the Sword v3.19 and RFC Epic/Marathon v1.22.

Changes:
Spoiler :
v2.2:
It is no longer possible to spawn wonders that are already built with the buildings() Action.
The units() Action now also works without any map target and will instead spawn the units in the capital.
The tech() Condition has been augmented with another setting.
The terrain() and erase() Actions include settings for adding/removing sign labels on the map.
v2.1:
Triggers are now automatically rebuilt when Python is reloaded.
Trigger looping has been prevented, so that a Trigger can't cause itself to fire once more.
Storing Triggers for save games has been integrated with the RFC mod making the process more streamlined.
A Trigger causing a Python exception will be automatically disabled.
The convert() Action takes a couple of new settings.

New additions:
Spoiler :
v2.2:
PyScenario can now be used with mod-mods which have their own mod folder, as the working folder is dynamically detected.
The new rebirth() Action grants Golden Ages.
v2.1:
The new area() and random() methods are used for global Trigger settings.
The new Condition is present() and the new Actions are strike(), commerce(), reset(), respawn() and civics().

Known issues:
Spoiler :
n/a

Corrected issues:
Spoiler :
v2.1:
An invalid Scenario module results in no Triggers being initialized.
Missing code added to the units() Trigger method.

Questions & Answers

What is PyScenario?
It is a set of Python code that enables non-programmers to script complex scenario events. Learn more in the main thread - full documentation with examples and tutorial included.

Can anyone - even a non-programmer - help out with testing?
Sure, but you're required to use the built-in debugging features in CivIV! Read more here. Any knowledge of Python or experience with CivIV modding is helpful, but not required.

So I think I found a bug, what should I do?
Post your findings in this thread! Note that comments like "my script isn't working" or "the application is broken" is not valid feedback. Follow these guidelines when submitting bug reports:
  • Make sure you are using the current version of PyScenario before submitting a bug report. If in doubt, download the latest version.
  • Include the line of code that isn't working for you - or better yet - include your entire script!
  • Be sure to include the full traceback (text) on any Python exception (error-message)! If you can't figure out how to debug, then you're not qualified to be a beta tester!
  • Do your best to describe what you intended to do, how you went by doing this - and what exactly the result was.
  • Post a screen caption or a save if possible. (On a PC system, hit the Print Screen button and the image will end up in your \My Documents\My Games\Beyond the Sword\ScreenShots\ folder. Auto-saves are found in \My Documents\My Games\Beyond the Sword\Save\single\auto\.)
 

Attachments

  • PyScenario.zip
    36.6 KB · Views: 367
I just uploaded a slightly updated version of the beta release. Please download it from the original post and use for testing! The change log is also updated.

No new features are included in this update and no actual errors have been corrected. Loading time in between turns - that also applies to autoplay - is however reduced with as much as 40%! Lag is still an issue though and any suggestions from resident programmers as to how the code can be streamlined would be appreciated!

Also, I stumbled on a C++ exception myself while testing something else (timing lag to be more exact), but I haven't been able to duplicate it myself. (I ignored the exception as I thought it would surely pop-up again, but strangely it hasn't.)

I believe it had something to do with the fact that I used a Trigger without any target Civ to spawn units - without specifying any unit type. This sort of thing is kosher however, since the application will automatically assign a target Civ and a suitable unit type in such instances! :eek: This one time there was an exception about there being a None type supplied as an argument instead of the required integer value, but I can't remember what CvPython method it was concerning.

I believe this learns one to save all exceptions (error messages) as they appear... :rolleyes:
 
(Continuing from the main thread.)

Bug found, these lines didn't work as planned when the Vikings entered the Renaissance:

Code:
#Vikings
Trigger(iVikings).tech(eEra=con.iRenaissance).name("Stockholm","Birka")
Trigger(iVikings).tech(eEra=con.iRenaissance).name("Kjøbmandehavn","Roskilde")
Did I screw something up at some point?
Oops! I'm looking at the code and just realized that the tech() method isn't even connected to the Event Handler. :rolleyes: My bad! :p (I can't figure out where the call has gone... :confused:)

This means that the tech() Condition would be checked somewhat randomly and that the results of those checks would be invalid. (In my test the Trigger fired when the Vikings were still in the Middle-Ages. :crazyeye:)

I'll get to work on this and will make sure to test it properly before the next update. Thanks for getting me on the trail of this bug! :goodjob:
 
(Continued from the main thread.)

I'm in the mid 18th century now and time between turns seems to be increasing very fast. Shouldn't lag affect less as time goes on, as triggers get discarded?
I'm looking into the lag issue right now, but you are correct. It could be something else causing the wait, though... But I might end up deleting expired Triggers altogether in the future, because they are still checked every time - whether or not they are expired. :p

Right now I'm looking at an issue where code spawning units (CyPlayer.initUnit()) is causing other Python code to slow down. It has probably something to do with the C++ code that is being activated in order to create a new Unit instance and issues with doing both things at the same time. (Next I'm gonna try out creating the units last and see how this affects lag.)

The good news is that my preliminary timing of the PyScenario processes is revealing very little lag caused by my own code! :goodjob: But its still some time in the future when everything will be fully optimized.
 
By the way, if anyone has a bug or other issue you could attach or send a save game. Because all the Triggers should be saved along with the game. (The actual Scenario module also helps, of course, but is not necessary for other than reference.) Then I could do some debugging and time lag and whatnot.
 
Breakthrough! I believe that I have located the cause for the lag I've been trying to pinpoint. It turns out it was a function call to the RFCUtils module (part of the RFC mod) that involves un-pickling a certain stored value. Since the Scenario module I was using for debugging caused a lot of these function calls there was something like 4 seconds of lag between turns.

Now I'll have to find a work-around for fetching this pickled value (used in determining random minor Civs where the ePlayer setting has been omitted in the Trigger constructor). But come next update I can almost promise that the lag issue will be solved! :goodjob:

(I've been working extra hours all weekend so expect an update in about a week or so. If more work doesn't land in my lap, that is. :rolleyes:)

edit: The pickling issue seems to be bigger than I initially realized. It turns out that PyScenario is really slowing down the RFC mod itself, because I've used its script dictionary to store the all the Triggers (in order for them to be saved alongside with the game session). Now I must find a work-around for saving this information without causing RFC to lag. :rolleyes:
 
Do the triggers have to be saved with the game session? Why can't the game just load the triggers again the same way it would load any other python when the game starts?
 
Do the triggers have to be saved with the game session? Why can't the game just load the triggers again the same way it would load any other python when the game starts?
I considered this also, but since Triggers can expire (and thus change during play) they need to be saved along with the rest of the game session.

The lag issue is however taken care of now. :goodjob: I'm working on a new version right now.
 
A new version has been uploaded - and can be downloaded from the first post. :goodjob:

This update should take care of all the lag issues, but since its a major overhaul of the code there is bound to be a mistake or an unforeseen outcome somewhere... (The last minute changes will always get you!) Please download and test!

Also, the flip() method has gotten a new argument that with the default setting saves Civs from automatically collapsing after losing cities to a city flip event. Civs can still collapse from instability though, but there is a new stability() method for adding or subtracting Stability points.

By the way, the tech() method now only recognize major Civs - Techs assigned to minor Civs will not trigger anything at all. Assigning starting Techs at spawn isn't recognized either. Both were potential causes for lag and should be taken care of.

I'll make sure to update the API entries for these methods!

Note that autosaving during autoplay no longer saves any Triggers! This is implemented in order to make autoplay quicker. (The best way to speed it up is still to disable autosaves entirely, though.) This also means that the initial autosave file doesn't contain any Triggers. Once the autoplay stops all Triggers will of course be saved along with the game, as usual.
 
Another major update is available from the original post. This time its mostly new content so be sure to check out the change log and the documentation in the main tread!
 
Why version 1.021 (used in your scenario) is not posted? :p
Why city naming goes wrong in my version? (I copy files into Python folder and start as Rome. Everything is OK. I settle Roma and reload. I add Trigger().check().valid().target() to scenario. Game loads Python and I settle Roma... but it's not Roma- it's Cumae. Melpum flips to me and the name doesn't change to Mediolanum). I delete what I've added to scenario but bug says on. I delete three files and put back orginal eventhandler and it's still buggy. When I turn off and on game everything is normal again)
 
Why version 1.021 (used in your scenario) is not posted? :p
It only contains a minor bug fix that will be included in the next update (v1.030). I honestly thought I'd be able to post it last weekend, but I added some more stuff last minute.

Why city naming goes wrong in my version? (I copy files into Python folder and start as Rome. Everything is OK. I settle Roma and reload. I add Trigger().check().valid().target() to scenario. Game loads Python and I settle Roma... but it's not Roma- it's Cumae. Melpum flips to me and the name doesn't change to Mediolanum). I delete what I've added to scenario but bug says on. I delete three files and put back orginal eventhandler and it's still buggy. When I turn off and on game everything is normal again)
What happens is that there was a Python exception during the game turn, and that also disables Rhye's CityNameManager module.

Also note that if you change any of the .py files during gameplay, then all your Triggers have been deleted. You need to reload then into memory manually (press shift + alt + R).

Your bug report is not complete however - so I wouldn't be able to know what happened. Refer to the first post in this thread about reporting bugs. Also, make sure to enable debugging!

Thank you for reporting on this issue, by the way! :goodjob:
 
There are always exceptions when files are changed during gameplay? It's really annoying. Especially when you try to learn by trying to do anything.
No, exceptions are error messages. This means that the Python interpreter can't make sense of your changes and will simply quit. There is no exception if your code is valid.
 
What should be the last big update of the beta-version is now available from the original post. The focus will from now on be on finding and fixing bugs and on improving things that are already in. (New Condition and Action methods can of course still be requested by beta-testers.)

Beta testing has entered the final stage and I will now be joining in myself. Expect bugs to be found and stomped out. :D
 
Doh! It seems I messed up while updating and that the PyScenario.py file has the wrong version number (1.022 instead of 1.030). :rolleyes:

So I changed the original post to reflect this: The current version is now 1.022 and not 1.030 - and the next one will be 1.031 just to avoid any more confusion... :p
 
Is it (or is going to be) possible to change city population by command? Or at least ensure that with flip() command a city won't be autorazed?
A migrate() Action, or something like it, would actually be helpful. It could be used to add or subtract population in a city.

Regarding razing cities, this seems to always be the option of the Civ receiving a city - whether or not to keep it that is... But I'll take a look at Rhye's code to see whether or not he uses another method or something. :p
 
Top Bottom