Pairing Combinable Objects

Hi guys, I’ve been working with Inform 7 for a while now and I’m trying to build an adventure game extension, but I’m a bit stuck. I have a system that uses relationships to mark objects that can be combined to create new objects, but I have two big problems

First - if I say X and Y can be combined, there is no way to add any more combinations as this creates errors for all but the first entry. I think this could be solved with a blank table, but I can’t work out how to use tables, let alone populate a blank one.

Second - if I want to combine objects, Inform demands that both of them have to be unique or it won’t compile. For example, I can’t create a ‘kind’ of thing called bread and have a pile of five slices of bread if I ever want to combine them with cheese because something described only by its kind should not be given a specific place or role in the world, to avoid ambiguity".

Is there any way round either of these?

Sounds like you’re using a one-to-one relation when you should be using a various-to-various relation. In other words, there’s a difference between:

Combineability relates a thing to a thing.

…which allows each thing to be combined with exactly one other thing, and:

Combineability relates various things to various things.

…which allows each thing to be combineable with any number of other things.

In this case, you may also want to make the relation reciprocal:

Combineability relates things to each other.

What “each other” does is that if you say “A combines with B”, it is automatically true that B also combines with A, which seems logical in this instance.

Thanks, I can now set multiple relations, but for some reason its now storing a number instead of the name of the object - so when I call on the related object in a script I just get ‘320’ instead of my test object. Have you any idea how to fix this?

The version I’m using is:

Combineability relates things to each other.

Can you show us a minimal example that results in the undesired numeric output?

Sure. I had to take apart the complex bits anyway. :stuck_out_tongue: This example doesn’t include the mechanics of the crafting system, but it should show you why they aren’t working. I think the number it gives you is the number of the object as it is stored in Inform’s database.

[code]Cafeteria is a room. Hyperspace Chest is a room.

Object Transmutable relates things to each other in groups. The verb to become means the Object Transmutable relation.

Definition: a thing is Object Transmutable if it becomes more than one thing.

Combining Objects is an action applying to two things. Understand “use [something] on [something]” as Combining Objects.

There is a Cheese in the Cafeteria. It becomes the cheese sandwich. [This line and the next one are what is producing the attached number.]

There is a Bread in the Cafeteria. It becomes the cheese sandwich.

Carry out Combining Objects:
say “You use [the noun] on [the second noun] and get a [Object Transmutable of the second noun].”;

Test me with "use bread on cheese".

[/code]

I don’t have Inform fired up right now to test it, but the problem is in your text substitution [Object Transmutable of the second noun]–I think it’s printing the internal representation of the Object Transmutable relation (or something like that). As a rule when you want to use a relation you want to use the verb, not the name of the relation. Sometimes there will be a special noun you can use for the relata, like if you’ve said “Loving relates one person to one person (called the inamorata)” then you can talk about the inamorata, but I don’t think you can do that for various to various relations.

Try something like this:

Carry out Combining Objects: let the result be a random thing that the second noun becomes say "You use [the noun] on [the second noun] and get a [result]."

Also I’m not sure you actually want a reciprocal relation here, as it looks like you could randomly get the bread, the cheese, or the sandwich. The reciprocal relation would work if you were using the relation to relate co-ingredients (which I’m guessing is how Triplanetary read your post) but if you want to relate the ingredients to the thing you’re making you don’t want it to be reciprocal, so you should go to the “various things to various things” thing that Triplanetary posted.

On your second issue, I think you can take care of it like this:

When play begins: now every slice of bread becomes the cheese sandwich.

You may not be able to set relations over time at startup (the way you can with properties like “Every slice of bread is burnt” if you’ve defined “burnt” as an adjective), but setting them when play begins should be good enough.

Thanks, but I’m afraid it didn’t work. :confused: “relates various things to various things.” compiles on its own, but the moment I try to read what the bread becomes I get an error saying:

I also tried the ‘When play begins’ statement, but it wouldn’t compile for the same reason. I can’t tell much from the index but I don’t think the transmutable is getting attached to the objects when I use the “various things to various things” phrase.

I’m also not sure about using the word ‘random’ since it might introduce problems with ingredients that have multiple uses. For example, bread could be the cheese sandwich, but it could also be the sausage sandwich, and if the outcome is chosen at random Bread + cheese could = sausage sandwich; which will cause a lot of problems once I start working on my alchemy addon.

It turns out the “Object Transmutable relation” is not storing anything when I write “various things to various things” or for “relates things to each other” - I checked in every way I know and it always says:

It doesn’t seem to understand “The verb to become means the Object Transmutable relation.” for this, even though it compiles.

