Multiple actors acting and reacting

This isn’t the same question as the other recently active topic about asking multiple actors to do something with a command. I’m looking for a way to have multiple actors act independently or in reaction to the player in the same turn, with these actions potentially interrupting and redirecting each other. The aim is to have an initiative and action speed system coupled with a table of potential responses for NPCs to various actions of other NPCs on their “sub turn”. This would be governed with “stats” and some degree of random chance so that different commands will cascade out with varying results depending on the actors present.

Now, that’s the very long-term goal, and I am nowhere even close to knowing how to do all that. I’m stuck on step 1, just getting a single action in a limited use case to be interrupted and reported without any initiative system or personality stuff written yet. I tried to change the current player to the character that is currently processing an action, so I can get the reporting out the other end from the action processing rules, but this doesn’t seem to work. The following never results in the “Bob” person taking the sandwich, always the “yourself” person.

Ownership relates various people to various things. The verb to own (he owns, it is owned) implies the ownership relation.

The kitchen is a room.

Bob is a person in the kitchen.

Sally is a person in the kitchen.

There is a sandwich in the kitchen. Bob owns the sandwich.

A thing can be disputed.

The begin-reactions rule is listed before the carry out requested actions rule in the action-processing rules. 

This is the begin-reactions rule:
	follow the reacting rules. 
		
Reacting rules is a rulebook.

A reacting rule for an actor that is not the player taking something (called x):
	repeat with y running through people in the location:
		if y owns x:
			say "[y] exclaims, 'Hey! That's mine!'";
			now x is disputed;
			now the player is y;
			try taking x;
			now the player is yourself;

I had this before:

A reacting rule for an actor taking something (called x):

But then there was, of course, stack overflow because the player was trying to take the sandwich after taking the sandwich after taking the sandwhich, etc. So, it seems like the “now the player is y” is turning Bob into the player after all, but then why doesn’t “try taking x” while Bob is the player result in Bob taking, and still results in yourself taking?

Look at the Problem-Solving Characters extension.

Well, if you tried typing “take sandwich” your reacting rule is never going to run in the first place, because the actor is the player.

The way to avoid the stack overflow is to make sure that the “disputed” thing doesn’t fire if y is the person who’s already trying to take the sandwich:

A reacting rule for an actor taking something (called x): repeat with y running through people in the location: if y owns x and y is not the person asked: say "[y] exclaims, 'Hey! That's mine!'"; now x is disputed; try y taking x;

(Or it probably would be even more efficient to exclude the person asked from the loop; you could do that by defining an adjective like “non-acting” which applies to people who aren’t the person asked, and then looping through non-acting people in the location.) Note “try y taking x” which means you don’t have to switch who the player is, which seems like it could cause all kinds of issues.

EDIT: And note you still get the “That seems to belong to Bob” message at the end; you could finish the rule with “if y holds x, stop the action.”

Aha! So that works, and I feel dumb, as that one I should have been able to tease out.

Now, I’m sorry to just ask back to back questions, but the reporting result is not intuitive here… the action works as expected, and Bob is now carrying the sandwich, but the reporting is behaving as if “yourself” was acting as Bob.

A reacting rule for an actor taking something (called x):
	repeat with y running through people in the location:
		if y owns x and y is not the person asked:
			now x is disputed;
			now the player is y;
			say "[y] exclaims, 'Hey! That's mine!'";
			try taking x;
	now the player is yourself;
kitchen
You can see Bob, Sally and a sandwich here.

>take
yourself exclaims, "Hey! That's mine!"

Bob picks up the sandwich.

That seems to belong to Bob.

>i
You are carrying nothing.

>look bob
You see nothing special about Bob.

>look
kitchen
You can see Bob and Sally here.

Shouldn’t “[y]” always be the owner of the sandwich here? In this case “Bob”?

Edit:
Ok so I fliped these:

			say "[y] exclaims, 'Hey! That's mine!'";
			now the player is y;

And it works… but I want to better understand why this is the case. Does “now the player is y” actually change the token of the actor to “yourself”? That could be annoying as the complexity of this system grows. What’s happening here?

There’s a special case in the standard name-printing rule that prints “You” or “yourself” if the actor is the player. The actual “yourself” object is called “your former self”.

Why are you changing the player to y instead of just having y try the action? (Try reading that sentence aloud.)

I see now that the special case for the actor printing as yourself is not tied to the name of the person, but to just the case that it is the player… luckily it isn’t necessary to actually change the player around to different people, as you are saying above. I had gotten the impression that the reporting rules wouldn’t print out the behaviors of the other actors correctly if I didn’t swap the current player around… this appears to have been the wrong impression and this isn’t as convoluted as I thought it would be.

Ok, now that step one makes sense, I’ve made some more progress on other things. Now, I’m at a point where I can get initiative working, but I want to centralize part of the function instead of having to write this block in every rule. However, I don’t know how (or if it is even possible) to do a decide phrase with multiple variables.

I am trying to write something like the following. This compiles:

To decide if it is (x - a person) turn or (y - a person) turn:
	if the initiative of x is equal to the initiative of y:
		let coin toss be a random number between 1 and 2;
		if coin toss is 1, decide on x;
		decide on y;
	if the initiative of x is greater than the initiative of y, decide on x;
	decide on y;

I have no idea how to reference it in the other code though (see the ??? line in comments):

