Basic money (no denominations or change) that can be found, earned, traded?

Apologies if I’m asking about something that has been thoroughly covered elsewhere. For what I’m trying to achieve with money, the examples I’ve found are either too simple (there is one coin which can be traded for one item) or too complex (dollars and cents, making change, etc.). The one example I’ve found that gets close to my needs doesn’t work for me for some reason (I’ll get to this at the bottom).

I want my game to have a currency called “shiny rocks” which can be given, received, found lying around, dropped, and retrieved after having been dropped. There are no denominations or change. Just trading rocks.

I’ve already made a game where the player trades an item as a bribe, but there was only one of that item in the game world. I’m not sure how to implement multiples of an item that can be found or traded in quantities.

I want to be able to leave shiny rocks lying around in different places for the player to pick up. “Oh, look! I found another shiny rock on the ground!”

I want the player to be able to receive a sum of shiny rocks as payment for a job, or to pay a sum of shiny rocks in exchange for goods/services/information. “Give me 500 shiny rocks and I’ll tell you a secret!”

I want a total of shiny rocks to show up in the player’s inventory.

This is the closest example I’ve found to what I’m trying to accomplish, but I’m not sure it covers all my bases, and anyway I gets some PROBLEMS when I try to test it.

[MONEY]

cash is a number that varies.  cash is 0.

shiny rocks is a thing.  The printed name is "[if cash is 1]a[otherwise]some[end if] shiny rock[if cash is greater than 1]s[end if]".
The description of shiny rocks is "Small rocks, polished to a shine.  You have [cash in words] of them."
Understand "rocks" or "stones" or "money" or "cash" as shiny rocks.

When play begins:
	if cash is greater than 0:
		now the player holds shiny rocks.
		
Every turn when cash is greater than 0:
	now the player holds shiny rocks.
	
Every turn when cash <= 0:
	remove shiny rocks from play.


moneypile is a number that varies.
Some discarded rocks is a thing.  The description is "You see [moneypile in words] shiny rock[if moneypile is greater than 1]s[end if] here."
Understand "rock" or "stone" or "money" or "cash" or "shiny rocks" as discarded rocks.

Instead of dropping shiny rocks:
	say "You drop your shiny rocks.";
	change moneypile to 0 + cash;
	change cash to 0;
	move discarded rocks to the location.
	
Instead of taking discarded rocks:
	say "You take the shiny rocks.";
	remove discarded rocks from play;
	increase cash by moneypile;
	if shiny rocks is off-stage:
		now player carries shiny rocks.

Yields:

Problem. You wrote 'change moneypile to 0 + cash'  : but this is a phrase which I don't recognise, possibly because it is one you meant to define but never got round to, or because the wording is wrong (see the Phrasebook section of the Index to check). Alternatively, it may be that the text immediately previous to this was a definition whose ending, normally a full stop, is missing?



--------------------------------------------------------------------------------

Problem. You wrote 'change cash to 0'  : again, this is a phrase which I don't recognise.

Can anyone steer me in the right direction?

The “change foo to bar” syntax is deprecated in later versions of Inform, I forget which was the first. I was able to compile your source in 6M62 by changing those lines to:

	now moneypile is 0 + cash;
	now cash is 0;
2 Likes

This is actually pretty tricky. I7 doesn’t like to deal with massive quantities of identical objects, letting you create no more than 100 in one assertion to remind you of that. But once they’re not identical, you no longer get a lot of benefits the parser normally gives you for free in terms of specifying number.

This is a study toward an approach I think might work, but it’s massively incomplete and would need to be extended to cover every case of the places where one can gain or lose items. The strategy is that there are 100 identical simoleons (a kind of thing whose printed name says shiny rocks) but any given object can only ever hold zero or one simoleons. The simoleon has a quantity property, and adding additional just increments that. Reducing it to zero recycles the simoleon by marking it unused and sending it to nowhere. And then there are some kludgy hacks to drop and take let you specify numbers of shiny rocks with them.

lab is a room.

simoleon is a kind of thing.
a simoleon has a number called the quantity.
the quantity of a simoleon is usually 0.
A simoleon can be used or unused.
A simoleon is usually unused.
A simoleon is usually proper-named.
There are 100 unused simoleons.
Understand "shiny/rock/rocks" as a simoleon.

