"unvisited by an NPC" status for rooms: is this code okay?

I’d like to have a framework so NPCs comment on seeing a new room for the first time.

table of NPC chatter
the-room	which-npc	is-said	babble
The Dump	The Snob	false	"'What a dump!' says the Snob."
The Castle	Bob	false	"'Hoity-toity!' says Bob."

after printing the locale description:
	repeat through table of NPC chatter:
		if is-said entry is true, next;
		if location of player is not the-room entry, next;
		if which-npc entry is not in location of player, next;
		say "[babble entry][line break]";
		now is-said entry is true;
	continue the action;

This works okay but since often tables aren’t really the way in I7, I’m wondering if there’s a more elegant way to do things. In particular, when the table gets long, it seems there’d be (unlikely) potential for parser slowdown. And this is inflexible–perhaps it’d be better to have a babble rule, and if it succeeds, only then change the is-said entry.

I suppose we could say “a room has a table name called npc-dialogue.”

So

  1. what cases did I miss which might make this code more flexible? Is there anything egregiously wrong with this code?
  2. is there already an extension that does everything a lot better?

(If this code is actually okay, it seems like it might be worth sharing, I dunno.)

There are various ways and times to call the dialogue action itself. I haven’t changed the one you’ve used, but I thought one thing you could do is not have a giant table, but have one table per room. (Edit - which I see you mentioned.) That will certainly reduce the effort of each table search, though whether it would ever have got to real slowdown (tables are faster than lists) would depend on it getting pretty big.

I set the tables up When Play Begins because it’s easy to use a table to do so:

Summary
dump is a room.
castle is east of dump.

There is man called The Snob. He is in dump.
Bob is a man in castle.

a room has a table name called the chat-table.

When play begins:
	repeat through table of chat indexing:
		now chat-table of room entry is chat-table entry;

table of chat indexing
room	chat-table (a table name)
dump	table of dump chatter
castle	table of castle chatter

table of dump chatter
which-npc	is-said	babble
The Snob	false	"'What a dump!' says the Snob."

table of castle chatter
which-npc	is-said	babble
Bob	false	"'Hoity-toity!' says Bob."


after printing the locale description:
	repeat through chat-table of the location:
		if which-npc entry is in location:
			if is-said entry is false:
				say "[babble entry][line break]";
				now is-said entry is true;
	continue the action;

-Wade

2 Likes

You could use a rulebook, I guess? If you made it a rule on people you could then repeat through all the NPCs in a location, and have the rule say what you wanted. This would also open up the flexibility to modify the response given circumstances.

The table is probably easier conceptually and from a choice organisation point of view though. Although I’d have blanked out the row instead of using is-said.

2 Likes

One thing I forgot to say was, the WIP is on the cusp of gblorb-hood. And the thing is, if you break things down into tables, it takes more memory. Which would push the binary over x80000 bytes of memory and then slow it down, since glulxe’s parser is more complex and works slower. (I’ve run tests on that!)

One possible solution to that would be to do preprocessing and give rooms a talk-table-start and talk-table-end number and only check out rows from start to end. e.g. in the trivial example above the dump would have start/end row 1 and the castle start/end row 2. But then you have to make sure all rooms are together, etc.

That’s a strong idea–rulebooks are always a pain to implement for me, because I learned them relatively late and I also forget some nuisance detail about them. But once they’re in place, things go nice and smoothly. I usually wind up having to write them in a sandbox project so I can isolate what I want to do with a really simple case, then I dump them into the main code. It’d also allow them to, say, nag you every five turns for particularly important clues/points.

Tables are fast if you choose by row number. So if you assigned a number (starting at 0) to each NPC and a number (starting at 0) to each room, you could choose row number ((id of npc) * (room count)) + (id of room) + 1;.Tto keep the table readable in the code itself, you could use comments identifying which npc and room are under consideration for the row.

2 Likes

True, although it’s not the fault of the parser per se.

As far as I know it’s down to: (a) Glulx opcodes are encoded in a fancier way than Z-machine opcodes. (More flexible, but it takes more work to pull each one out.) And (b) almost every Glulx memory operation involves pulling four bytes out of memory and gluing them together into a 32-bit number, or the reverse. (For Z-code it’s two bytes for a 16-bit number, so Glulx is twice the work by definition.)

1 Like