fuzzie Posted August 13, 2010 Share Posted August 13, 2010 The last (ok, optimistic, but I can hope) hugely broken thing in the GemRB scripting code is the trigger code. At the moment, GemRB just keeps some objects around in every scriptable object (actor, door, etc) for things like LastAttacker, checks them, and every time a trigger references one of those, it is set to be wiped after the action queue for that actor is processed. This is obviously a huge source of bugs. And is terrible. Oh, despair. It's pretty difficult to tell exactly what's going on from just poking at the original engine, too. ToBEx's source (much love!) is more helpful; I see that there's a trigger list there as well as a list of objects (and our friend labelled as the attack type), and it says that triggers are checked with comparison for 0x0-style triggers and in a more complicated manner for 0x4-style triggers. Can anyone shed more light into this? I haven't found any good clues in the forum history. In particular it would be helpful if anyone had any idea how (a message? a flag? always?) and when (end of frame? if flagged? in the message execution?) the triggers are removed. Link to comment
Ascension64 Posted August 15, 2010 Share Posted August 15, 2010 I only have a preliminary understanding, but I think trigger opcodes 0x0XXX check if a SetTrigger has been made on the scripted object. Used for things like AttackedBy(), HitBy(), Heard(), etc. They check the object specifiers [EA.GENERAL.CLASS.all that] match that in the script. If so, it returns true. This is because whenever a scripted object is attacked for example, the attacker sends a MessageAddTrigger that will be attached to the target. If you take an excerpt from CGameSprite class (scriptable object): Object oAttacker; //42h, for AttackedBy() trigger, for LastAttackerOf triggerid DWORD nType; //56h //ASTYLE.IDS from AttackedBy() //DAMAGES.IDS from HitBy() Object oCommander; //5ah, for ReceivedOrder() trigger, for LastCommandedBy triggerid Object oProtector; //6eh, for ProtectedBy triggerid Object oProtectee; //82h, for ProtectorOf triggerid Object oTargetor; //96h, for LastTargetedBy triggerid Object oHitter; //aah, for HitBy() trigger, for LastHitter triggerid Object oHelpShouter; //beh, for Help() trigger, for LastHelp triggerid Object oTriggerer; //d2h, for trigger in SVTRIOBJ.IDS, for LastTrigger triggerid Object oSeeer; //e6h, for LastSeenBy triggerid Object oTalker; //fah, for Said() trigger, for LastTalkedToBy triggerid Object oShouter; //10eh, for Heard() trigger, for LastHeardBy triggerid Object oSummoned; //122h, for Summoned() trigger, for LastSummonerOf triggerid Let's say A attacks B. I presume that when A is given an action to attack B, it will send a MessageAddTrigger, so that B.oAttacker is set to the object specifiers of A. If B has a script that AttackedBy(id), id will be checked against B.oAttacker. If the object specifiers are the same, then the trigger will be true. I am not sure when these triggers are cleared. Trigger opcodes 0x4XXX, parse independently. They check everything else in the game. Take with a bunch of salt, of course! Link to comment
devSin Posted August 15, 2010 Share Posted August 15, 2010 I don't think stored objects are ever cleared (is that what is asked here?). A lot of hardcoded stuff will set them, so they change frequently, but I think the current value persists until the next update. Maybe through master area transitions? But I don't think it would matter even if they got cleared then. So they init to null on game load (or new object load), and then accrue values throughout the session until the next reload. Link to comment
Avenger Posted August 16, 2010 Share Posted August 16, 2010 Huh, i always assumed triggers get cleared eventually. But found no code (didn't look for it intentionally). So, i guess, if there is no evidence triggers are ever cleared (unless processed), then i don't have to look for this This stuff is difficult to test, because there is no way to know if a trigger is set without clearing it. Link to comment
Ascension64 Posted August 16, 2010 Share Posted August 16, 2010 This stuff is difficult to test, because there is no way to know if a trigger is set without clearing it.I ran some quick tests using a debugger. It appears the triggers are truly never cleared. It can only be overriden by a new trigger. Link to comment
Avenger Posted August 16, 2010 Share Posted August 16, 2010 This stuff is difficult to test, because there is no way to know if a trigger is set without clearing it.I ran some quick tests using a debugger. It appears the triggers are truly never cleared. It can only be overriden by a new trigger. Overridden? What does that mean? My current understanding is that there could be 2 AttackedBy triggers on the queue. Link to comment
fuzzie Posted August 16, 2010 Author Share Posted August 16, 2010 I think maybe you two are being confused by the triggers vs the objects? The objects are not so interesting. They are indeed kept around; I already had to add a bunch of hacks to GemRB there to make SoA completable, otherwise scripts are (obviously) left using incorrectly-cleared objects. But there's no clear way to see how/when the triggers in the list are cleared. I'm pretty sure HitBy doesn't return true for the entire life of an object, and I'm also pretty sure it doesn't stay true for hours if it's not checked before then. My current plan is to make *all* triggers go via a message-type queue (things like PartyRested can go there too, dammit) and clear triggers before message proocessing, but I haven't looked into that beyond trying it quickly and checking that it's no more broken than GemRB's current system. (Sorry for my delayed response, I suppose replying to devSin's post up there would have avoided any confusion.) Link to comment
Ascension64 Posted August 16, 2010 Share Posted August 16, 2010 I think maybe you two are being confused by the triggers vs the objects? The objects are not so interesting. They are indeed kept around; I already had to add a bunch of hacks to GemRB there to make SoA completable, otherwise scripts are (obviously) left using incorrectly-cleared objects.Yes, you are right. I was thinking of the objects. I haven't really looked much at trigger lists stored in scripted objects. Link to comment
Taimon Posted September 23, 2010 Share Posted September 23, 2010 The trigger list (0x272) is cleared after every script round, if there are some actions to be executed for the active AI object. (And this makes sense, think about the HotKey() trigger.) Player controlled characters do some additional clearing after every action the player gives. (like attack, move, dialogue, guard, cast spell etc.) This is done in an indirect way, not sure if I got this correctly. Here goes: There is a counter (0x35FC) that is set to 75 (multiple of 15 -> AI updates?) after any of the above actions and this counter is decremented quite often (every AI update?). As long as this counter is greater 0, the AI object clears the trigger list but updates all the last_attacker, last_help, etc. objects before doing that. There is an additional counter (0x35FE) that does basically the same, but it is only set in dialogue, when the transition has some actions. In a nutshell: Trigger list is cleared after the AI object gets something to do. Link to comment
Recommended Posts
Archived
This topic is now archived and is closed to further replies.