for printing the name of a simoleon (called cash):
  say "[quantity of cash] shiny rock[if quantity of cash > 1]s[end if]"

To bestow (n - a number) nugget/nuggets on/upon (o - an object):
  let stash be a random unused simoleon;
  if o holds a simoleon (called cash-held), now stash is the cash-held;
  if stash is not nothing begin;
    if stash is unused, now stash is used;
    now the quantity of stash is the quantity of stash + n;
    if o is a room, move stash to o;
    if o is a person, now o carries stash;
    if o is a container, now o contains stash;
    if o is a supporter, now o supports stash;
    else do nothing;
  else;
      say "** Out of nuggets.";
  end if;

To diminish (nugget - a simoleon) by (n - a number):
if the quantity of nugget >= n begin;
      now the quantity of nugget is the quantity of nugget - n;
      if the quantity of nugget is 0 begin;
        now nugget is unused;
        now nugget is nowhere;
      end if;
   else;
     say "** Nugget only has [quantity of nugget] simoleons, needs [n].";
   end if;

To withdraw (n - a number) nugget/nuggets from (o - an object):
  if o holds a simoleon (called cash-held), diminish cash-held by n;
  else say "** [o] has no nuggets, needs [n].";

[ earning and spending are just debugging actions to create and destroy money ]
earning is an action applying to one number.
understand "earn [number]" as earning.
carry out earning: bestow the number understood nuggets upon the player;

spending is an action applying to one number.
understand "spend [number]" as spending.
carry out spending: withdraw the number understood nuggets from the player;

rock-dropping is an action applying to one number and one carried thing.
Understand "drop [number] [simoleon]" as rock-dropping.
check an actor rock-dropping:
  let n be the number understood;
  if the actor holds a simoleon (called cash) begin;
    if the quantity of cash < n begin;
      if the action is not silent and the actor is the player begin;
         say "[We] [don't] have that much.";
      else;
         say "[Actor] [can't] do that.";
      end if;
    else;
      withdraw n nuggets from the actor;
      bestow n nuggets on the holder of the actor;
    end if;
   else;
    say "[We] [don't] have any.";
   end if;

rocks-taken is initially 0.
rock-taking is an action applying to one number and one thing.
Understand "take [number] [simoleon]" as rock-taking.
before an actor rock-taking: now rocks-taken is the number understood; 
instead try the actor taking the second noun;

Last check an actor taking simoleon (called stash):
let n be the number understood;
if n > the quantity of stash, instead say "[There] [regarding stash][aren't] that many.".

Carry out an actor taking simoleon (called stash):
  bestow rocks-taken nuggets on the actor;
2 Likes

Yeah, in short it’s difficult to create a large number of discreet “coins” and usually that is best handled by a number variable. That’s why most games across genres show a loot window and award an amount of money and items instead of having you pick up every individual piece of it. It causes drag on the system to simulate hundreds of individual items.

(You can fudge this, but I don’t recommend it - in Baker of Shireton there was a total of 50 coins in the world, but I created an in-game reason to force the player to insert them into a box once they accumulated so they could be recycled and appear again.)

2 Likes

Thanks for the feedback, everyone! I will experiment with this later tonight. Perhaps I can do without littering money around the landscape and/or reduce the amount of currency necessary in the game. I just had notions of making a little joke about money by having the character carry around an absurd amount of shiny rocks that occur in nature.

Yes, sadly the “identical objects” part of the Inform library is not especially robust. It works fine on the order of 10 things, less well on the order of 100 (lag and hard-to-read output), and falls apart on the order of 1000.

I wonder if you could do something interesting with a “[number]” token in an Understand line. You can then check “the number understood” (as long as the grammar line doesn’t involve parsing another KoV) and see how many rocks the player wanted to interact with.

Basic proof of concept:

A shiny rock is a kind of thing. The player carries a shiny rock.
Understand "[number] shiny/-- rock/rocks" as a shiny rock.
Before doing anything with a shiny rock: say "Number: [number understood]."

Hacking the parsing like this isn’t ideal (and in fact I’d usually recommend against it), but using the “[number]” token like this gives you a way to see exactly how many rocks the player wanted to interact with, and mess with variables appropriately.

3 Likes

