Inform grouping things together inconsistently.

Has anyone come across this strange behaviour before? It seems like a bug to me but I won’t raise it until I’m sure.

A monster is a kind of person. 

A skeleton is a kind of monster.
A rat is a kind of monster.
A screamer is a kind of monster.
A worm is a kind of monster.
A troll is a kind of monster.
A ghost is a kind of monster.

The Graveyard is a room. 

The Graveyard is a room. 

Skeleton1 is a skeleton.
Skeleton2 is a skeleton.

In the graveyard is Skeleton1 and Skeleton2.

Rat1 is a rat.
Rat2 is a rat.

In the Graveyard is Rat1 and Rat2.

Screamer1 is a screamer.
Screamer2 is a screamer.

In the Graveyard is Screamer1 and Screamer2.

Worm1 is a worm.
Worm2 is a worm.

In the Graveyard is Worm1 and Worm2.

Troll1 is a troll.
Troll2 is a troll.

In the Graveyard is Troll1 and Troll2.

It generates the following output:

Why has Inform decided to group some of the monsters and not the others?

I’m using version 1.2 6.31/6F95. I’ve compiled it to all story file formats but get the same behaviour - actually for Glulx I don’t get any grouping at all.

I’d appreciate anyone shedding some light on this otherwise I’ll raise it as a bug.

Thank you.

I think it has somehow something to do with a limitation of the Z-Machine: as far as I know, only the first nine characters of object names are recognized (i. e., available to distinguish objects). The strange thing is that this limit seems to kick in one letter earlier when the object name ends in a number, like in your examples. For illustration purposes, try adding this to your code:

[code]SkeletonA is a skeleton.
SkeletonB is a skeleton.

In the graveyard is SkeletonA and SkeletonB.

SkeletonXY is a skeleton.
SkeletonXZ is a skeleton.

In the graveyard is SkeletonXY and SkeletonXZ.
[/code]
When you test the game, you will see that Skeletons A and B are not grouped together, while Skeletons XY and XZ are grouped and indistinguishable from one another (try examining SkeletonXZ and you’ll get the description for SkeletonXY, just like it is with Skeleton1 and Skeleton2).

So I guess one solution would be to give them shorter names (probably the player is not supposed to see their internal names like “Skeleton1” in the finished game anyway?).

Hi StJohnLimbo,

You’re spot on by the looks of it. Thanks very much for pointing that out to me as I had no idea of such a limitation. I’m new to Inform.

You’re also correct on the player not seeing the internal names so your solution will work a treat.

Thanks again.

This is a miniaturized version of the way I’m handling massive groupings and appearances of monsters in a WIP I’m putting together now. It might not ideally answer the way you want to address things, but if it helps give you any ideas, here it is.

[code]graveyard is a room.

undead is a kind of person.

undead-nature is a kind of value. the undead-natures are skeleton, zombie, wraith, spectre, ghoul and vampire. Every undead has an undead-nature. An undead is usually skeleton.

Understand the undead-nature property as describing an undead.

five zombie undead are in the graveyard. three skeleton undead are in the graveyard. one ghoul undead is in the graveyard. two spectre undead are in the graveyard.

When play begins:
repeat with x running through every undead:
now the printed name of x is “[undead-nature]”;
now the printed plural name of x is “[undead-nature]s”.
[/code]

Edit: Actually, I had some free time, so I put together something a bit more relevant to your example:

[code]The Graveyard is a room.

A monster is a kind of person.

monster-nature is a kind of value.
The monster-natures are skeleton, rat, screamer, worm, troll, and ghost.
Every monster has a monster-nature.
Understand the monster-nature property as describing a monster.

every monster has a number called monster-number.
the monster-number of a monster is 0.

two skeleton monsters, two rat monsters, two screamer monsters, two
worm monsters, and two troll monsters are in The Graveyard.

When play begins:
repeat with x running through every monster:
now the printed name of x is “[monster-nature]”;
now the printed plural name of x is “[monster-nature]s”.

When play begins:
let N be 0;
repeat with x running through every monster:
increase N by 1;
now the monster-number of x is N.[/code]

This way, it will keep track of every monster in the game by a number so you can identify each both in groups and more generally in the game.

… and the skeletons will be assigned monster-numbers 1 and 2, the rats will be assigned 3 and 4, and so on.

Hi Luci,

Thanks for that. It never even occurred to me to solve the problem without creating a new kind for each monster. I’m guessing your way will also help reduce memory footprint.