A reacting rule for an actor taking something (called desired) (this is the theft reaction rule):
	let initiator be the person asked;
	let interrupter be a person;
	repeat with x running through not-current-actor people that own desired:
		now interrupter is x;
		now desired is disputed;
		[if it is initiator turn or interrupter turn returns interrupter???:]
			say "[Interrupter] exclaim[s], 'Hey! That's mine!' [run paragraph on]";
			try interrupter taking desired;
		otherwise:
			say "[Interrupter] exclaim[s], 'Hey! That's mine!'";
	if interrupter holds desired:
		stop the action;

Note that I want to avoid global variables for initiator and interrupter for this. I think I could puzzle out how to do it with global variables, but I would really prefer it if each reacting rule kept it’s variables to itself, because things could get messy otherwise.

Also, the conditional with “stop the action” at the end is not stopping the initial action from going forward even when Bob takes the sandwich. If I put it in an After rule that runs after the reacting rule, this works, but again, this needs global variables and I don’t want them.

Hm, I’m surprised as heck that your “to decide” phrase compiles; it doesn’t compile for me. A “To decide if” or “To decide whether” phrase should be returning a yes or no answer. If you want your phrase to return a person, you should write “To decide which person is…” and then I guess you could make x and y arguments of the phrase, so it starts something like “To decide which person has initiative between (x - a person) and (y - a person):”; or you could write “To decide whether (x - a person) has initiative over (y - a person):” and then refer to it in your code with “If interrupter holds initiative over initiator.”

Also, from the compiler errors I’m getting, you need “is” rather than “is equal to.”

Well, I posted after fiddling it looks like, that did not compile, the thing I had previous to it did, but didn’t help. I prefer your “over” method there, as it is intuitive how to use it in other rules. My brain is just half off from work (yes on the weekend too) by the time I’m writing Inform I just can’t hardly think any more. If it wasn’t for you helpful folks, I’ve said before… I’d never even have hope of finishing this. I’d ask if anyone wants to collaborate more officially than me just posting random questions here, but I tried to write a purpose statement of my framework, and even that was an enormous task to put into words I could share with others… I know what I want it to be, but it’s hard even writing it down in a concise way.

Anyway, this is working, and initiative is getting filled in. Believe it or not I solve several things in between most questions on my own! I’m not posting full code, just the trouble bits extracted from my framework.

Anyway, as for trouble bits… I still can’t get the initial action to stop after an interrupting action is successful. The following bit, I’ve moved around all over the place, and it won’t work:

	if interrupter holds desired:
		stop the action;

I had something like this at one point:

After the theft reaction rule:
	if interrupter holds desired:
		stop the action;

And that seemed to work, when I made interrupter a global variable. I’m really kind of afraid of making global variables when so many actions are going to be flying around and interrupting one another. If something gets gunked up, it could be hard to figure out why… so I would rather not do this. Why doesn’t this work just at the end of the rule itself, and only after the rule?

Moving on from trying to merely stop the action, I realize I need a way for the player to enter input in the middle of a turn when they are interrupted. NPCs can make decisions in the background, but the player needs a secondary input in the middle of the action processing rules when interrupted successfully by an NPC.

After researching a bit, it looks like Glulx Input Loops by Erik Temple is going to be very helpful, if not required, to do this. I am having the following issue with the extension:

Problem. You wrote 'The glulx input handling rules have outcomes replace player input (success) and require input loop to continue (success)'  : but this duplicates a previous assignment of the same outcome, and to the same rulebook.

If that is resolved, I think the below should mostly work, but I have AGAIN run into where I need to be able to halt a specific actor’s action, but not all actions. I have commented it in the below as “[stop the action??? I can’t seem to stop a specific action…]”.

A reacting rule for an actor taking something (called desired) (this is the theft reaction rule):
	let initiator be the person asked;
	let interrupter be a person;
	repeat with x running through not-current-actor people that own desired:
		now interrupter is x;
		now desired is disputed;
		if interrupter has initiative over initiator:
			say "[Interrupter] exclaims, 'Hey! That's mine!' [run paragraph on]";
			try interrupter taking desired;
			if interrupter holds desired and initiator is player:
				say "Do you continue your attempt to take [the noun] from [interrupter]? Y/N >[run paragraph on]";
				wait for any key;
				if keystroke is "y" or keystroke is "Y" or keystroke is "n" or keystroke is "N":
					if keystroke is "y" or keystroke is "Y":
						say "[paragraph break]";
					otherwise:
						say "[paragraph break]You decide to delay your action for the time being.";
						now the player is delaying;
						[stop the action??? I can't seem to stop a specific action...]
				otherwise:
					say "[paragraph break]You must decide if you wish to continue your attempt to take [the noun] from [interrupter]? Y/N >[run paragraph on]";
		otherwise:
			say "[Interrupter] exclaims, 'Hey! That's mine!'";

Glulx Input Loops isn’t compatible with 6L02, and it looks like it won’t be until someone else updates it. But interrupting for a Y/N answer is built in; you just write “if player consents” and it interrupts to ask for a yes/no answer. See section 11.5.

Thank you once again! I have said before, but knowing the text you are looking for before you know to look for it is a prerequisite for finding something specific about Inform 7…

Anyway, the player consents thing works. Now, as for making the action stop, I finally got that to happen by doing this:

The descend to specific action-processing rule does nothing when choosing-to-continue is false.

This seems extreme to me, basically cutting out the entire action rules to make it stop, but just saying “stop the action” wasn’t working. I of course restore choosing-to-continue to true before every action, so that SHOULD be OK… but I don’t know. Is this going to cause something I’m not anticipating?