I kind of see what you’re getting at here, but I’m not sure how to make it work. I am actually having an issue with this now. My game works fine if you type “give shiny rocks to [whoever]”, but if you type “give [number] shiny rocks to [whoever]”, the game says “You can’t use multiple objects with that verb.” This is causing problems for some testers who are specifying the amount to pay for items. Is there a simple way to patch this up such that typing “give 100 shiny rocks to Slunk” succeeds in giving shiny rocks to Slunk, but say “give 10 shiny rocks to Slunk” fails? I’m lost on this one.

[MONEY]

cash is a number that varies.  cash is 0.

shiny rocks is a thing.  The printed name is "[cash in words] shiny rock[if cash is greater than 1]s[end if]".
The description of shiny rocks is "Small rocks, polished to a shine.  You have [cash in words] of them."
Understand "rocks" or "stones" or "money" or "cash" or "rock" as shiny rocks.

When play begins:
	if cash is greater than 0:
		now the player holds shiny rocks.
		
Every turn when cash is greater than 0:
	now the player holds shiny rocks.
	
Every turn when cash <= 0:
	remove shiny rocks from play.

moneypile is a number that varies.
Some discarded rocks is a thing.  The description is "You see [moneypile in words] shiny rock[if moneypile is greater than 1]s[end if] here."
Understand "rock" or "stone" or "money" or "cash" or "shiny rocks" as discarded rocks.

Instead of dropping shiny rocks:
	say "You drop your shiny rocks.  This can't possibly be a bad idea.";
	now moneypile is 0 + cash;
	now cash is 0;
	move discarded rocks to the location.
	
Instead of taking discarded rocks:
	say "You take the shiny rocks.  Maybe they're important?";
	remove discarded rocks from play;
	increase cash by moneypile;
	if shiny rocks is off-stage:
		now player carries shiny rocks.
Instead of giving shiny rocks to Slunk:
	if Slunk is unpaid:
		if cash is at least 100:
			now cash is cash - 100;
			say "Slunk pockets the shiny rocks and smiles.  'Oops,' he says as he drops his skeleton key on the floor.";
			now Slunk is paid;
			now the skeleton key is in Room 101;
		otherwise:
			say "You don't have 100 shiny rocks.";
	otherwise:
		say "You've already given Slunk enough."

The problem that you are experiencing comes from the parser’s built-in logic to try to understand a number as possibly being a “descriptor” word meaning a certain number of otherwise identical objects. (I think.) Following Draconis’s suggestion, to avoid this confusion you will want to make use of a [number] grammar token.

It seems that your testers are implicitly expecting a paying action that is different from the regular giving action in that an amount can be specified. This seems to me like a reasonable expectation, so you may want to accommodate it.

In your setup, a paying action would have two parameters: a number and a thing, which are respectively the amount paid and the intended recipient. In a command like >PAY 100 ROCKS TO SLUNK, the command words that matter are PAY, 100 and SLUNK. The words ROCKS, ROCK and SHINY do not matter.

You can construct a grammar token that will match the rock-related words but otherwise ignore them. Then that token can be put in the grammar line to skip over the words that are not relevant in that context.

Understand "shiny/-- rock/rocks" as "[rockwords]". [per the example from Draconis above]

Paying it to is an action applying to one number and one thing. Understand "pay [number] [rockwords] to [someone]" as paying it to. Understand "pay [someone] [number] [rockwords]" as paying it to (with nouns reversed).

Note that the Standard Rules define the command “pay” as a synonym of “give”, so >GIVE 100 ROCKS TO SLUNK should also result in a paying action. You’ll want various rules for that action to make sure the player has enough money, that the thing specified can take it, to decrease available cash, to report something to the player, etc.

2 Likes

I set up the paying action as prescribed.

I tried to use this check on the action:

Check paying:
	if the second noun is Jagii:
		try buying the flowers instead;
	otherwise if the second noun is Klerta:
		if the number is 50:
			try giving shiny rocks to Klerta instead;
		otherwise:
			say "The price for the room is 50 shiny rocks.";
			stop the action;
	otherwise if the second noun is Uji:
		if the number is 45:
			try giving shiny rocks to Uji instead;
		otherwise:
			say "The price for the ball gown is 45 shiny rocks.";
			stop the action;
	otherwise if the second noun is Duilla:
		if the number is 5:
			try giving shiny rocks to Duilla instead;
		otherwise:
			say "The price for the splay is 5 shiny rocks.";
			stop the action;
	otherwise if the second noun is Slunk:
		if the number is 100:
			try giving shiny rocks to Slunk instead;
		otherwise:
			say "The bribe for the skeleton key is 100 shiny rocks.";
	otherwise:
		say "That person doesn't seem interested in your money.";
		stop the action.

