[I7] Current action being done by a person

Is there any way to access the current action being performed by a person (and by this I mean actions that have started but haven’t yet finished processing)? This is to be used with actions that can be interrupted by NPCs (if they see the action during the turn(s) it is being performed).

I did this… horrible thing that works for that:

[code]A person has a list of stored actions called myActions.

First before an actor doing anything when the actor is a person and not acting fast:
add current action to myActions of the actor;

Last after an actor doing anything when the actor is a person and not acting fast:
truncate myActions of the actor to ((number of entries in myActions of the actor) - 1) entries;
continue the action;

To decide if (act - an stored action) is the/-- current action for (p - a person):
let entries be number of entries in MyActions of p;
if entries is 0, decide no;
if entry entries of myActions of p is act:
decide yes;
decide no;
[/code]
While it works, it doesn’t look pretty and doesn’t seem very reliable. I think inform somehow thinks that when we do “after” rules we mean “oh, and by the way, do this and nothing else now, okay? This is ALL I want you to do, so please just, you know, stop it all now, it’s fine, I’ll take it from here”. Which means that my code is also very likely to conflict with any future changes (or maybe even built-in code that I don’t know about, unreliable!). So I wonder: is there something built-in function that can be used for this? Or even a more reliable way of doing just this (always execute piece of code before any action, always execute piece of code after any action).

If we only care about the player, we can do “if we are taking the pearl…”, but that one is often unreliable, besides only working on the player. It works well enough to grab the action performed by the player (current user), but it doesn’t grab actions performed by the player (a kind of person). So if one action creates another one (“check taking the pearl: if the box is closed, try opening the box;”), the condition will still return true, as if we were just doing the first action for the whole time.

It’s not 100% clear to me what you’re trying to accomplish. You say the purpose is “to be used with actions that can be interrupted by NPCs” and that you are trying to affect “actions that have started but haven’t yet finished processing,” but I don’t see how your code is intended to help with that. Is the myActions list for a person supposed to have just one entry, and only during the Before-After action processing rules?

Some things that you might be misunderstanding or underappreciating:

  • The After rulebook is not the final rulebook consulted during action processing – the final one consulted is the Report rulebook. This may be unintuitive due to the naming, but the idea is that “after” means “after the action has been deemed successful – but before normal reporting rules are processed.”
  • Any individual actor’s action will be processed all the way through unless one of the action processing rules initiates a new action via a “try” statement.
  • There is a built-in way to address testing for NPCs performing actions – it’s the “actor” action variable, especially in conjunction with the “current action” stored action variable. A condition “the current action is an actor taking the pearl” should evaluate true if that’s the kind of action being processed, and rules like “Instead of an actor taking the pearl…” should be triggered by anyone trying to take it, not just the player.

If none of the above seems applicable, then maybe you can try to explain a bit more about what exactly it is you’re trying to do?

It’s mostly with situations like this:

[code]Check taking something (this is the assist new players with transparent closed containers rule):
if the noun is inside a thing (called container) and container is closed:
say “(first opening [the container])[command clarification break]”;
silently try opening the container;

Last check taking the pearl:
if the player is interrupted in 1 turn: [this calls for the turn this action costs to be passed NOW and checks for interruptions]
say “You were interrupted.”;
stop the action;

Every turn (this is the guard AI rule):
[make other decisions]
if the guard can see the player and the current action for the player is the action of taking the pearl:
say “The guard slaps your hand away from the pearl.”;
now the player is interrupted;
[/code]

Considering this example is a short 1-turn action the purpose of this is probably less clear. But if taking the pearl took multiple turns, then the player would have to start this action while he managed to keep the guard in a very far room, so that he’d have enough time to complete the action before the guard is around to interrupt him.

However, I have improved my code in the first post and I’m now satisfied with it:

[code]A person has a list of stored actions called myActions.
A person has a stored action called Last Action.

First before an actor doing anything when the actor is a person and not acting fast (this is the add current action to myactions list rule):
add current action to myActions of the actor;

First after an actor doing anything when the actor is a person and not acting fast (this is the remove current action from myactions list rule):
truncate myActions of the actor to ((number of entries in myActions of the actor) - 1) entries;
now last action of the actor is the current action;
continue the action;

To decide which stored action is the/-- current action for (p - a person):
let entries be number of entries in MyActions of p;
if entries is not 0, decide on entry entries of myActions of p;
decide on last action of p;[/code]
This means that, yes, for most actions, the myActions of a person will hold zero actions. I’ve also made a “last action” so that I can avoid the “if we are [action]” entirely. But in case a “check” creates a second action, then until this second action is complete we will see two actions in myActions of a person: the initial action and then the action that was created. And until this created action completes, “the current action for person” will return it, rather than the first.

Using “first after” with “continue the action” seems to be safe and reliable enough.

This is the thing that’s confusing–unless you’re doing something very unusual, actions take one turn, period. Every turn the player is performing a new action. When you type “take pearl” the action that turn is the action of taking the pearl, and then if you type “wait” the action the next turn is the player waiting.

Now from the business of “acting fast” that you have in there, I’m guessing you’re using Modified Timekeeping? I’m not super familiar with how things work with Modified Timekeeping… but it seems to me that it doesn’t have any built-in facility for allowing an action to take more than one turn. Failed actions and “acting fast” will take zero turns–they won’t run the Every Turn rules and they won’t advance time–but I don’t see a way for them to take two turns.

So anyway, if you want more useful advice, you might want to post some of the code you have for an action that takes more than one turn. Or if you’ve got things going OK, then you’re probably OK. But if you’re handrolling a system that allows an action to take more than one turn, then you probably also have to handroll the system for keeping track of which actions are going on.

The code for turn processing is working fine. In most circumstances, it will only process Every Turn rules after the player’s action is finished. The exceptions are: doing multiple actions in a row or doing special actions that can be interrupted (as per the code provided in my second post).

But this is pretty much the core of what I did to count time:

First after doing anything (This is the count action time rule): if player turn counter > current turn counter: follow the passage of time rule; [Prevent players from ending up doing 10 turns in a row when doing complex actions] let n be a number; if acting slow: let n be 2; otherwise if acting fast: let n be 0; otherwise: let n be 1; if not acting interruptible: increase player turn counter by n; continue the action;

The every turn rules were taken out of the Turn Sequence Rulebook and replaced with a Passage of Time rule, which runs the every turn rules however many times it takes to make Player Turn Counter == Current Turn Counter.

What I wanted to do is find a way of knowing which action a person (any person) is currently doing, if any. I wanted to know if Inform had some way of checking that without me having to implement my own rules to make notes of actions being done.

The rules I’m currently using on my second post work just fine, but since they need to implement “before doing anything” and “after doing anything” I feel they are non-ideal, since Inform was made to execute only one After rule (meaning that if anything ever adds an After rule that comes before mine and doesn’t say “continue the action”, it’ll break).

But I’m assuming that there is no other way to query the queue of actions any given person is doing through built-in codes. Like you said, it just wasn’t meant to be used in this way. So unless there’s some guaranteed way of doing “before” and “after” in a way which they will always be executed regardless of what happens, this is probably the best solution to my problem.

Either way, I’m satisfied and it works, although I’d be even happier with a better solution.

Action execution is a stack, not a queue.

In case that helps.