I just want to ask though, do you need to uniquely identify each of the instances within the group. e.g. attacking the second zombie or first skeleton? If so, how are you doing it? This is the ultimate problem I was trying to solve when I hit the above.

Thanks.

Actually, I saw that that was the next logical step here. :slight_smile:

I actually was wondering if you wanted it to display something along these lines, though…

… or if you wanted, say, them to not get individualized until they’re hit.

such as…

I admit I’m kind of assuming a lot here, but the first version is probably the easiest to create until you have a HP/life/health system in place first.

edit: known as the Sword Of Hope method and the Ultima method, respectively :stuck_out_tongue:

Whilst the first solution is easier to implement, I don’t feel it is very elegant for the player; the second is much better.

The lightly wounded aspect of the description isn’t necessary in the game I’m creating. I’m more than happy with:

Even after the player has issued attack commands to a monster, I still don’t want their health status to be identified. However, if the player repeatedly attacks the first skeleton, for example, they should be guaranteed to be hitting the same one.

Thanks for your help on this by the way.

Well, the best quick&dirty way to put together a way to continuously target the same enemy would be to add something like …

[code]A monster can be current-target or potential-target.
A monster is usually potential-target.

After attacking a monster:
now every current-target monster is potential-target;
now the noun is current-target.

Understand “current target” as a monster when the item described is current-target.[/code]

… this, though you’ll want to make a way to actually let attacking happen. The easiest way to do that ( though you would still have to add some checking, carrying out, and possibly reporting rules for the action, but that can probably wait if you’re just testing ) would just be to add the line …

The block attacking rule is not listed in the check attacking rulebook.

… into your code somewhere. now you can type ‘attack current target’ after you’ve attacked whichever enemy you wanted to hit. You can easily modify the wording if you wanted something more suitable, too.

Also, by default, attacking will target the first listed target of the type you name, you’ll have to make it random-by-default manually, if that’s how you want it to otherwise behave.

Edit: You’ll also want to remove that last bit of code after you have decided on a better way to permit attacking monsters; it’s not exactly good form to unlist rules without -really- good reason in a completed work.

I wonder if it would work to define “first,” “second,” etc adjectives to describe objects of identical kind.If that capability isn’t built-in, it would probably be worth creating an extension to do it. (Is there something like that in Numbered Disambiguation Choices?) The monster-number idea might come in handy, or perhaps there’s some way to access the I6 object-number for ordering purposes.

I think that the linked object list will generally keep the objects in the same order (creation order, more or less) each time you reference it, so that there might not be much reason for manually ordering. (I could be wrong, though!) In any case, if the I6 object number is needed, it can be got at pretty easily:

To decide what number is the number_ID of (O - an object): (- {O} -)

One way to use this would be to loop through all objects at the beginning of the game, add the ID as a property, and then sort lists based on the ID as needed, e.g.:

[code]When play begins:
repeat with item running through things:
now the ID of item is the number_ID of item.

[later…]
let L be the list of skeletons;
sort L in ID order;
say “[L].”[/code]

However, as I said, this is probably superfluous, since there probably will not be a difference in the default ordering of the list of skeletons vs. the number-ID sorted list.

–Erik

Luci,

With your example source, every monster now has a unique id across all monsters in the game; they are also nicely grouped into monster type. But I really need go one step further because the player isn’t going to know that the second zombie has an id of 3. So, for each group of monsters the id needs to start at 1. From the player’s perspective this is what I’m hoping to achieve:

So from this I should be able to map the attack command to the relevant monster in the group.

I don’t play MUDs but I think this solution is something similar to what they use.

I have actually got a crude way of doing this, but I was hoping for a neater solution using an equivalence relation. This has stumped me a bit because of my limited knowledge of Inform. I was thinking along these lines:

Pack relates monsters to each other in groups. The verb to band together with (it bands together with, they band together with, it banded together with, it is banded together with, it is banding together with) implies the pack relation.

Sk1 is a skeleton.
Sk2 is a skeleton.

Sk1 bands together with Sk2.

When play begins:
   [loop through all the groups of the pack relation]
    [loop through all the monsters in the group]
      [generate and allocate identifier]

What I don’t understand is how I get hold of a list of groups of the pack relation. I know it can be done because the relations command shows exactly this information.

I know I’m pushing you for more help but I don’t suppose you know where I’m going wrong?

