Help Buying things when they are in a container

I cannot get this to work! I want the player to be able to buy a thing when they walk into Gus’s Provisions (a room I’ve already set up and described). However, the objects for sale are listed in a written inventory list and are inside the container cupboard, and are not seen by the player, like so:

A written inventory is in Gus’s Provisions. The written inventory is fixed in place. The description of the written inventory is “Inventory of Gus.”

Instead of examining the written inventory:
say "[bold type]Inventory[roman type]

Weapon - Price - Damage[italic type]

Dagger - 4 copper - 1 damage

Spear - 11 copper - 3 damage

Staff - 8 copper - 2 damage

Sword - 14 copper - 4 damage

[roman type]Protection - Price - Resistance[italic type]

Helmet - 9 copper - 2 resistance

Breastplate - 15 copper - 4 resistance

Chausses - 12 copper - 3 resistance

Shield - 6 copper - 1 resistance

[roman type]Provision - Price - Health[italic type]

Herbs - 8 copper - 3 health

Potion - 14 copper - 4 health

Ration - 3 copper - 2 health

Water - 1 copper - 1 health
"

A counter is a container. It is scenery. It is fixed in place. The cupboard is part of the counter. The cupboard is an openable and lockable container. The cupboard is closed.

A dagger is a thing. Understand “knife” or “blade” as the dagger. The description of the dagger is “A small, silver blade is attached to an ivory handle. Exotic, for sure.” The dagger is in the cupboard. The dagger is portable. The price of a dagger is 4 copper.

That part works just fine. But the below code that is bolded does not work. I want the player to be able to buy whatever is on the inventory list even though they cannot see the actual object until they go to buy the object that is unseen in the cupboard in the counter.

Here is what I have:

The price is a kind of value. 999 copper specifies a price. A thing has a price. The price of a thing is usually 0 copper.

Definition: a thing is free if the price of it is 0 copper.
Definition: a thing is for sale if it is not free.

Instead of taking something for sale:
say “You’ll have to pay for that!”

Before buying something for sale when the money is not in the satchel:
say “You do not have enough copper.” instead.

The description of copper is “Copper is quite shiny - and valuable!”

Before buying something for sale when the money is free:
say “You have no copper.” instead.

Before buying something for sale when the price of the money is less than the price of the noun:
say “You do not have enough copper to purchase [the noun].” instead.

Instead of buying something:
** If a thing is for sale and is in a container:**
** say “Gus smiles, leans over and pulls out [the noun] from his counter cupboard and hands it to you.”;**
** decrease the price of the money by the price of the noun; **
** say “You give [the price of the noun] for [the noun], leaving yourself with [the price of the money].”; **
** if the money is free: **
** now the money is nowhere; **
** now the price of the noun is 0 copper; **
** now the player is carrying the noun.**

I cannot get it to work. Please direct me!

1 Like

First question: Have you defined “buying (something)” as an action?

You’ve defined your buyable items as “a thing” but without a location that means they’re off-stage and therefore out of scope and unavailable for the player to refer to. You might want to write A dagger is a thing in cupboard...

Objects in closed, opaque containers are not in scope and thus also not available for the player to refer to. That might be a simple fix of making the container transparent. (Perhaps the cupboard has a window for display?)

If not, you will need to do a tricky check to place off-stage objects in-scope for the player. It’d be easier if the items were visible in the shop, but that’s also doable.

I’d also advise not writing one complicated INSTEAD rule for your buying action, but use CHECK/CARRY OUT/REPORT per the action rulebooks.

(for example, not tested)

Check buying something:
     if the noun is not for sale:
          say "Gus doesn't have that for sale." instead.

Check buying something:
     if the noun is not in the cupboard:
          say "Gus doesn't have that in stock." instead.

Check buying something:
     if the price of the noun is greater than the price of the money:
          say "You don't have enough to purchase [the noun]." instead.

Carry out buying something:
     decrease the price of the money by the price of the noun;
     now the player carries the noun.

Report buying something:
     say "You paid [the price of the noun] for [the noun] and now have [the money] remaining."
2 Likes

Hi Jonah. Welcome to IntFiction!