Aargghh, I always get that syntax wrong, which is why I shouldn’t do it without running it through Inform. I’ve checked it out now and the proper syntax is to use the passive voice:

Carry out Combining Objects: let the result be a random thing that is become by the second noun; say "You use [the noun] on [the second noun] and get a [result]."

(If the relation is reciprocal you can actually use “thing that the second noun becomes” and it’ll be OK.)

Once this is fixed the “When play begins” statement should work:

[code]A slice of bread is a kind of thing. The plural of slice of bread is slices of bread. There are five slices of bread in the cafeteria.

When play begins: now every slice of bread becomes the cheese sandwich.[/code]

Now, about the “random” thing: This is not something that can be helped the way we have it, so we need to go to something more complicated.

Think of it this way: Suppose the bread and cheese combine to make the cheese sandwich, and the bread and sausage combine to make the sausage sandwich, and the cheese and macaroni combine to make the mac’n’cheese. Now the player combines the bread and cheese. What should they get?

Well, if the result is determined by something that relates to the first noun or second noun, there’s absolutely no way to tell except by picking at random! Suppose the cheese is the second noun. The cheese becomes the cheese sandwich, and the cheese becomes the mac’n’cheese. If we’re just looking at what the cheese is related to, Inform has no way of distinguishing the two.

What we need to do is to do something a little more complicated, to look at what the noun and the second noun both relate to. So we could write something like this:

Carry out Combining Objects: if something (called the result) that is become by the noun is become by the second noun: say "You use [the noun] on [the second noun] and get a [result]."; otherwise: say "Those don't combine."

Note that our “if” test is now testing whether there’s something that both the noun and second noun become, and picking that. (If we’re not careful defining the relations, there could be more than one such thing, and then Inform will just pick the first one we defined. But there’s no way around that other than to make sure we don’t try to let two separate objects combine with more than one result. If the egg and bread make the egg sandwich, and the bread and egg make the french toast, then neither Inform or the player will know what to do with “Use egg on bread.”)

And if we’re going to do this we really need the relation to be nonreciprocal, or we’ll wind up making the ingredients instead of the result. So:

[code]Cafeteria is a room. Hyperspace Chest is a room.

Object Transmutable relates various things to various things. The verb to become means the Object Transmutable relation.

Definition: a thing is Object Transmutable if it becomes more than one thing.

Combining Objects is an action applying to two things. Understand “use [something] on [something]” as Combining Objects.

There is a Cheese in the Cafeteria. It becomes the cheese sandwich. [This line and the next one are what is producing the attached number.]

A slice of bread is a kind of thing. The plural of slice of bread is slices of bread. There are five slices of bread in the cafeteria.

When play begins: now every slice of bread becomes the cheese sandwich.

Carry out Combining Objects:
if something (called the result) that is become by the noun is become by the second noun:
say “You use [the noun] on [the second noun] and get a [result].”;
otherwise:
say “Those don’t combine.”

Test me with "use bread on cheese".[/code]

(By the way, a nice little bonus you may not have noticed–we don’t actually have to define the Cheese Sandwich as an object, and in fact we didn’t. When we write “It become the Cheese Sandwich” Inform knows that it needs to create a thing called the Cheese Sandwich and put it into the appropriate relation with the cheese. So it automatically creates the cheese sandwich off-stage.)

…I’m not exactly sure how you’re getting that “is a nothing, holding nothing” text, but “Object Transmutable of the noun” is not the way to access the relation you’ve defined. Use the verb: “thing that the noun becomes” and “thing that is become by the noun” will both work (as I said above, I messed up the syntax the first time I tried this).

Matt, thanks, it’s working flawlessly now! :smiley: I think this should do it, all I have to do now is translate my experimental script from before into the working extension and I should be able to publish it.

I tried “thing that the noun becomes”, but it doesn’t recognise the phrase, but Matt just gave me a way to name the result so it shouldn’t matter.

Oh yeah, the compiler error messages are sometimes trying to guess as to what should go there and the messages aren’t always helpful. Sometimes if it doesn’t make sense you just have to take it as “Something went wrong in this line somewhere” (in this case, that I forgot that “thing that noun becomes” should be “thing that is become by the noun”).

I just tested “[thing that is become by the noun]” and it doesn’t seem to work. :confused: I don’t seem to be able to call that phrase at all.

I also tried cloning the script Matt fixed for me with different names, but that didn’t work either. This is really frustrating.

Actually, I solved it! :stuck_out_tongue: It’s misunderstanding because I am asking it for one object when actually there is a list of objects. This works: “list of things become by the noun”

I am still having the second problem, though. :confused:

Ok, I have it all working now, but I’m wondering about object management. At the moment the script is set up to use Dynamic Objects by Jesse McGrew to clone new items every time one is crafted, but I’d like to minimise this by checking that there isn’t already an out-of-play object I could move, but I can’t figure out how. Here is what I have tried:

If the craft result is in the Hyperspace Chest: Move a random craft result in the Hyperspace Chest to the player;

I have tried this a few different ways, but I can’t seem to get it to work. Any ideas?

So what you want is a check for whether something of the same kind as the craft result is in the Hyperspace chest? Finding something of the same kind as a given object isn’t built-in functionality in Inform 7, but the extension Object Kinds by Brady Garvin was designed for exactly this kind of use, I think.

Oh, don’t worry, I just found a way round it. :wink:

Ok, I have just come upon a bit of a problem - I need to build exceptions into my script for other times that the player might say “use [something] on [something]”. I have already covered lockable objects, can anyone suggest any others? Or maybe a better conflict-proof way to avoid script conflicts?

I think I just found a much bigger problem. :stuck_out_tongue: For some reason I can’t get inform to craft together components that were made by crafting. For example, here is one of my basic tests:

[code]Lup Powder is a kind of thing.

Nup Nut is a kind of thing. There are 5 Nup Nuts in the Wizard Shop. Every Nup Nut becomes the Lup Powder.
Quog is a kind of thing. There are 5 Quogs in the Wizard Shop. Every Quog becomes the Lup Powder.[/code]

This far works - the ‘Nup Nut’ and the ‘Quog’ combine to make ‘Lup Powder’. However, if I try to combine absolutely anything else with the ‘Lup Powder’ it tells me it doesn’t recognise the combination, even though I wrote the combo the same way. In other words, I can only combine once, no matter what I do. Can anyone think of a solution?

If it’s any consolation, I can’t get “Nup Nut” and “Quog” to combine either!

Here’s what I think is happening: You’ve defined “Lup Powder” as a kind of thing. Inform usually treats “the [name of kind]” as the same as “a [name of kind].” (It doesn’t know which Lup Powder you refer to when you say “the Lup Powder.”)

So when you write “Every Nup Nut becomes the Lup Powder” it sees “Every Nup Nut becomes a Lup Powder” and thinks you mean to implicitly define a Lup Powder for every Nup Nut to become. (To see why this make sense, think of the code “A nose is a kind of thing. Every person incorporates a nose”–the effect this has is to create a nose as part of every person, so we don’t have to define the noses individually.)

So we wind up with ten total Lup Powders, with each Nup Nut related to a different Lup Powder and each Quog related to a different Lup Powder. This isn’t going to help at all. (Again, it didn’t work for me even with “Use Nup Nut on Quog,” because the Lup Powder that the Nup Nut relates to isn’t the Lup Powder that the Quog relates to.)

To take care of this we have to go back to the “When play begins” solution, because I’m pretty sure that Inform will always take things like “Every Nup Nut becomes a Lup Powder” as requests to implicitly create new Lup Powders for every Nup Nut to become, and that’s not what you want.

So:

[code]Wizard Shop is a Room. Hyperspace Chest is a room.

Object Transmutable relates various things to various things. The verb to become means the Object Transmutable relation.

Definition: a thing is Object Transmutable if it becomes more than one thing.

Combining Objects is an action applying to two things. Understand “use [something] on [something]” as Combining Objects.

Lup Powder is a kind of thing. There are 5 Lup Powders in Hyperspace Chest.

Powdered Nut is a kind of thing. There are 5 Powdered Nuts in Hyperspace Chest.

Nup Nut is a kind of thing. There are 5 Nup Nuts in the Wizard Shop. Quog is a kind of thing. There are 5 Quogs in the Wizard Shop.

Carry out Combining Objects:
if something (called the result) that is become by the noun is become by the second noun:
say “You use [the noun] on [the second noun] and get a [result].”;
now the noun is in the Hyperspace Chest;
now the second noun is in the Hyperspace Chest;
now player carries the result;
otherwise:
say “Those don’t combine.”

When play begins:
now every Nup Nut becomes every Lup Powder;
now every Quog becomes every Lup Powder;
now every Nup Nut becomes every Powdered Nut;
now every Lup Powder becomes every Powdered Nut.[/code]

And this works OK, at least up to “use nup nut on quog” and “use nup nut on lup powder.” If we try “use nup nut on quog” twice we get the same lup powder back again–that’s the problem where you’d want to select a lup powder from the Hyperspace Chest rather than one that’s already on-stage, and you say you have a solution for it, so if you plug this into your solution you should be OK, I hope.