Thanks.

This is pushing the limits of my knowledge, but I imagine something like this could be the beginning of a solution:

[code]Graveyard is a room.

A monster is a kind of person.

There are three monsters in graveyard.

Ordinal is a kind of value. The ordinals are first, second, third, and fourth.

A thing has an ordinal called order. Understand the order property as referring to a thing.

After reading a command:
let N be first;
Repeat with enemy running through monsters in the location:
Now the order of enemy is N;
increment N;[/code]
This depends on the player only using “first” etc. with monsters. It would fall apart with sub-kinds. To really do this right, you’d have to hijack the disambiguation process, probably in I6.

Sorry to respond so late to some of these…

Actually, yes. The more subtle reasoning for that is that you can recycle monsters as any type this way. If, say, you have a bunch of dead rats in your monster ‘recycle bin’ room ( sorta-kinda how I handle it ), you can convert them into skeletons elsewhere when needed, and only use the same 20 to 30 monsters through the whole game ( unless you’re getting Bard’s-Tale-3-degree ambitious, and want to have groups of 99 monsters or more in a room :stuck_out_tongue: ).

Well, I have to admit the unique ID is for the use of the creator, not really for the player. Basically it’s just so you can do ‘whatever’ with any given monster, usually in the form of keeping tabs on it, bringing it back as something else elsewhere in the game world as needed… there are probably better ways to do this, but I am just used to creating NPCs and creatures in masses or through tables.

The reason I didn’t offer a method to order whole groups yet is because I wasn’t sure how you were handling monster movement and behaviour. In combat-oriented games, I sometimes have a tendency to let creatures roam totally independently, and then group them at appropriate times. If you generated packs ( as in your one example ) when play begins, it would probably still require on-the-fly grouping afterwards, since packs will change size, and would likely have to be resummoned as alternate monsters, and such. Capmikee’s idea for ordinals is a good basis for naming them, though it still needs to be subdivided among the monster types.

Anyway, before I get a bit tl;dr with this, I’ll pore through some of my code and see if I can find something relevant. :slight_smile:

Why not? It seems like I’ve seen a lot of examples where rules get unlisted – as a novice I admit it gives me the heebie-jeebies a little, but are there any hidden issues with unlisting rules?

IMHO when you unlist a rule you should be aware of what it does and how removing it affects gameplay. Block rules should be safe to remove if you have a structure to replace their functionality. For example if you unlist the block attacking rule and handle only the special case of attacking monsters, attacking anything else gives an empty response.

Real life example: Once I unlisted a rule that I didn’t think I’d need. Later I spent hours trying to figure out why the turn counter wasn’t advancing. Turns out the rule I unlisted had also incremented the turn counter.

What I usually do when I need to remove the functionality of a rule is to find its source in the Standard Library and copy it into a new rule.

e.g. this is the original Block Attacking rule:

Check an actor attacking (this is the block attacking rule): stop the action with library message attacking action number 1 for the noun.

You could change it like this:

[code]Check an actor attacking something that is not a monster (this is the only attack monsters rule):
stop the action with library message attacking action number 1 for the noun.

The only attack monsters rule is listed instead of the block attacking rule in the check attacking rulebook.
[/code]

Here’s a complete example:

[spoiler][code]Graveyard is a room.

A monster is a kind of person.

There are three monsters in graveyard.

Ordinal is a kind of value. The ordinals are first, second, third, and fourth.

A thing has an ordinal called order. Understand the order property as describing a thing.

Before printing the name of a monster, say "[order] "

After reading a command:
let N be first;
Repeat with enemy running through monsters in the location:
Now the order of enemy is N;
increment N;

Check an actor attacking something that is not a monster (this is the only attack monsters rule):
stop the action with library message attacking action number 1 for the noun.

The only attack monsters rule is listed instead of the block attacking rule in the check attacking rulebook.

Carry out attacking something:
Say “You hit [the noun] with a mighty blow!”

test me with “attack monster/first”[/code][/spoiler]

As capmikee says, this would be difficult to get right when monsters are divided into subkinds, but it wouldn’t be too hard to adapt capmikee’s code to work with the “dynamic” monster reassignment that Luci recommends. I don’t know if the OP is going that route or not, though.

Here are two ideas which are tangential to what the OP wants to do, but might work for other authors working on similar kinds of game:

  1. Allow the author to assign nicknames, e.g.:
  1. Have the game assign nicknames automatically when the player does something that causes a differentiation (an attack, most obviously):