When you’re posting code, it’s helpful to insert it as a code block using the </> icon in the editing bar or putting 3 backticks: ``` on the line above the code and below it. And also to pare it down to the minimum that demonstrates the issue you’re talking about. If you do those things, people can just click a copy icon and get your actual code, and tab characters don’t get messed up.

Hanon’s idea of making the cupboard transparent was a very neat and economical approach. An alternative would be something like:

After deciding the scope of the player when the location is Gus's provisions:
  repeat with item running through the things contained by the cupboard begin;
    place item in scope;
  end repeat;

Then the contents of the cupboard would be in scope, thus the player could refer to them in commands. (This assumes the player should always be able to refer to the things when in the room. You might want something more complicated if the room could be dark, or if the player could climb into a box and close it, or if the player could be blindfolded…)

[Edited: It’s worth mentioning that among the virtues of Hanon’s transparency suggestion is that it would automatically take care of most of these situations without further thought or effort…]

3 Likes

Thanks for the quick responses. I have implemented the counter transparency, and that works just fine. However, the only thing that doesn’t work is when I go to buy something, it says “Nothing is on sale.”

I had it working before I even made a counter or anything, where a dagger could just be sitting on the floor and I could buy it and it would work correctly (giving me the dagger in exchange for 4 copper). But now that doesn’t work when I can see it in the counter (I removed the cupboards and just let the counter be transparent).

There are a bunch of built-in commands and actions that exist as stubs an author might like to extend, and so by default don’t have anything defined except a Check rule with some sort of “You can’t do that” or “That does nothing” message. When you do extend one of those, you need to override the corresponding rule.

The block buying rule does nothing.

should put you (and Gus) in business.

2 Likes

Thanks! It does work now. Both of you were quite helpful!

Okay, another issue I’ve run into: When I buy one of the 25 rations that are in the transparent counter, it says there are twenty-four left. When I go to buy one again, it says that “Gus doesn’t have that in stock.” I want the number of rations (or whatever item) to decrease when a player purchases it.

Here is what I have:

<>Carry out buying something:
decrease the price of the money by the price of the noun;
decrease the number of the noun in the counter;
now the player carries the noun.</>

It obviously doesn’t work. I know there should be something like that, though.

You almost got the code tag - you need to either surround a single line of code with back-ticks ( ` ) or put three of them ( ``` ) on a line by themselves before and after multiple lines of code. You typed </> which isn’t the tag - that’s the button you can use while composing your message - highlight the code and click the </> button in the post editing menu to automatically add back-ticks for code formatting.

Carry out buying something:
decrease the price of the money by the price of the noun;
decrease the number of the noun in the counter;
now the player carries the noun.

Your rule applies to singular items as well as a kind with multiples and Inform might be confused and considering them collectively. You might want to make another rule for buying rations - just add it in, a more specific rule will take precedence over a less specific one.

If you’ve implemented rations as objects you can’t just “decrease” them, you need to move them into the player’s inventory (for multiples you have to have Inform select “a random” one) or move it off-stage to make it disappear.

Carry out buying a ration:
     decrease the price of the money by the price of the noun;
     now a random ration in the counter is carried by the player;
2 Likes

I tried your code and it still isn’t working. When I go to buy one ration, TWO are now taken out, and when I go to buy another, it still says “Gus doesn’t have that in stock.” But your explanation makes more sense to me than how I was going about it.

Just to add on to Hanon’s great post, I suspect the place where things are currently going awry is this code:

Check buying something:
     if the noun is not in the cupboard:
          say "Gus doesn't have that in stock." instead.

What’s likely going on is that when you type the command BUY RATION, Inform thinks it’s ambiguous since there are 25 different rations in scope. One of the default rules Inform uses to resolve this ambiguity is to assume that the player’s referring to something they’re carrying, so it’s probably picking the ration that’s already been bought and isn’t in the cupboard, rather than one that’s still for sale.

You should be able to fix this by telling Inform how to resolve this ambiguity:

Does the player mean buying a ration (called the foo) when the foo is not in the cupboard: it is very unlikely.

(See documentation for “Does the player mean” here).

2 Likes

That last question/rule thing of yours worked. Thank you.