Dialog Challenge: Liquids

I’ve been enjoying how active this category is at the moment, so why not throw my own challenge into the mix? This time, we’ll be confronting one of parser IF’s classic difficulties: liquids!

Your challenge, if you choose to accept it, is to implement a small game:

  • There are (at least) three rooms in the first area. One has a source of water, one has a source of oil, and one has a thirsty plant.
  • There are (at least) two portable liquid containers (bottles, buckets, etc) which can be filled with either water or oil, or emptied out. Their inventory listings should mention what liquid they contain (if any).
  • Pouring water on the plant causes it to grow, opening a path upward to a new area with a rusty door.
  • Pouring oil on the rusty door allows it to be opened. There’s some fabulous treasure on the other side. Reaching that treasure is the victory condition.
  • Water is potable (whether in a container or not). Oil is not. For a bonus point, allow pouring liquid from one container into another; it’s up to you if this empties the first container or not.
7 Likes

this is a lot so i stopped at pouring stuff on the tree (the door can open itself…) but everything works and you get the idea.

i had most of this already in place from other projects. it took me a while to originally set up. a lot of the code is simply checks (is it really a liquid? is it really a container? is it held?) i also usually check if the container is open but that doesn’t apply here. it’s also a good idea to disallow pouring a liquid into a container with something already in it. that just makes everything messy.

there’s also a lot of redirection since it seems reasonable to allow the player to POUR JAR as well as POUR water.

it would not be that hard to have > 1 water object to fill > 1 containers. but it does introduce a level of complication that i’m bailing on for our purposes here.

(intro)
    "A Fluid Diversion" 
	(try [look])