The payment seems to work no matter what number is typed. What’s going wrong here?

EDIT:
Nevermind. I needed to say “if the number understood is…” instead of “if the number is…”

Using “number understood” the above code almost works, except the payment still works if I use the number 1 or the correct number, but seemingly not other incorrect numbers apart from 1?

EDIT:

give 60 rocks to slunk
The bribe for the skeleton key is 100 shiny rocks.

give 1000 rocks to slunk
The bribe for the skeleton key is 100 shiny rocks.

give 1 rocks to slunk
Slunk pockets the shiny rocks and smiles. “Oops,” he says as he drops his skeleton key on the floor.

First, let me point out that I should have defined the new action as paying it to instead of paying, because the action has two parameters. I’ve corrected my post above. I’ve also added a nouns-reversed grammar line so that >GIVE SLUNK 100 ROCKS will work. Those changes don’t solve your current problem.

If you turn on actions display via >ACTIONS, I suspect that what you’ll find is that the command >GIVE 1 ROCKS TO SLUNK translates immediately to the action giving the shiny rocks to Slunk. If you turn on rules display with >RULES, you would probably also see that your Instead of giving shiny rocks to Slunk: rule is firing as a result.

In the case of >GIVE 1 ROCKS TO SLUNK (or >GIVE 1 ROCK TO SLUNK), I’m pretty sure that this is being parsed the same as >GIVE SHINY ROCKS TO SLUNK. The reason is again that the parser is interpreting the number 1 as a “descriptor” word. Your statement:

Understand "rocks" or "stones" or "money" or "cash" or "rock" as shiny rocks.

makes the parser understand the word “rock” to mean the shiny rocks. When the number 1 is treated as a descriptor, the effect is basically the same as omitting the number. For example, if the PC carried a sword, then >GIVE 1 SWORD TO SLUNK parses the same as >GIVE SWORD TO SLUNK. (The parsing process isn’t exactly the same because of differences in the way that “definite mode” and “indefinite mode” are handled, but the resulting action is identical.) For this type of command, the 1 isn’t translated into the number understood.

The most straightforward way to address this would be to modify the order of the grammar lines for the command word “give,” but I’m not sure what control the author has over that. (Any other mad scientists want to chip in?)

Another way to address this is to prevent the parser from understanding the name words of the shiny rocks whenever a number is included. This can be done by exposing an internal parser variable.

Indefinite mode flag is a truth state that varies. The indefinite mode flag variable translates into I6 as "indef_mode".

The shiny rocks are privately-named. Understand "shiny" or "rock" or "rocks" as the shiny rocks when indefinite mode flag is false.

This means that >GIVE 1 ROCK TO SLUNK can only be understood as a paying it to action, but >GIVE ROCKS TO SLUNK will still be interpreted as a giving it to action. Unfortunately, this also interferes with >GIVE A ROCK TO SLUNK. I’ll think about it.

2 Likes

After reconsideration, I think that given your setup it may be better to explicitly guide players away from using numbers of things instead of trying to make sense of the number they’ve specified.

I came up with the following:

Include (-

[ ContextualNumber num nw ;
	num = TryNumber(wn);
	if (num ~= -1000) {
		!parsed_number = num;
		wn++;
		return GPR_PREPOSITION;
	}
	nw = NextWord();
	if (nw == 'a//') {
		!parsed_number = 1;
		return GPR_PREPOSITION;
	}
	return GPR_FAIL;
];

-).

The Understand token contextual number translates into I6 as "ContextualNumber".

Understand "[contextual number] [something]" as "[numerically prefixed noun]".

Understand "give [numerically prefixed noun] to [someone]" or "give [someone] [numerically prefixed noun]" as a mistake ("In this game, there's no need to specify an amount of something given; either you have enough or you don't.").

This uses a “general parsing routine” (GPR) to recognize numbers, treating “a” the same as “1”. Using a GPR blinds the compiler to what’s being parsed, and this gets past some of its validity-checking code that applies to complex tokens and mistakes.

3 Likes

Sorry if this has been mentioned, but there is a recipe book article about currency:

RB: 9.4. Money

1 Like