• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

Dom Pedro's Mod Helper for Python Modders

I have not tried that mod, but I just looked at the doc in the download page.

Does it allow hover help for the action button?

Does it keep a MP game in sync, ie does it go through ModNetMessage?

I think both of those are requirements to be useful.
 
I have not tried that mod, but I just looked at the doc in the download page.

Does it allow hover help for the action button?

Does it keep a MP game in sync, ie does it go through ModNetMessage?

I think both of those are requirements to be useful.

Well, a direct merge of the code will not be possible, so some changes are going to have to be made. It does already make use of tooltips. I'm not sure about the second point, but even if it creates problems with MP games, I'm sure it can be corrected.

The main thing I'm struggling with now is the fact that I want to be able to have interfacemodes for the action buttons, but I don't think that'll be possible.
 
By coincidence, TC01 has traced through Gods Of Old to understand how to use the python pick plot interfacemode. I have made this work using python, and also figured out how to fit in canPickPlot. Please see this thread.
 
By coincidence, TC01 has traced through Gods Of Old to understand how to use the python pick plot interfacemode. I have made this work using python, and also figured out how to fit in canPickPlot. Please see this thread.

Hmm... yes, indeed. Just went through the enums, and there is indeed an INTERFACEMODE_PYTHON_PICK_PLOT. In order to get this particular part of the code to work, it might be necessary to handle more of the code in python than I was anticipating. Might be better to let modders add their own buttons if they need to pick a plot.
 
In order to get this particular part of the code to work, it might be necessary to handle more of the code in python than I was anticipating. Might be better to let modders add their own buttons if they need to pick a plot.

Perhaps you could just provide a unit-specific override to canPickPlot, and a unit-specific function to call after successful selection of a plot. The rest of the wiring is there. I suppose as an additional point, you could allow creation of an overlay of a given radius as a display aid, but canPickPlot would still be needed to accept or reject plots within the radius.
 
Perhaps you could just provide a unit-specific override to canPickPlot, and a unit-specific function to call after successful selection of a plot. The rest of the wiring is there. I suppose as an additional point, you could allow creation of an overlay of a given radius as a display aid, but canPickPlot would still be needed to accept or reject plots within the radius.

Unfortunately, that's not going to work. The "canPickPlot" and "onPlotPicked" methods aren't called from the SDK or python, which means we have no way to have the game pull from different methods.

But the bad news doesn't stop there either... There's nothing to connect the picked plot to the unit that was picking the plot. They do it in Gods of Old and Afterworld by storing the unit's id and the button pushed. But I think that could get ugly on multiplayer...

Alternatively, there may be one other possible solution... there is a function in the SDK to set the interfacemode, and another to retrieve what I'm assuming is the picked plot selected via that interface mode. Of course, it does also mean that there won't be any way to have the tile greyed out if it's invalid. You'll have to simply guess if it's right or not.
 
Well, the action buttons code has been successfully merged into this modcomp, but the interfacemode part is remaining elusive. I'm cursing whoever was responsible for designing that part of the game. There's simply no good way to get the plot selected. Sure, there's a python method that gets called that you can mess with, but there's no way to pass addition information to it besides the plot itself. I'm honestly baffled that they didn't find a better way to do this...
 
I really do not think that storing data locally (like GOO) will cause MP OOS problems. I am certainly not an expert on MP, but I read the guide about it and it describes that any code directly executed by an action button is private to each machine. Once you have users clicking buttons, you need to publicize the action using SendModNetMessage. So I think the GOO approach of storing some global data is actually OK.
 
Good news, everyone! It's working now!

Thanks, davidlallen. I didn't store the data in python like they use in the other mods, but it occurred to me as I was reading your post that calling the currently selected unit in the onPlotPicked method (and the canPickPlot method) without it being a problem. I think people are going to have to rigorously test this to see if I've somehow missed something, but it looks to me like this should work.

So the ActionButtonInfos have five python tags:
PythonCanDo
PythonCallback
PythonCanDoAtPlot
PythonCallbackAtPlot
PythonHelp