#player
(current player *)
(* is #in #fishTankRoom)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#fishTankRoom
(name *)    room with a fish tank
(room *)
(room header *) Fish Tank Room
(look *)
    It's a room containing a large fish tank.
(from * go #east to #simpleRoom)

#fishTank 
(* is #in #fishTankRoom)
(name *)    fish tank 
(dict *)    aquarium 
(descr *)
    It's a large fish tank full of water and little else. 
(container *)
(prevent [take *])
    It's too heavy.

#tankWater 
(* is #in #fishTank)
(name *)    water in the tank
(uncountable *)
(potable *)
(descr *)
    It's reasonably clean water inside the tank.
(perform [drink *])
    You take a gulp from the tank and pick up a soupcon of fish pee.
(perform [fill $Con with *])
    You fill (the $Con) from the fish tank.
    (now) (#waterObject is #in $Con)
(unlikely [drink *])

#waterObject 
(name *)    water from the tank
(uncountable *)
(descr *)
    It's questionable water from the fish tank.
(liquid *)

#jar 
(* is #in #fishTankRoom)
(name *)    glass jar
(item *)
(pourable *)
(descr *)
    It's a glass jar. 
(appearance *)
    There's a glass jar here 
    (if) ($Liquid is #in *) (then)
        full of (a $Liquid).
    (else)
    .
    (endif)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#simpleRoom
(name *)   simple room
(room *)
(room header *) Simple Room 
(look *)    
    It's a boring room with little of interest.
(from * go #west to #fishTankRoom)
(from * go #east to #treeRoom)

#can 
(* is #in #simpleRoom)
(name *)    can 
(item *)
(pourable *)
(descr *)
    It's a metal can.
(appearance *)
    There's a metal can here 
    (if) ($Liquid is #in *) (then)
        full of (a $Liquid).
    (else)
    .
    (endif)

#oil 
(* is #in #can)
(name *)    oil 
(uncountable *)
(liquid *)
(descr *)
    It's yellowish clear oil. 
(potable *)
(perform [drink *])
    You take a swig and immediately have regrets. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#treeRoom
(name *)   tree room
(room *)
(room header *) Tree Room 
(look *)  
    It's a simple room, empty except for a tree in the center. 
(from * go #west to #simpleRoom)

#tokenTree 
(* is #in #treeRoom)
(name *)    tree 
(descr *)
    It's a parched tree.
(perform [pour #waterObject on *])
    You give the tree a drink which it greatly appreciates.
    (now) (#waterObject is nowhere)
(perform [pour #oil on *])
    You pour the oil on the tree, which just seems mean.
    (now) (#oil is nowhere)

%% GRAMMAR
(after [examine $Con])
    (container $Con)
    ($Liquid is #in $Con)
    In (the $Con) you can see (a $Liquid).

(container *(pourable $))

(prevent [put $ #in $Con])
    (pourable $Con)
    ($Liquid is #in $Con)
    (liquid $Liquid)
    (The $Liquid) is already in (the $Con).
(prevent [take $Liq])
    (liquid $Liq) 
    You can't take a liquid.

    


(grammar [pour out [held]] for [pour out $])

(before [pour out $Con])
    (pourable $Con)
    (ensure $Con is held)
(perform [pour out $Con])
    (pourable $Con)
    ~($ is #in $Con)
    There's nothing in (the $Con).
(perform [pour out $Con]) %% allows for pouring out liquids
    (pourable $Con)
    ($Liquid is #in $Con)
    (liquid $Liquid)
    You pour out (the $Liquid). It runs away and disappears.
    (now) ($Liquid is nowhere)
(perform [pour out $Con]) %% allows for pouring out a non-liquid item in the container
    (pourable $Con)
    (current player $Player)
    ($Player is $Rel $Dest)
    You pour out (the $Con), spilling its contents out. 
    (exhaust) {
        *($Obj is #in $Con)
        (now) ($Obj is $Rel $Dest)
    }

(instead of [pour out $Liquid]) %% allows for "pour out liquid" along with "pour out container"
    (liquid $Liquid)
    ($Liquid is #in $Con)
    (try [pour out $Con])

(grammar [pour [held] in/into [single]] for [pour $ in $])

(before [pour $Con in $])
    (pourable $Con)
    (ensure $Con is held)
(prevent [pour $Liquid in $])
    ~(liquid $Liquid)
    (The $Liquid) isn't pourable.
(prevent [pour $ in $Con])
    ~(pourable $Con)
    (The $Con) isn't an appropriate container.
    (tick)(stop)
(prevent [pour $ in $Con])
    ($ is #in $Con)
    There's already something in (the $Con).
(prevent [pour $Con in $])
    ($Obj is #in $Con)
    ~(liquid $Obj)
    (The $Obj) isn't pourable.
(instead of [pour $Source in $Con]) %% redirect to pouring the liquid. this allows the player to "pour glass into bucket"
    ($Liquid is #in $Source)
    (try [pour $Liquid in $Con])
(perform [pour $Liquid in $Con])
    ($Liquid is #in $Source)
    (now) ($Liquid is #in $Con)
    You pour (the $Liquid) from (the $Source) into (the $Con).

(grammar [pour [single] on/onto [single]] for [pour $ on $])
(prevent [pour $Obj on $])
    ~(liquid $Obj)
    ~(pourable $Obj)
    That's not pourable 
(prevent [pour $Con on $])
    (pourable $Con)
    ~($ is #in $Con)
    There's nothing in (the $Con).
(instead of [pour $Container on $Obj]) %% if pouring the container redirect to the liquid for the pouring
    (pourable $Container)
    ($Liquid is #in $Container)
    (try [pour $Liquid on $Obj])
(before [pour $Con on $])
    (ensure $Con is held)
(perform [pour $Con on $Obj])
    You pour (the $Con) out onto (the $Obj) where it runs away and disappears. 
    ($Liq is #in $Con)
    (now) ($Liq is nowhere)

(grammar [fill [held] with [single]] for [fill $ with $])
(before [fill $Con with $])
    (ensure $Con is held)
(prevent [fill $Con with $])
    ~(pourable $Con)
    That's not an appropriate container. 
(prevent [fill $Con with $])
    ($ is #in $Con)
    There's already something in (the $Con).
(perform [fill $Con with $Liquid])
    You can't fill (the $Con) with (the $Liquid), you twit. 

(grammar [fill [held]] for [fill $])
(before [fill $Con])
    (ensure $Con is held)
(perform [fill $Con])
    With what?
    (asking for object in [fill $Con with []])
3 Likes

if you suggest a “rope challenge” i’m abstaining :slight_smile:

1 Like

Here’s how I would lay out my approach!

First, I’m going to make two traits: (liquid source $) and (liquid container $). A liquid source can provide an unlimited supply of liquid; a liquid container can, well…contain a liquid.

Since we want each container to hold no more than one liquid, but each liquid can be held by several containers, we need a relation of one liquid to various containers. Dialog’s relation handling isn’t as advanced as Inform 7’s, but this sort of relation is easy: we make a per-object variable ($ is filled with $). This will be used for both our sources and our containers.

In other words, we’re not going to have our actual liquid objects on-stage—instead they’ll be abstract off-stage objects, like #north or #heldby, which only matter when they appear in properties of on-stage things. All actions will actually be performed on the sources instead.

This means we’ll want sources to have appropriate synonyms:

(dict (liquid source $Obj))
	($Obj is filled with $Liquid)
	*(dict $Liquid)

And we’ll want our containers to show what they’re full of:

(name (liquid container $Obj))
	~($Obj is filled with $)
	empty (real name $Obj)
(name (liquid container $Obj))
	($Obj is filled with $Liquid)
	(name $Liquid) (no space) -filled (real name $Obj)

(after [examine (liquid container $Obj)])
	($Obj is filled with $Liquid)
	(par) (It $Obj) (is $Obj) currently full of (name $Liquid) .

With a bit of extra machinery to clear up parsing and printing. It’s unfortunate that we need to bring in a new (real name $) predicate here, but Dialog’s standard library is not good at inserting adjectives in front of object names.

(dict (liquid container $Obj))
	%% First, add “water filled”
	($Obj is filled with $Liquid)
	*(dict $Liquid)
	filled
	%% Then, add “water-filled”
	(collect words)
		(name $Liquid)
	(into $Name)
	(append $Name [-filled] $Tmp)
	(join words $Tmp into $Compound)
	$Compound

(an (liquid container $Obj))
	~($Obj is filled with $) (just) %% “Empty” starts with a vowel
(an (liquid container $Obj))
	($Obj is filled with $Liquid)
	(just) (an $Liquid) %% Otherwise it depends on the liquid’s name

The efficiency of this (dict $) trickery is not great. It would probably be better just to give each liquid a (name-filled $) property that prints “water-filled”, “oil-filled”, etc. That would also let us say “hydrogen peroxide-filled” instead of “hydrogenperoxide-filled”. Actually, let’s do that.

(dict (liquid container $Obj))
	($Obj is filled with $Liquid)
	filled (name-filled $Liquid)

Much better!

For the purposes of this scenario, I’m going to have liquid containers count as liquid sources when full. In other words, you can pour water from a bucket into a bottle and still have water left in the bucket.

(liquid source $Container)
	*(liquid container $Container)
	($Container is filled with $)

And since I mentioned drinking:

(potable (liquid source $Obj))
	($Obj is filled with $Liquid)
	(potable $Liquid)

There we go! Plenty of traits. Next up: actions!

2 Likes

The first and most basic action is filling a liquid container from a liquid source.

(grammar [fill [single] with/from [single]] for [fill $ with $])
(grammar [fill [single]] for [fill $])

(before [fill $Obj | $])
	(ensure $Obj is held)

(prevent [fill $Obj | $])
	~(liquid container $Obj)
	(The $Obj) (is $Obj) not designed to hold liquids.

(prevent [fill $Obj | $])
	($Obj is filled with $Liquid)
	(The $Obj) (is $Obj) already full of (name $Liquid). You would need to empty (them $Obj) first.

(prevent [fill $Obj with $Source])
	~(liquid source $Source)
	(The $Obj) (is $Obj) only designed to hold liquids, which (the $Source) (is $Source) not.

(instead of [fill $Obj])
	(current room $Room)
	*($Source has ancestor $Room)
	(liquid source $Source)
	\( from (the $Source) \) (line)
	(try [fill $Obj with $Source])

(perform [fill $Obj]) %% Couldn’t find a source
	You don’t see any liquid around to fill (the $Obj) with.

(perform [fill $Obj with $Source])
	(liquid container $Source)
	($Source is filled with $Liquid)
	You pour some (name $Liquid) from (the $Source) into (the $Obj).
	(now) ($Obj is filled with $Liquid)

(perform [fill $Obj with $Source])
	($Source is filled with $Liquid)
	You scoop up some (name $Liquid) in (the $Obj).
	(now) ($Obj is filled with $Liquid)

Note that FILL BOTTLE will not ask “with what?”—instead, it will pick the first liquid source in the room. That may or may not be what you want, but the player can always explicitly FILL BOTTLE WITH OIL instead.

And since GET WATER or PUT WATER IN BOTTLE are also reasonable phrasings:

(instead of [put (liquid source $Source) #in $Obj])
	{ (liquid container $Obj) (or) ~(item $Source) }
	(try [fill $Obj with $Source])

(instead of [take (liquid source $Source)])
	~(item $Source) %% Portable things should be taken normally
	(current room $Room)
	*($Container has ancestor $Room)
	(liquid container $Container)
	\( in (the $Container) \) (line)
	(try [fill $Container with $Source])

I’m also not allowing liquids to mix. If you want to switch your bottle from water to oil, dump out the water first.

Speaking of which!

(grammar [empty/pour [single]] for [empty $])
(grammar [empty/pour out [single]] for [empty $])
(grammar [empty/pour [single] out] for [empty $])

(before [empty $Obj])
	(ensure $Obj is held)

(prevent [empty $Obj])
	~(container $Obj)
	~(liquid container $Obj)
	(The $Obj) (is $Obj) not a container.

(prevent [empty $Obj])
	~($ is #in $Obj)
	~($Obj is filled with $)
	(The $Obj) (is $Obj) already empty.

(perform [empty (liquid container $Obj)])
	($Obj is filled with $Liquid)
	You find an unobtrusive spot to dump (the $Liquid) out of (the $Obj).
	(now) ~($Obj is filled with $)

It also makes sense to empty normal containers, so here’s a basic implementation of that.

(perform [empty (container $Obj)])
	(current player $Player)
	($Player is $Rel $Parent)
	(collect $Item)
		*($Item is #in $Obj)
		(item $Item) %% Don’t move non-items
	(into $List)
	You dump (the $List) out of (the $Obj).
	(exhaust) {
		*($Item is one of $List)
		(now) ($Item is $Rel $Parent)
	}

Finally, you might want to pour one container into another, leaving the first one empty and the second one full.

(grammar [empty/pour [single] to/in/into/on/onto [single]] for [pour $ into $])

(before [pour $Obj | $])
	(ensure $Obj is held)

(prevent [pour $Obj | $])
	~{ (liquid container $Obj) ($Obj is filled with $) }
	(The $Obj) (has $Obj) nothing in (them $Obj) to pour.

(prevent [pour $ into $Target])
	~(liquid container $Target)
	~(liquid source $Target)
	(The $Target) (is $Target) not designed to hold liquids.

(prevent [pour $Obj into $Target])
	($Obj is filled with $First)
	($Target is filled with $Second)
	~($First = $Second)
	(The $First) from (the $Obj) would mix with (the $Second) from (the $Target), and that would just be a mess!

(perform [pour $Obj into $Target])
	~(liquid container $Target)
	($Obj is filled with $Liquid)
	You pour (the $Liquid) out of (the $Obj), letting it join the rest in (the $Target).
	(now) ~($Obj is filled with $)

%% At this point, $Target is either full of $Liquid, or empty
(perform [pour $Obj into $Target])
	($Obj is filled with $Liquid)
	(now) ($Target is filled with $Liquid)
	(now) ~($Obj is filled with $)
	You pour all (the $Liquid) into (the $Target), leaving (the $Obj) empty.

Again, no mixing is allowed. If you want to get rid of your oil, dump it on the ground, not into the water. Just think of the harm it could do to the ecosystem!

2 Likes

Finally, here’s the basic scenario.

The liquids themselves:

#water
(name *) water
(name-filled *) water-filled
(potable *)
#oil
(name *) oil
(name-filled *) oil-filled

The containers:

#bucket
(item *)
(real name *) bucket
(liquid container *)
(* is #heldby #player)
(descr *) An ordinary bucket.

#bottle
(item *)
(real name *) bottle
(liquid container *)
(* is #heldby #player)
(descr *) An ordinary bottle.

And the rooms.

#player
(current player *)
(* is #in #cavern)
(descr *) Just your average adventurer.

#cavern
(room *)
(look *) You’re in a wide, tall cavern. Tunnels lead east and west.

(from * go #east to #oilroom)
(from * go #west to #waterroom)
(from * go #up through #plant to #vault)

#plant
(name *) plant
(door *)
(appearance * #in #cavern)
	~(plant is grown)
	A small plant pokes through a crack in the ground.
(appearance * #in #cavern)
	A massive plant stretches upward, sturdy enough to climb!
(appearance * #in #vault)
	The top of a massive plant protrudes into the room.

(instead of [climb *]) (try [enter *])

(when * blocks passage)
	~(plant is grown)
	The plant is too small to climb—you would crush it!

(instead of [put/pour $Source $ *])
	($Source is filled with #water)
	The plant bursts into furious growth!
	(now) (plant is grown)
(instead of [put/pour $Source $ *])
	($Source is filled with #oil)
	The plant looks sad and wilted under the oil.

#waterroom
(room *)
(name *) spring room
(look *) A cold spring bubbles up through the rock here.

(from * go #east to #cavern)

#spring
(name *) cold spring
(* is #in #waterroom)
(descr *) It smells like good water.
(liquid source *)
(* is filled with #water)

#oilroom
(room *)
(name *) pit room
(look *) A small pit is filled with shimmering oil.

(from * go #west to #cavern)

#pit
(name *) small pit
(* is #in #oilroom)
(descr *) It smells like bad oil.
(liquid source *)
(* is filled with #oil)

#vault
(room *)
(name *) vault
(look *) You’re standing on a small ledge above the cavern.

(from * go #down through #plant to #cavern)
(from * go #north through #door to #treasure)

#door
(name *) rusty door
(door *)
(openable *)
(descr *)
	~(door is oiled)
	It’s rusted shut.
(descr *)
	It might open now!

(appearance *) A rusty door stands to the north.

(prevent [open *])
	~(door is oiled)
	The door is too rusty to move.

(instead of [put/pour $Source $ *])
	($Source is filled with #water)
	The door rusts more.
	(now) ~(door is oiled)
(instead of [put/pour $Source $ *])
	($Source is filled with #oil)
	You work oil into the hinges, through the rust.
	(now) (door is oiled)

#treasure
(room *)
(name *) treasury
(look *)
	All sorts of wonderful treasure awaits you!
	(game over {The end})

And here it is!

liquids.z5 (90.8 KB)

Play around with it and let me know what you think. I coded this in a day, so it’s definitely going to have bugs and oversights. But I’m hoping it’s an intuitive enough liquid implementation for many purposes (e.g. Colossal Cave).

3 Likes

Liquid source $ and liquid container $. Nice to see such industry on a really bothersome thing. Now make all of it happen when a player wanders into a bathroom with sink, shower, tub, and toilet.

I’m glib but I love the industry.

Rob

Why not have a puzzle where the oil is at the bottom of a really deep amphora, and all you have at your disposal is lots and lots of water…

(And perhaps a teaspoon.)

2 Likes

Liquids are a wondrous thing. Consider the following examples of reasonable player input:

> spray wall with paint

> squirt water at swimmer

> water plants with watering pot

In each case the liquid we want to manipulate is beyond the ordinarily limits of what the parser deems to be within reach. Even if the (implicit) container prevents us from seeing or touching the liquid, we still want the verbs to work. But if all the containers that contain the liquid are out of reach, we want the liquid to be out of scope.

Inspired by Daniel’s solution, I’ve written code for a [liquid] custom grammar token:

@(grammar transformer [[liquid] | $Tail] $SoFar $Verb $Action $Rev)
  (grammar transformer $Tail [90 | $SoFar] $Verb $Action $Rev)

(match grammar token 90 against $Words $ into $Liquid)
  *(understand $Words as liquid $Liquid)

(understand $Words as liquid $Liquid)
  (filter $Words into $Filtered)
  (determine object $Liquid)
    *(liquid $Liquid)
    *($Obj is filled with $Liquid)
   (player can reach $Obj)
  (from words)
    *(dict $Liquid)
  (matching all of $Filtered)

The token can then be used when defining verbs:

%% POUR OUT 

(grammar [pour out [liquid]] for [pour out $])

~(refuse [pour out $])

(before [pour out $Liquid])
  *($Obj is filled with $Liquid)
  (current player $Actor)
  ~($Obj is #heldby $Actor)
  (first try [take $Obj])

(perform [pour out $Liquid])
  *($Obj is filled with $Liquid)
  (liquid container $Obj)
  You pour (a $Liquid) from (the $Obj).

Note that in addition to Daniel’s predicates this requires us to give each liquid a liquid predicate:

(liquid $)

Now we can pour out a liquid but only if it is inside a reachable container.

> pour out water
You pour some water from the watering pot.

> pour out vinegar
(I’m sorry, I didn’t understand what you wanted to do.)
3 Likes

Excellent addition! It’s probably not worth maintaining my principle of “actions only apply to liquid sources and containers, not liquids themselves”, and this is much better than the ad-hoc prevent rules for each individual action.

1 Like

This scenario is a fun challenge, and (in my opinion) a much better axis along which to compare languages/development systems than Cloak of Darkness.

In that spirit, I’ve tried to implement the same thing in Inform 10.1.2:

Code (3268 words)
"Liquids" by "FLACRabbit"

Part - The liquid model

A liquid container is a kind of container.

A liquid is a kind of thing.

Rule for clarifying the parser's choice of a liquid: stop.
Rule for clarifying the parser's choice of a source: stop.
Rule for clarifying the parser's choice of a liquid container: stop.

water is a liquid.
oil is a liquid.

A source is a kind of thing. A source is usually fixed in place.

Offering relates various things to a liquid. The verb to supply means the offering relation.

After examining a liquid container:
	if the noun supplies a liquid:
		say "It's currently full of [random liquid supplied by the noun].";
	make no decision.

Rule for printing room description details of a liquid container (called C) when C supplies a liquid and C contains nothing: stop. 

Chapter - Parsing and printing for liquid containers

After printing the name of a liquid container (called C) while listing contents:
	if C supplies a liquid, say " of [random liquid supplied by C]".

Understand "of/-- [something related by offering] in/--" as a liquid container.

Chapter - Filling

Filling it with is an action applying to one carried thing and one visible thing. Understand "fill [thing] up/-- with/at/full of/-- [thing]" as filling it with. Understand "dispense [thing] into/in [thing]" as filling it with (with nouns reversed).

After deciding the scope of the player when the action name part of the current action is the filling it with action:
	repeat with L running through liquids:
		place L in scope.

Instead of filling something with something when the second noun is not a liquid and the second noun is not a source:
	say "[The second noun] isn't a liquid."
	
Does the player mean filling something with a liquid container (called C):
	if the player can see at least one source that supplies a random liquid supplied by C:
		it is unlikely;
	otherwise:
		it is likely.

Instead of filling something with a liquid when the noun is not a liquid container:
	say "[The noun] can't contain liquids."

Instead of filling something with a liquid:
	let chosen source be a random visible source that supplies the second noun;
	if chosen source is nothing:
		say "You can't find any source of [second noun] here.";
	otherwise:
		try filling the noun with chosen source.
		
Check filling a liquid container with a source when the noun supplies a liquid:
	let L be a random liquid supplied by the noun;
	if L is a random liquid supplied by the second noun:
		say "[The noun] already has some [L] in it." instead;
	otherwise:
		say "You don't want [the L] and [the random liquid supplied by the second noun] to mix." instead.

Carry out filling something with a source:
	now the noun supplies a random liquid supplied by the second noun.

Report filling something with a source:
	say "You fill [the noun] full of [random liquid supplied by the second noun]."
	
Chapter - Emptying

Emptying is an action applying to one carried thing. Understand "empty [thing]" as emptying. Understand "pour out [thing]" as emptying.

Check emptying something when the noun is not a container:
	say "[The noun] can't contain things, so you can't empty it."

The emptying action has a list of things called prior contents.
The emptying action has a liquid called prior liquid.

Setting action variables for emptying a container:
	now prior contents is the list of things contained by the noun;
	now prior liquid is a random liquid supplied by the noun.

Check emptying a container when the noun contains nothing and the noun does not supply a liquid:
	say "There's nothing in [the noun]!"

Carry out emptying a container:
	repeat with T running through things in the noun:
		move T to the holder of the player;
	now the noun supplies nothing.

To fall is a verb.

Report emptying a container:
	if the noun is a liquid container:
		say "You dump all the [prior liquid] out of [the noun]. Good thing they put drains in the floors[if the number of entries in prior contents is at least 1]. Also, [the prior contents] [fall] to the floor[end if].";
	otherwise:
		say "You take [prior contents] out of [the noun] and set [if the number of entries in prior contents is at least 2]them[otherwise]it[end if] down." 
	
Chapter - Pouring on

Pouring it on is an action applying to one carried thing and one touchable thing. Understand "pour [thing] out/-- on/onto/over [thing]" as pouring it on.

The pouring it on action has a liquid called liquid used.

Instead of pouring something on something when the noun is not a liquid container:
	say "[The noun] isn't the kind of thing you can pour very easily."

Instead of pouring something on something when the noun does not supply a liquid:
	say "There's nothing in [the noun]."

Instead of pouring something on something when the noun is not a liquid container:
	say "You don't want everything in [the noun] to spill all over the floor."
	
Instead of pouring a liquid container on a liquid container:
	if the second noun is the noun:
		say "That's physically impossible.";
	otherwise:
		try pouring the noun into the second noun.
		
Setting action variables for pouring something on something:
	if the noun is a liquid container, now the liquid used is a random liquid supplied by the noun.

Check pouring something on something (this is the default stop pouring it on rule):
	if the second noun is a person:
		if the second noun is the player:
			say "You've watched Titanic. You know what that would [italic type]really[roman type] be like." instead;
		otherwise:
			say "That sounds unpleasant for [the second noun]." instead;
	otherwise:
		say "There's no reason to pour [liquid used] on [the second noun]." instead.
		
First carry out pouring something on something:
	now the noun supplies nothing;
	continue the action.

Chapter - Pouring into

Pouring it into is an action applying to one carried thing and one touchable thing. Understand "pour [thing] in/into [thing]" as pouring it into.

First instead of filling a liquid container with a liquid container:
	if the second noun is the noun:
		say "But... those two containers are the same thing!";
	otherwise:
		try pouring the second noun into the noun.

Instead of pouring something into something when the noun is not a liquid container or the noun supplies nothing:
	say "[The noun] doesn't have any liquid in it."
	
Instead of pouring a liquid container into something when the second noun is not a liquid container:
	say "[The second noun] can't contain liquids."
	
Check pouring a liquid container into a liquid container when the second noun supplies a liquid:
	let L be a random liquid supplied by the second noun;
	if L is a random liquid supplied by the noun:
		say "[The second noun] already has some [L] in it." instead;
	otherwise:
		say "You don't want [the L] and [the random liquid supplied by the noun] to mix." instead.
		
Carry out pouring a liquid container into a liquid container:
	now the second noun supplies a random liquid supplied by the noun;
	now the noun supplies nothing.
	
Report pouring a liquid container into a liquid container:
	say "You pour the [random liquid supplied by the second noun] from [the noun] into [the second noun]."

Chapter - Non-liquid objects in liquid containers

Instead of inserting something into a liquid container when the second noun supplies a liquid:
	say "You don't want [the noun] to get soaked with [random liquid supplied by the second noun]."
	
Instead of filling a liquid container with a source when the noun contains at least one thing:
	say "You don't want [the list of things contained by the noun] to get soaked with [random liquid supplied by the second noun]."
	
Instead of pouring a liquid container into a liquid container when the second noun contains at least one thing and the noun supplies a liquid:
	say "You don't want [the list of things contained by the second noun] to get soaked with [random liquid supplied by the noun]."

Instead of pouring a liquid container into a liquid container when the noun contains at least one thing and the second noun supplies a liquid:
	say "You don't want [the list of things contained by the noun] to get soaked when they fall into [the second noun]."
	
Chapter - Drinking

A liquid can be potable. A liquid is usually not potable.

The block drinking rule does nothing when the noun is a liquid container.

The drinking action has a liquid called the beverage.

Check drinking a liquid container when the noun supplies nothing:
	say "[The noun] is empty!" instead.

Check drinking a liquid container when a random liquid supplied by the noun is not potable:
	say "You eye the [random liquid supplied by the noun] in [the noun] dubiously, then decide against it.[paragraph break]You've seen Romeo and Juliet. You know what [italic type]really[roman type] happens when you take a drink of a sketchy-looking liquid." instead.

Carry out drinking a liquid container:
	now the beverage is a random liquid supplied by the noun;
	now the noun supplies nothing.
	
Report drinking a liquid container:
	say "You drink [the beverage]."


	

Water is potable.

First report drinking a liquid container when the beverage is water:
	say "You down the water in a single refreshing gulp. You don't feel any better - actually, it makes you feel a little sick - but you've played enough video games to know that, in reality, you're slightly healthier than you were before. 10/10 would drink again.";
	rule succeeds.

Part - The map

When play begins:
	say "There's a rumor that, inside the abandoned research center on the east side of town, there's a really valuable treasure just waiting for some enterprising capitalist to walk in and grab it. People always tell you to avoid the place, though, because of the giant mutant spiders. What idiots."

Chapter - Genetics Research Lab

Genetics Research Lab is a room. It has description "In the dim beams of sunlight shining in the dust you've stirred up, you can see a plainly built square room with a tiled floor. There's a door in the south wall, and a door leading back outside to the west.[paragraph break]The company's motto is painted on the wall: 'BIOFUTURE: Growing the Future.'"

Instead of going west when the player is in Genetics Research Lab:
	say "But you haven't found the treasure yet!"

A pile of dead giant mutant spiders is in Genetics Research Lab. It has description "The poor creatures must all have starved after Biofuture went out of business. They're kind of cute now that they're dead."

Instead of searching the spiders:
	say "Like a real adventurer, you start digging through the corpses, looking for anything useful. They don't seem to have any private possessions, though. Maybe they formed some sort of utopian anarcho-communist society before they all died? You don't know.[paragraph break]You've read The Dispossessed. You know what that would [italic type]really[roman type] be like."
	
Instead of taking the spiders:
	say "They're about as big as a large dog, and there must be dozens of them. Not possible."

Chapter - Botany Research Lab

Botany Research Lab is a room. It is west of Stairwell. It has description "The skylights are clouded and most of the plants have shrivelled into brown dust, but aside from that this room is actually kind of pleasant. The door back to the stairwell is to the east."

Chapter - Stairwell

Stairwell is a room. It is south of Genetics Research Lab. It has description "Everything metallic in this room appears to have been mostly dissolved by a heretofore undiscovered species of yellowish metal-eating fungus. Unfortunately, that includes the steps and railings. You can still see the (wooden) doors to the other stories set into the wall, though. There are also doors to the north and west."

Instead of going east in Stairwell when the plant is small:
	say "You can't reach any of the doors from where you're standing."

Chapter - Corrosion Resistance Research Lab

Corrosion Resistance Research Lab is a room. It is east of Stairwell. It has description "This room is full of rusty junk. There's a wooden door to the west, leading back into the stairwell, and another rusty metal door to the north."

Chapter - Precious Metals Research Lab

Precious Metals Research Lab is a room. It is north of the rusty door. It has description "This room is pretty much empty, except for a large treasure chest."

Part - The objects

The description of yourself is "You look like a mess at the moment, but you'll be as good-looking as ever as soon as you can afford some more vodka."

Chapter - Bottle

The player carries a liquid container called a bottle. The bottle has description "The label says 'VODKA'. There used to be some actual vodka in it."

Instead of inserting something into the bottle, say "The bottle isn't big enough."

Chapter - Bucket

A liquid container called a bucket is in Botany Research Lab. It has description "It's just a plastic bucket."

Chapter - Tap

A tap is a source in Botany Research Lab. It supplies water. It has description "It's a typical industrial-grade water tap."

Chapter - Notebook

A lab notebook is in Botany Research Lab. It has description "You flip through the notebook. Seems like they were working on 'dihydrogen monoxide reaction efficiency,' which they claim would allow a suitably engineered plant to survive for decades without water. One corollary (that's a word you just learned from this notebook) is that giving it a normal amount of water would cause explosive, rapid growth."

Chapter - Note

A note is in Corrosion Resistance Research Lab. It has description "The note reads:[paragraph break]Preliminary Experiment 1[paragraph break]Objective: Collect experimental data regarding the rates of corrosion of various common alloys to form a substantive empirical framework to develop a model with which we can rigorously define (and subsequently compute) the desirable quality thus far vaguely referred to as 'corrosion resistance'.[paragraph break]Procedure:[paragraph break]- Place objects made of iron alloys in a room (DONE)[line break]- Wait 20+ years (IN PROGRESS)[line break]- Analyze data"

Chapter - Plant

A plant is in Stairwell. The plant can be big or small. The plant is small.

Understand "small" as the plant when the plant is small.
Understand "big" as the plant when the plant is big.

Instead of going up when the player is in Stairwell, try going east.
Instead of climbing the plant, try going east.
Instead of entering the plant, try going east.

First report going to Corrosion Resistance Research Lab:
	say "You climb up the plant like a well-known fairy tale character, reach out to carefully open the door, and make the short leap from the leaf you're standing on into the room beyond."

Rule for writing a paragraph about the plant:
	if the plant is small:
		say "One of the mutant spiders must have pushed a potted plant in from the Botany Research Lab, because you don't know how it would have gotten here otherwise[first time]... unless Biofuture has developed moving plants, which is a possibility too terrifying to contemplate.[paragraph break]You've seen Day of the Triffids. You know what would [italic type]really[roman type] happen[only].";
	otherwise:
		say "The plant has grown to be at least ten feet tall, with its roots pushing up against the walls. You can now easily reach the lowest door, up and to the east."
		
The plant has description "[if the plant is small]It's a small potted plant with thick, dull, stiff leaves, like a succulent.[otherwise]The plant is tall enough to reach the door to the second story, and its leaves are stiff enough to stand on. There's a ring of dirt and ceramic shards around the stalk.[end if]"

Instead of pushing the plant to a direction, try pushing the plant.
Instead of pulling the plant, try pushing the plant.
Instead of pushing the plant:
	if the plant is small:
		say "You eye it suspiciously. There's a chance Biofuture made that plant sentient, and then pushing it around like that could get you arrested for assault, or battery. Maybe both. You're not a lawyer.";
	otherwise:
		say "It's not going anywhere now."
		
Instead of taking the plant:
	say "It would be heavy and inconvenient to lug around."
	
The default stop pouring it on rule does nothing when the second noun is the plant.

Instead of pouring a liquid container on the plant when the plant is big and the noun supplies water:
	say "Another uncontrolled spurt of growth like the first could be dangerous to the plant, you, and the structure of the building. Better not."

Carry out pouring a liquid container on the plant:
	if the liquid used is water:
		now the plant is big.
		
Report pouring a liquid container on the plant:
	if the liquid used is water:
		say "Nothing happens as the water splashes over the leaves and runs down the stalk, but as soon as it seeps into the dirt around the base, there's a sudden creaking sound and a flash of movement. When the spray of dust from the leaves clears, the plant is now many times as tall as it was before - in fact, it reaches all the way to the second story door.";
	otherwise if the liquid used is oil:	
		say "You splash some oil on the plant. Now it looks shinier."
		
Chapter - Oil source

A fixed in place source called a 50 gallon drum of microscope lens oil is in Genetics Research Lab. It has description "Apparently they were worried about running out." It supplies oil.

Chapter - Rusty junk

A scenery thing called some rusty junk is in Corrosion Resistance Research Lab. It has description "There's a ton of useless stuff here. Is that [one of]a shovel[or]a spring[or]a lawnmower[or]a pipe[or]a knife[or]a grate[or]an oven[or]a condenser microphone[or]a rocket nozzle[or]a desk lamp[or]a screwdriver[or]a football helmet[in random order]?"

Instead of taking the rusty junk:
	say "It's useless."
	
Chapter - Rusty door

A scenery door called a rusty door is north of Corrosion Resistance Research Lab. It has description "There's a faded notice taped to it: 'DO NOT TOUCH! THIS DOOR IS PART OF PRELIMINARY EXPERIMENT 1. Thanks, The Corrosion Resistance Development Team'"

The rusty door can be oiled or stuck. The rusty door is stuck.

Instead of opening the rusty door when the rusty door is stuck:
	say "You pull on the handle; bits of rust flake off and drift to the ground. The door squeaks and groans, but you can't move it more than a few degrees before the friction becomes overwhelming.[paragraph break](You've played Hadean Lands. You know what a [italic type]real[roman type] solution to this problem would look like.)"
 
The default stop pouring it on rule does nothing when the second noun is the rusty door.

Carry out pouring a liquid container on the rusty door:
	if the liquid used is oil:
		now the rusty door is oiled.
		
Report pouring a liquid container on the rusty door:
	if the liquid used is oil:
		say "You pour oil from [the noun] over all the hinges and wait a few moments for it to seep into the mechanism.";
	otherwise if the liquid used is water:	
		say "You splash water over the door. That didn't accomplish much."

Chapter - Treasure chest

A treasure chest is a closed openable scenery container in Precious Metals Research Lab. It has description "There's a piece of pink paper taped to it. The paper says 'LAB SUPPLIES'."

First carry out opening the chest:
	say "You haul the lid open and gaze greedily over all the gold and silver inside. That should be enough to buy a lifetime's worth of vodka!";
	end the story finally.

Liquids.ulx (527.8 KB)

I didn’t pay nearly as much attention as I normally do to adding scenery objects and synonyms, so looking at the source code is not only allowed but encouraged. I’ll update it if anyone finds a bug in the liquid model.

4 Likes

And you get bonus points for actually making an interesting scenario with some story to it!

1 Like