Again, these ideas may or may not be useful, but I thought I’d throw them out there.

–Erik

Reading through Ron Newcomb’s new “Inform for Programmers,” I came across this useful type definition:

This can be used to write one phrase to order any kind of monster (or in fact any kind of thing):

[code]After reading a command:
order zombies;
order skeletons;

To order (name of kind of value K):
let N be first;
Repeat with enemy running through K in the location:
Now the order of enemy is N;
increment N;
[/code]

This modified source:

[spoiler][code]Graveyard is a room.

A monster is a kind of person. Understand “monster” as a monster.

A zombie is a kind of monster.
A skeleton is a kind of monster.

There are three zombies in graveyard.
There are two skeletons in graveyard.

Ordinal is a kind of value. The ordinals are first, second, third, and fourth.

A thing has an ordinal called order. Understand the order property as describing a thing.

Before printing the name of a monster, say "[order] "

After reading a command:
order zombies;
order skeletons;

To order (name of kind of value K):
let N be first;
Repeat with enemy running through K in the location:
Now the order of enemy is N;
increment N;

Check an actor attacking something that is not a monster (this is the only attack monsters rule):
stop the action with library message attacking action number 1 for the noun.

The only attack monsters rule is listed instead of the block attacking rule in the check attacking rulebook.

Report attacking something:
Say “You hit [the noun] with a mighty blow!”

test me with “attack monster/first/zombie”[/code][/spoiler]

produces this delightful exchange:

What I can’t figure out is how to phrase the ordering as a loop over kinds of monsters - something like this:

Repeat with K running through names of kinds of monster: order K

That doesn’t work.

Well I’m overwhelmed by the input from everyone. Thank you to you all.

Firstly,

An absolutely fantastic idea! My game will consist of many monsters that also regenerate, so this is a great technique.

This is very interesting and creative I think, and I’m going to explore this for myself. It’s a great way to allow the player to organise their combat and personalise enemy identities. I really like this.

With regards to monster movement and behaviour, I intend to allow them to roam freely and then form packs when they meet up - even if they are outside the room of the player. Some monsters will actually be created as packs at the beginning of play, but anything goes after that. I want an involving combat experience and I’m looking to have monsters seek each other out as a backup, form new packs and then hunt the player - not quite ready for that yet though! In summary, this is a dynamic world so my coding needs to be robust enough to cope.

Simplicity and convenience to the player is also a major requirement.

I have developed some code using the equivalence relation (see below) but I think this idea capmikee is a far better avenue to explore. Thanks for that.

I’ve posted my own code here as a form of contribution as I feel like I’m zapping people’s knowledge. I don’t claim this to be the best, but it was a start and adds to the Inform learning experience. It is complicated code I know, but I had to see my idea through to implementation.

Basically, the following code was my way of grouping monsters together. It doesn’t actually assign the ids as I think I’m going to abandon the implementation now. Instead, all it does is print out all the monsters grouped together. Originally I thought this would be simple (maybe it is) but this was the only way I could get it to work.

A monster is a kind of person.

A skeleton is a kind of monster.
A rat is a kind of monster.

Pack relates monsters to each other in groups. The verb to band together with (it bands together with, they band together with, it banded together with, it is banded together with, it is banding together with) implies the pack relation.

Sk1 is a skeleton.
Sk2 is a skeleton.

Sk1 bands together with Sk2.

R1 is a rat.
R2 is a rat.
R3 is a rat.

R1 bands together with R2 and R3.

When play begins:
	allocate identifiers to members of pack relation;

To allocate identifiers to members of (R - an equivalence relation of monsters):
	let the monster list be a list of monsters;
	let the final monster set be a list of a list of monsters;
	repeat with the monster running through the list of monsters that R relates:
		repeat with the group monster running through the list of monsters which relate to the monster by R:
			add the group monster to the monster list;
		add the monster list to the final monster set, if absent;
		truncate the monster list to 0 entries;
	say "[the final monster set][line break]".

You end up with this:

It is clearly inefficient with large numbers of monsters, particularly running at the start of play. But it still maybe useful at some point. I’ll keep it in the code repository just in case.

Thanks everyone.

I can’t say why, but I’m now obsessed with creating an extension for enumerating indistinguishable things. I’ve started another thread to talk about it in more detail:

https://intfiction.org/t/name-of-value-of-kind-k/1555/1