This is nice because it keeps with the original idea of modders just having to make small self-contained methods rather than slogging through the rest of the python code.
 
How would you suggest AI_unitUpdate and AI_chooseProduction being controlled from the XML though?

For AI_unitUpdate, I see you have provided unitinfos PythonDoTurn. But, I imagine this is in *addition* to whatever movement the AI makes for the unit as part of the normal turn. I have many units for which I have written the movement logic in python. AI_unitUpdate returns true or false, true if I have made a move, false if I couldn't find anything and I want the normal AI to move it. Can you add this callback? My AI_unitUpdate gets messy with a big set of if-statements to get to the right unit type, and it is hard to merge individual units into another mod.

For AI_chooseProduction, what I want to do is override the decision that a city makes, about what unit to build next. I am not sure how to "hang" this off a python callback defined in XML; I guess I need to think about that more, unless somebody else has a good suggestion.

The callback method for a particular civic is called both when it's being activated or deactivated (along with specialists, religions, promotions, etc.) One of the arguments passed to the python method is the integer "iChange", which is either a 1 or a -1 depending on whether you're switching to or switching from a particular civic.

Please make this more clear in the documentation. Rereading your example #1 for the third time, I finally spotted the "iHappiness * iChange", but only after you told me in this thread. In addition, a prototype for each function would be helpful as a quick reference.

Other thoughts ...

onImprovementBuilt is very helpful, corresponding to ImprovementInfo PythonCallback. I suppose it would also take iChange, called with -1 when the improvement is destroyed. It is important to note a "bug", or design philosophy anyway, for improvements. There is onImprovementDestroyed; but this is *not called* when an improvement is built over. If I build improvement A, and later build improvement B on the same plot, A is destroyed but the onImprovementDestroyed event is not generated. I would call this a "bug", but the destroyed routine may be intended to give a pillage bonus, and building over an improvement should not generate that. I worked around this for my particular case, but in general if some benefit is given when an improvement is added, it should be removed when the improvement is built over.

One challenge for calls to AI_unitUpdate is that you may want to add, or delete units during the call. For example, a unit may wish to delete itself, or convert itself into another unit which is both a delete and an add. Doing this during the AI movement loop is a big no-no. You get inconsistent results and occasionally huge runtime. I do not understand the details of why, but generally, you should not modify a list while some other routine is in the middle of iterating it. I am not sure if other modders have had this problem.

In both of my large python projects, I have had to maintain a separate list object, of "unit add/delete to process after the AI loop". So my code for an AI_update may wish to delete the unit; instead it calls a subroutine to add the deletion request onto this list. Then in my onEndGameTurn, I walk through this list and perform the adds, conversions and deletions and empty the list.

So if you do provide a nice hook for AI_unitUpdate, you may wish to provide this type of list. It would be more of a convenience than a necessity, I suppose, because the author can always put their own list and onEndGameTurn. But it took me a while to figure out why I was getting inconsistent results and/or long runtime; so other modders may run into the same problem and give up on python without understanding why.
 
For AI_unitUpdate, I see you have provided unitinfos PythonDoTurn. But, I imagine this is in *addition* to whatever movement the AI makes for the unit as part of the normal turn. I have many units for which I have written the movement logic in python. AI_unitUpdate returns true or false, true if I have made a move, false if I couldn't find anything and I want the normal AI to move it. Can you add this callback? My AI_unitUpdate gets messy with a big set of if-statements to get to the right unit type, and it is hard to merge individual units into another mod.

I just added it.

For AI_chooseProduction, what I want to do is override the decision that a city makes, about what unit to build next. I am not sure how to "hang" this off a python callback defined in XML; I guess I need to think about that more, unless somebody else has a good suggestion.
Yeah, I'm still not clear how that would be different from the current python method, so I'll need more info before I can create an alternative.


Please make this more clear in the documentation. Rereading your example #1 for the third time, I finally spotted the "iHappiness * iChange", but only after you told me in this thread. In addition, a prototype for each function would be helpful as a quick reference.

