How to change object descriptions during the game

I am looking for best practices/advice on how to handle objects whose description changes during the game.

As an example: we have 2 buckets of paint, yellow and red.
Defined as follows (pseudo code):
OBJECT paintbucket1, “paint”, “bucket”, “can”, “yellow”
OBJECT paintbucket2, “paint”, “bucket”, “can”’ “red”

We allow the player to pour the paint from one can in the other, thus creating a can with orange paint and an empty can.

If done so, both cans have to stop responding to their original color, one can has to start responding to “orange” and the other one to “empty”.

In general, when an object changes, I have a new object standing by in an inaccessible storage and I simply swap the objects. This works well if the new object also has completely different properties (like a stone coal transforming into a diamond).

But in this case, the objects stay almost the same, only an attribute - the color and full/empty - changes. It can easily be modeled by defining properties/attributes for color and filled, but how to make sure the interpreter takes it into account when parsing the user input?

One way I can think of is to have functions in the modeling language to add or remove object descriptions. Something like (pseudo code):

REMOVE “red” FROM paintbucket1
ADD “orange” TO paintbucket1

Another way could be to have “special” properties or attributes that are also consulted by the interpreter when mapping user input to objects. Again in pseudo code:

ATTRIBUTE color USED_BY_INTERPRETER
ATTRIBUTE full-empty USED_BY_INTERPRETER

Would these be viable approaches? Or are there better ways?

Thanks for reading…

What program are you building this in?
Probably not inform… I know how to do this in inform.

No, it’s not Inform, nor any of the other mainstream authoring systems. I’m interested in the underlying design concepts of such functionality.

Short answer: it really depends on your authoring system. Some favor one approach, some favor another, and there’s no universal “best” way.

This is hard to answer without sliding from “design concept” to “internal implementation.” (And if you’re planning a new system, you really want to avoid thinking about internal implementation too soon.)

I lean towards this principle: “as little stored data as possible; compute everything else based on that.”

Consider your “REMOVE ‘red’ FROM paintbucket1” approach. You might have several spots in your code where you set the color. Each of them would have to have some ADD and REMOVE lines. Say you forget one. Now the “red” term lingers for the rest of the game; you have a red-blue bucket, which turns into a red-empty bucket, and so on. This is a difficult bug to track down! When you notice it, you know that something went wrong at some earlier point in the game. That sucks.

If you have a color property, then every spot in the game that sets it is one line. This is much less likely to go wrong.

In your full example, you’ve got two properties (color and fullness). These could still become unaligned, which is not idea. Depending on the game, it might be better to include “colorless” as a color, and treat the bucket as empty when color==colorless. This wouldn’t work for every game, though.

+1 zarf

Although, paint and bucket same object?

bucket.color == {silver}
bucket.material == {metal}

paint.color == {red}

bucket CONTAINS paint

Don’t need empty/full property?

Seems like the issue with that might be that you have two paint buckets… do you want to define a different paint for each bucket? Where does the bucket’s paint go when the bucket gets emptied?

I’d stick to your original “swapping objects” plan. Make a third object which is a can of orange paint, drop it in, remove the red paint and yellow paint.

Swapping objects is pretty limiting as a strategy. If the buckets have any other properties at all (labels, dents, solid objects contained) or relations (current “it” pronoun?) then you have to swap all of that stuff. Difficult in general.

I tend to favour the way Inform 7 encourages handling these things - descriptions can be computed by looking at the properties of an object.

The description of a paint-can is usually "It's a can of  paint. [if empty]It's empty.[else]It's full.[end if][if dented] There's a nasty dent on one side.[end if]"

The underlying implementation reality of this is that the description isn’t just a chunk of text in memory, it’s a method of the object that produces the description text whenever it’s called. As a rule, if you have two independent pieces of data that are always supposed to be in sync (eg, the value that determines what colour wall the paint will produce, and the description text of the paint can that references the colour), that’s very bug-inducing.

I would create an paint object consisting of the following:
Litres of paint
Percentage of cyan
Percentage of magenta
Percentage of yellow

So ½ litre of green paint would be a paint object with litre=0.5 cyan=50 magenta=0 yellow=50

Now, each possible color is a point in a 3-dimentional color space:
X = Cyan
Y = Magenta
Z = Yellow
To mix two colors - two points in color space - you just have to calculate the point between them with CompuPhase metric or a similar algoritm.

To tell the player the name of the color he has just mixed, you just need list of color names and their position in color space. Calculate which is closest to your mixed color.