Determining Argument Lists for Events

trystero49

Prince
Joined
Apr 30, 2012
Messages
515
I'm trying to make a mod to remove embarkation from a unit, and it looks like I'll need to attach code removing this onto four different events to cover all the bases:

ActivePlayerTurnStart
SerialEventUnitCreated
SerialEventUnitMovetoHexes
UnitSelectionChanged.

Of course, not all of these events fire on the AIs turn, but I'll have to work out what I should do for the AI later.

Anyway, I've made some unpack functions to determine what the argument list is for these events. The unpack function lists a bunch of numbers and boolean values (except APTS, that seems to have no argumnets). I don't understand how I'm supposed to deduce some of these values. I'm pretty certain that the first value in most of these events is "PlayerId", since it always returns 0 no matter what. However, other values have numbers like "8192", and I can't possibly imagine what that number might mean?

Does anyone have any tips or pointers on how to work through this?
 
Hello.

There are three ways to deal with this problem:
* The one you used: subscribe to the event and use unpack(arg)
* The "search in all files" tool, using Notepad++ for example, to see how this event is used in the game. This is the prefered way when available.
* Use a tool like PEExplorer to browse the binaries' asm code in a convienent way. This is the most painful way (not as painful as it may sound though) but sometimes the only available one.


Teaser: And soon you will be able to browse the new CF wiki.
 
First of all, most of those events won't do what you want.

Of course, not all of these events fire on the AIs turn, but I'll have to work out what I should do for the AI later.

BAD idea. If you can't get it to work for the AI now, it's unlikely you'll be able to get it to work for the AI later, because the tools we've been given are just extremely limited. Most Serial events are UI-related, and so have behaviors that often heavily skew toward the active player, but there's almost never a corresponding GameEvent. Some of these serial events only trigger if the active player SEES the triggering event, so SerialEventImprovementCreated won't trigger when an AI on another continent builds an improvement, but WILL trigger once you move a scout into the area a few thousand years later.

Now, SerialEventUnitCreated DOES work for all players, even the ones hidden from view. However, as I said, it's UI-related, which means it doesn't trigger whenever a unit is created, it triggers whenever a unit's ARTWORK is created or modified. That means when it's created, sure, but it also triggers whenever a unit embarks or disembarks (since that changes the artwork), rebases, upgrades, or a few other things along the same lines.

You can reduce this load a bit by simply checking a unit's "birth date" against the current turn number; the chance of those other triggers occurring on the first turn are fairly slim, so it'll likely only trigger once. But there's a way to be even MORE sure of a single trigger, which I've used for my own mods: a "Rookie" promotion. That is, whenever SerialEventUnitCreated is called, check if the unit has the Rookie ability. If so, do nothing; if not, give the unit the Rookie ability, and do whatever on-created effects you want. Then, remove the Rookie promotion at a later date, whenever you feel like it; in my mods, I removed it after the unit's first combat, so there's really no possible way to duplicate the effects unless your unit starts the game with the ability to move after attacking AND tries to embark after making an attack out of its home city. Very, very unlikely, but you could also just do it during the following turn's start-of-turn event.

Now, it also depends on what you want the event to do. If it's only removing a promotion, then you don't care if it triggers twice for the same unit. You only run into problems with SerialEventUnitCreated if the effect is something stackable, like +10 XP.

However, other values have numbers like "8192", and I can't possibly imagine what that number might mean?

Generally, that's a Unit ID (or City ID, for certain events) number. Unit IDs are unique for a given player; that is, you can only have one unit #8192, but each player can (and often will) have their own #8192, so you have to use the Player:GetUnitByID() function. (And just so you know: 8192 is 2 to the 13th power, so you can guess which bits are being used to store unit IDs...)
 
That means when it's created, sure, but it also triggers whenever a unit embarks or disembarks (since that changes the artwork), rebases, upgrades, or a few other things along the same lines.

Unfortunately, this doesn't cover all the bases. I want to remove embarkation from a unit, and SerialEventUnitCreated doesn't fire when embarkation is awarded. If I were to move a unit from outside territory into my borders, it would get the Embarkation promotion and SerialEventUnitCreated won't fire; makes sense, since the artwork doesn't change. (Thank you for that information btw, I did not know that it was dependent on changed artwork).

That's why I wanted to attach this code to the other events, because my unit would be available before optics. I figured I'd need to attach code removing embarkation from a unit every time a unit moved. There are also cases when a unit is created before optics but is in borders when optics is researched (although not at the start of turn; e.g. the tile it is on can be bought during the turn). So I figured I'd need to add this code every time a unit was selected. But then the UnitSelectionChanged event doesn't fire when there is only one unit. So I'd need to do it on the start of a turn, although that wouldn't really help in the case where there is one unit standing on a neutral tile that is bought by the player and then moves that unit out of the territory into other neutral territory....yeesh, this is getting to be a real nightmare.

Maybe I would be able to make a promotion that is mutually exclusive with Embarkation, so that Embarkation does not award automatically? Then I could probably just attach the remove promotion code to SerialEventUnitCreated, because that should cover all the bases.

Also, thanks for the advice on making sure it works for the AI first. It was bad problem solving practice on my part.

I also did notice that 8192 was a power of 2, but because I am a beginner at computer programming I did not know what significance to place on it (other than the special significance of powers of 2 to binary).

Also, Don Quiche, thank you for your advice on how to unpack events. Do you know of any freeware alternatives to PEExplorer? Thanks.
 
Also, Don Quiche, thank you for your advice on how to unpack events. Do you know of any freeware alternatives to PEExplorer? Thanks.
Well, it depends on. Do you want one that work or not? :D
If "it has to work" matters for you, then I only know PEExplorer (note that it has a 30days free period). However I can name plenty of tools that crash miserably. Well OllyDbg works but it is far less convenient. You need a tool to show you the asm code, the strings, than can find references to any address and to navigate across addresses.

Also, even PEExplorer only works with the dll files. The exe files seem to have something special that make most tools fail. Unfortunately, the events themselves are probably defined in the exe now that I think about it.

EDIT: Well, IDA has a freeware edition. Didn't test it, though.
 
I just downloaded the IDA freeware and it works fine. I can disassemble the .dlls and read it, but it probably lacks some features that more experienced people would want.
 
Back
Top Bottom