I've included examples of each of the python methods in the python file with all of the parameters being passed to them from the SDK. I have not, however, included methods that actually do some sort of change.

I am currently working on improving and expanding on the initial tutorial, so stuff like iChange and better explanations of the tags and how it all works together is being included.


onImprovementBuilt is very helpful, corresponding to ImprovementInfo PythonCallback. I suppose it would also take iChange, called with -1 when the improvement is destroyed. It is important to note a "bug", or design philosophy anyway, for improvements. There is onImprovementDestroyed; but this is *not called* when an improvement is built over. If I build improvement A, and later build improvement B on the same plot, A is destroyed but the onImprovementDestroyed event is not generated. I would call this a "bug", but the destroyed routine may be intended to give a pillage bonus, and building over an improvement should not generate that. I worked around this for my particular case, but in general if some benefit is given when an improvement is added, it should be removed when the improvement is built over.
Ok, I've added a callback for improvements that should be executed whenever the specified improvement is added or removed from the tile regardless of whether it's pillaged or not.

One challenge for calls to AI_unitUpdate is that you may want to add, or delete units during the call. For example, a unit may wish to delete itself, or convert itself into another unit which is both a delete and an add. Doing this during the AI movement loop is a big no-no. You get inconsistent results and occasionally huge runtime. I do not understand the details of why, but generally, you should not modify a list while some other routine is in the middle of iterating it. I am not sure if other modders have had this problem.

In both of my large python projects, I have had to maintain a separate list object, of "unit add/delete to process after the AI loop". So my code for an AI_update may wish to delete the unit; instead it calls a subroutine to add the deletion request onto this list. Then in my onEndGameTurn, I walk through this list and perform the adds, conversions and deletions and empty the list.

So if you do provide a nice hook for AI_unitUpdate, you may wish to provide this type of list. It would be more of a convenience than a necessity, I suppose, because the author can always put their own list and onEndGameTurn. But it took me a while to figure out why I was getting inconsistent results and/or long runtime; so other modders may run into the same problem and give up on python without understanding why.
I have to think about how I want to do this, but it sounds like a generally good idea. It's on my to-do list.
 
I've posted version 0.3.

In it I've added the ability to easily and quickly make new Action Buttons complete with the plot picking interface that was giving me trouble earlier in the thread.

Enjoy! And let me know when somebody releases a mod that makes use of this!
 
Is there a way to make the AI use any action buttons added? I'm thinking of using this for some stuff in my Eugenics Wars scenario.

Well, that's an interesting point... Yes, it's possible to use the PythonAIUpdate tag that I've added in by request to script your own AI behavior including having it use the action buttons.

But would it perhaps be better for me to eventually tackle this in the SDK and add code there? I'm not sure if it's worth the effort. But also considering that the actual effects of the action buttons are controlled in python, there's really no way for the AI to evaluate the actionbuttons based on what they do.
 
Honestly I would say leave it to be controlled by the AIPython fields, for precisely your stated reason, the AI has no clue what it actually does, so doing anything other than saying "Always perform any action available" would be hard, and you would need the same amount of python override use to prevent using at the wrong times as to force using ever.
 
So we've used this kind of setup in FfH based mods for quite a while in more places than events, but someone just revealed an even better method for using them. It essentially makes python modular :)

How to import a file and call a function with eval

Could be worth including in your documentation for people to use :)
 
So we've used this kind of setup in FfH based mods for quite a while in more places than events, but someone just revealed an even better method for using them. It essentially makes python modular :)

How to import a file and call a function with eval

Could be worth including in your documentation for people to use :)

Hmm... this would require more than just including in the documentation. I would have to go back and redo some of the code. This might be worth doing.
 
I was in the process of merging this with another component and I noticed two other commented blocks (specifically titled PoliticsMod and Factions). I wasn't sure if these needed to be included or not for the PythonDLL to work (I wasn't sure if they were a type of precourser to the PythonDLL as some of the PythonDLL blocks end with PoliticsMod End).
 
Back
Top Bottom