Making an NPC copy the actions of the player

So one of the weird things I discovered is that the actor will reset to the player at the beginning of every turn.

As for what I was trying to do with all of this: learn Inform 7, mostly. I wanted to figure out what the grammar was to take a player’s command and make it control the behavior of an NPC. It was purely exploratory. (It’s also related to prototyping new puzzles for our IntroComp entry, Good Bones).

This led to me wanting to know “okay, why does this action seem to now cut off printing the room description.” I figured it may have had something to do with implicit look rules (in fact, one of my solutions was to just run a look command after going), but I’m also trying to understand how rulebooks work and what the chain of events actually is.

I really wish the debugging commands for rules and actions would be displayed in a tree-like form so these things could be more easily traced. I hope in the future we can actually get full debugger support with stepping, because as @Zed mentions, a lot of the inner workings are undocumented and/or would require you to have an intimate level of knowledge with Inform’s source code.

2 Likes

It’s a great way to learn!

I actually implemented that once. I should try to find it, but as ever there are a lot of I7 projects on my buffet table…

2 Likes

Tangentially related: Matt Weiner’s Faithful Companion does this sort of thing, if you’re interested in seeing it in action. It sounds like his is different enough from what you’re trying to do, but playing/reading his source code may help you discover stuff.

http://mattweiner.net/Faithful%20Companion%20post-comp%20Materials/Release/source.txt

This may not immediately may hows and whys click, but I’ve found the “see it works elsewhere and figure the hows and whys later” approach worked well enough for me learning I7.

4 Likes

Absolutely. When I was learning PunyInform I downloaded all the source code for the I6 games (which for any IF Archive people lurking: could you please separate the source code for I6 and I7 games?) and I would do multi-file searches to figure out how to do stuff.

I see crazy stuff done in the BB awards and elsewhere on this board, and the eternal student in me wants to understand all of it because it’s just so incredibly cool.

I’ve also read large chunks of the manual (and consult it repeatedly). Another amazing resource is @mathbrush’s Let's Play/Read: Inform 7 manuals (Done for now). I’d love to see something similar but for the Recipe Book (and I’ve even started penning that, although I don’t feel qualified at all to!).

(Writing with Inform is honestly a great resource, although over and over it will just give you a single sentence about some topic or concept that should really have its own paragraph.)

I think an “advanced” book on Inform 7 would be welcome that could level game programmers up, something to fill the gaps between the current learning materials available. Anyway, bit of a digression.

2 Likes

I haven’t actually read the content of this thread but you may want @mathbrush to chime in as I beta tested while he worked on his copying clone in Never Gives Up Her Dead…

1 Like

I can post some of the stuff I’ve tried before. In my game the clone copied you two turns late. I had a region where copying happened (castle-region) and the clone could become ‘turned off’ by the flag clone-submerged. Dark-pool was the room where the clone was waiting.


Past-actions is a list of stored actions that varies. Past-actions is {clone-you waiting}.
PastPast-actions is a list of stored actions that varies. PastPast-actions is {clone-you waiting}.
PastPastPast-actions is a list of stored actions that varies. PastPastPast-actions is {clone-you waiting}.

TempAction is a stored action that varies.

Before the player doing something when the player is in castle-region:
	now the actor is clone-you;
	now TempAction is the current action;
	if the player is on east-ledge and the current action is clone-you going west:
		now TempAction is clone-you waiting;
	if clonesubmerged is false:
		add TempAction to past-actions; 
	now the actor is the player; 
	continue the action. 

Every turn when the player is in haunted-region:
	if clonesubmerged is true and the player is not in dark-pool:
		now Past-actions is {clone-you waiting};
		now PastPast-actions is {clone-you waiting};
		now PastPastPast-actions is {clone-you waiting};

Every turn (this is the clone copying rule):
	if pastpastpast-actions is not empty:
		if clonesubmerged is false:
			try entry 1 of pastpastpast-actions;
[		say "Now the clone is [entry 1 of pastpastpast-actions].";]
	if clonesubmerged is false:
		now pastpastpast-actions is pastpast-actions;
		now pastpast-actions is past-actions;
		now past-actions is {};
	now playerpushing is false;
	now cloneheadedout is false;
	
Clonedebugging is an action out of world. Understand "debugclone" as clonedebugging.

Carry out clonedebugging:
	if debugclone is false:
		say "Turning on clone debugging.";
		now debugclone is true;
	otherwise:
		say "Turning off clone debugging.";
		now debugclone is false;
	
Debugclone is a truth state that varies. Debugclone is false.

Every turn when debugclone is true:
	say "The pastpastpastactions-actions list is currently [pastpastpast-actions], pastpast-actions list is currently [pastpast-actions], and the past-actions list is currently [past-actions]";

The issue is that NPCs doing actions usually doesn’t get reported. So I then wrote dozens of special cases to report the clone doing standard actions. I started making it in to an extension but gave up. Here are some examples:

Before clone-you taking a a held thing:
	if clone-you is enclosed by the location:
		say "[one of]Your clone[setcloneact] copies the motions you made when grabbing [the noun], but only grasps air.[or]Your clone[setcloneact] pretends to grab an non-existent version of [the noun]. She smiles at you, as if amused.[or]The clone[setcloneact] mimics grabbing [the noun].[stopping]" instead;

Instead of clone-you waiting:
	if clone-you is enclosed by the location of the player:
		say "[one of]The clone[setcloneact] waits patiently[or]The clone[setcloneact] waits again, looking a bit bored[or]The clone[setcloneact] waits calmly, anticipating your next move[or]The clone[setcloneact] waits[stopping]."

Cloneheadedout is a truth state that varies. Cloneheadedout is false.

Before clone-you going:
	if clone-you is enclosed by the location:
		now cloneheadedout is true;

After clone-you going:
	if clone-you is in the location of the player:
		say "The clone[setcloneact] arrives, following your movements.";
	otherwise if cloneheadedout is true:
		say "Your clone heads out to [the noun]."

Instead of clone-you swimming:
	say "Your clone[setcloneact] firmly refuses to swim."

I’d love to see something similar but for the Recipe Book (and I’ve even started penning that, although I don’t feel qualified at all to!).

Feel free! I think the most engaging part of my original thread was when I didn’t understand something and other people chimed in to explain it, so being unqualified is probably a bonus.

As a side note I hate using Inform 6 and do everything I can to avoid using it. I’ve only used it for debugging and working on extensions. I think the vast majority of Inform questions can be solved without it, though, fortunately.

5 Likes

Thank you very much for sharing this code with us. The way in which actions are stored to be reproduced two turns later is very instructive.

2 Likes

No problem!

The reason I stored it as a list is that many actions result in implicit actions, so if I stored it as a single thing it would get overriden during the turn. By storing a list and only carrying out the first action in the list, it causes the NPC to do the same implicit actions that the PC did.

5 Likes

yup, this was my thinking behind recording just the top level action above.

2 Likes

As someone who has spent months working on a project in I6, I would say it’s less good at the modelling stuff that makes Inform 7 shine, but as this whole thread shows, debugging in Inform 7 can sometimes be extremely frustrating (and it could be a lot better with slightly better debugging tools). I don’t hate I6, but both me and my partner have recognized that for large scope projects Inform 7 is probably the way to go for us in the future.

2 Likes