(WIP) Working on a Fluid Library

I’ve spent some time writing a simple and naive fluid library (no conscious inspiration from Inform 7’s fluid extension, simply something done for fun).
It works, but I’ve run into some issues, which I can’t really find the solution of.

fluidlib.dg (4.0 KB)

Create a fluid container with the (fluid-container $) trait. Change the maximum amount of fluid that the container can hold with (maximum fluid level of $ is $). You can set the preset amount of fluid in the container with (fluid content of $ is $) and the type of fluid the container is holding with (fluid type of $ is $). By default, setting the fluid type of a container will make the container be locked to that type of fluid; to allow the player to use the container for any fluid, add the (dynamic-fluid $) trait.

Fluids are objects with the trait (fluid $). Objects can be made into fluid sources by using ($ is a source of $).

Issues and my questions

The most annoying issue is that fluids, despite being topics and having been added to the scope, will not be allowed in actions such as “FILL FLASK WITH WATER”, which I intended to cause the player to search for a source of water in the current room and fill the flask from there. I’ve checked Chapter 10 of the Dialog Manual but I still don’t completely understand which parts of the standard library I need to override.

Another thing I’ve noticed is that I keep repeating similar prevent lines such as these:

(prevent [fill $Obj from $])
	~(fluid-container $Obj)
	(The $Obj) cannot be filled.

I wonder if I absolutely have to write this check for every action dealing with fluid containers?

Thanks in advance for your help - feel free to send suggestions regarding the library (I have no idea what to add to it), or to add your own contributions to it.


I wonder if making fluids topics rather than (fungible?) objects is really necessary; I feel like a simpler approach may be possible.

In the mean time this library inspired me to consider how to give solid objects volumes and containers capacities (defaulting to standard unlimited behavior). It turned out to be surprisingly simple.

Here’s the code:

%% Containers by default have unlimited capacity
%% To set a capacity, use (capacity of $Container is $Number).

%% By default all objects have a base volume of 1
(base volume of $ is 1)

%% Container volumes are their base volume plus their content's volumes
(volume in (container $Container) is $Amount)
        (collect $C)
                ($Obj is #in $Container)
                (volume in $Obj is $C)
        (into $VolumeList)
        (sum $VolumeList into $Amount)
(volume in $Obj is $Amount)
        (base volume of $Obj is $Amount)

%% Something like this (or better yet, maps or folds)
%% would be nice in the standard library I think
(sum [] into 0)
(sum [$Head|$Tail] into $Amount)
        (sum $Tail into $Subtotal)
        ($Head plus $Subtotal into $Amount)

%% Am I forgetting other cases that need to be addressed?
(prevent [put $Obj #in (container $Container)])
        (capacity of $Container is $Capacity)
        (volume in $Container is $ContainerVolume)
        (volume in $Obj is $ObjVolume)
        ($ContainerVolume plus $ObjVolume into $TotalVolume)
        ($TotalVolume > $Capacity)
        You can't fit (the $Obj) into (the $Container),
        (if) ($Capacity > $ObjVolume) (then)
                though you could if you removed stuff from (it $Container).
                (it $Obj) (is $Obj) too large for (it $Container).

Hmm. I don’t understand what you mean by making fluids fungible objects. As the manual states, topics can also represent abstract objects that have names. I think this is a much clearer way than to use a dynamic predicate like (water content of $ is 3) or something. Also, it is much easier to create a new fluid this way - just create an object with a name and the fluid trait.

And yes, I love Dialog for it’s simplicity. Linus made a really user-friendly language.

1 Like

Mount’s Fluid Library 0.02:

(again, this is something I’m working on for fun - nothing really serious. I can’t guarantee no bugs or mastery of the language.)

fluidlib.dg (6.6 KB)

  • Added POUR FROM <obj> INTO <obj>/EMPTY <obj> INTO <obj>
  • Set a default fluid content.
  • Inverted dynamic-fluid into static-fluid. Containers are now dynamic by default. To make a container’s fluid type static (immutable), add the (static-fluid $) trait.
  • Added (library version).

To clarify, anyone may use, modify or distribute copies of this project without prior permission or attribution (through it is appreciated).

1 Like

fluidlib.dg (7.1 KB)

Rename (maximum fluid level of $ is $) to (maximum fluid content of $ is $) to make it consistent with (fluid content of $ is $).
Make containers able to be filled when they are not empty, and the fluid is the same as the fluid they are containing.
Add examine text for sources.
Made it so that EMPTY FROM would use the current amount of fluid in a container rather than the maximum (if the specified amount of fluid is more than the container is containing).

Current issues:

  • The library will print “(The $) can’t hold (the $Fluid)” when a container is holding another type of fluid, even if the container could hold the fluid if it were empty.
  • I want to add a prefix for empty containers, but I’m not too sure how to do this. Adding it to (the $) will cause wonkiness using fluid-relevant actions.
1 Like

Hmm, I thought I had a clever approach for your prefix problem (though I tried making it a parenthetical suffix instead), but it seems you can’t temporarily turn off a predicate, make a query then turn the predicate back on? @lft is that the intended behavior? It would be useful in some situations to have some way to fall through to a different rule like this, I think.

(a (fluid-container $Vessel))
        (now) ~(fluid-container $Vessel)
        (a $Vessel)
        (now) (fluid-container $Vessel)
        (if) ($Vessel is empty) (then)
                (fluid type of $Vessel is $Fluid)
                \( (fullness $Vessel) of (a $Fluid) \)

1 Like