I thought of a way. The explanation might be a little complex, but once you get it I think it is both simple and powerful.
It lets you refer to the caller of a specific action without messing with the pointers of other actors at all.
It does not need to be saved (the stack is always empty at the start of a tick).
One thing it does not do: Let newly spawned actors see (as GLOBAL) the actor that spawned them. It doesn't work that way unless you force them to act DURING the spawn call, and they normally just appear and hang around until the next tick.
I added a new AAPTR-selector: AAPTR_GLOBAL. (complex wordsy) Most of the time, AAPTR_GLOBAL will return NULL/nobody. However, it can be set to the caller at the beginning of a function call (push to a stack), and restored to its previous value at the end (pop from stack). Currently, this can only be set from decorate. How? With a new keyword that can affect any state/frame: GLOBAL.
Let me show you (sample excerpt; something forces everything nearby to take its side):
- Code: Select all • Expand view
TNT1 A 2 GLOBAL A_RadiusGive("code_item", 200, RGF_MONSTERS)
- Code: Select all • Expand view
// pickup state of code_item CustomInventory;
TNT1 A 0 A_CopyFriendliness(AAPTR_GLOBAL)
So... Global keyword added to decorate. If nothing is executing with GLOBAL-modifier, AAPTR_GLOBAL is NULL. If something is currently executing with GLOBAL-modifier, the latest started action that is still running defines the GLOBAL-actor. (If the GLOBAL actor dies, the value for that actor becomes NULL; it's a valid value in this case, and can actually be used to test for the continued existence of an original caller.)
:: If I did explain that poorly, or overly complexly, would anybody please help clarify ? :: I really like this feature (suggestion) ::
Other changes introduced:
A_JumpIfTargetInLOS-flag; JLOSF_CHECKGLOBAL: When a non-player calls A_JumpIfTargetInLOS, the global pointer (AAPTR_GLOBAL) provides the target.
A_JumpIfTargetInLOS-flag; JLOSF_NOPLAYERBEHAVIOUR: Players behave just the way monsters do, never using aim/linetarget. (Normally they use their aim/linetarget, no matter what you specify.)
JLOSF_CHECKGLOBAL|JLOSF_NOPLAYERBEHAVIOUR: Check the global pointer for any actor
JLOSF_CHECKGLOBAL: Check the global actor for non-players, check linetarget for players
No flags: Check stored target for non-players, check linetarget for players
JLOSF_NOPLAYERBEHAVIOUR: Check stored target for any actor
In an A_RadiusGive-situation, this allows you to use such features as field-of-view and JLOSF_ALLYNOJUMP to refine selections and actions based on the giver.
And guys: Do you think any of this is at all potentially useful?
Reasons why I steer clear of A_JumpIfInTargetLOS.
1: The two functions, although similar, have developed slightly differently, possibly as a result of poorly maintained code-duplication. Most significantly, A_JumpIfTargetInLOS has special handling for players, while A_JumpIfInTargetLOS treats players and monsters alike. (JLOSF_NOPLAYERBEHAVIOUR would allow A_JumpIfTargetInLOS to duplicate this behaviour)
2: A_JumpIfInTargetLOS contains or contained a bug which... I did mention it, and try to find out if anybody depended on this odd behaviour. It checks the wrong field of view. Probably some bad copy-pasta. Rather than change this age old behaviour that I got no clear response on, I chose to leave it be.
3: Extending A_JumpIfInTargetLOS to cover all cases by flags is more flexible, and the function seems bug-free to begin with.
4: Code duplication is bad.
For a while now, we have had an imperfect reproduction of A_JumpIfInTargetLOS:
The way it was supposed to be: JLOSF_TARGETLOS (correct since 3503)
The way it was: JLOSF_TARGETLOS|JLOSF_FLIPFOV
I believe adding JLOSF_NOPLAYERBEHAVIOUR to those flag-sets would make the reproduction perfect. Additionally, you can have player-specific behaviour if you want to. Thus, A_JumpIfTargetInLOS duplicates and extends/exceeds A_JumpIfInTargetLOS. Maintaining A_JumpIfInTargetLOS seems unnecessary. (Deprecate? I would.)
I'd add THINGSPEC_SETGLOBAL. If trigger is activating, the thing is AAPTR_GLOBAL. If thing is activating, the trigger is AAPTR_GLOBAL. If the special is ACS_ExecuteWithResult, it will execute soon enough that the information can be used. If you want to store a permanent pointer on one actor, you can then have your pick of MASTER TRACER TARGET fields on both actors without too much difficulty.
NOTE/QUESTION: It is now possible for an actor to make a sight check on itself, by checking global on its own global frame; easy to avoid if you don't (somehow) want it though. ("####" "#" 1 GLOBAL A_JumpIfTargetInLOS("ICantTellYouButIKnowItsMe", 0, JLOSF_CHECKGLOBAL). Should there be a safeguard against it?