I managed to make it so that socks, shoes, underwear and pants all coexist and layer in their own little stacks without resorting to a “foot slot, lower body slot”, etc system. There are two predicates needed, ($ can go underneath $)
that defines how layering works and ($ can coexist with $)
that defines what can exist in a separate stack.
%% Coder responsible for all other (their $) predicate definitions
(their (current player $))
your
This is the base class for any type of thing that can belong to someone.
%% Possession class
(name (possession $possession))
(if)
($possession belongs to $owner)
(then)
(their $owner)
(endif)
(possession prefix $possession)
(possession name $possession)
(possession suffix $possession)
(possession prefix $)
(possession suffix $)
(dict ($ belongs to $owner))
*(dict $owner)
(proper (possession $possession))
(if)
($possession belongs to $owner)
(then)
(proper $owner)
(else)
(possession proper $possession)
(endif)
(possession proper $)
(fail)
(singleton (possession $possession))
(if)
($possession belongs to $owner)
(then)
(singleton $owner)
(else)
(possession singleton $possession)
(endif)
(possession singleton $)
(fail)
All clothes derive from this subclass.
%% Clothing subclass
(possession *(clothing $))
(dict (clothing $))
clothing garment
(plural dict (clothing $))
clothing clothes garments
(wearable (clothing $))
Socks can go under socks and shoes, and coexist with underwear and pants.
%% Socks subclass
(clothing *(socks $))
(possession name (socks $))
socks
(dict (socks $))
sock
(plural (socks $))
((socks $) can go underneath (socks $))
((socks $) can go underneath (shoes $))
((socks $) can coexist with (underwear $))
((socks $) can coexist with (pants $))
((shoes $) can coexist with (necklace $))
Nothing goes over shoes; they coexist with underwear and pants.
%% Shoes subclass
(clothing *(shoes $))
(possession name (shoes $))
shoes
(dict (shoes $))
shoe
(plural (shoes $))
((shoes $) can coexist with (underwear $))
((shoes $) can coexist with (pants $))
((shoes $) can coexist with (necklace $))
Underwear can go under underwear and pants, and coexist with socks and shoes.
%% Underwear
(clothing *(underwear $))
(possession name (underwear $))
underwear
(plural dict (underwear $))
underwears
((underwear $) can go underneath (underwear $))
((underwear $) can go underneath (pants $))
((underwear $) can coexist with (socks $))
((underwear $) can coexist with (shoes $))
((underwear $) can coexist with (necklace $))
Pants can go under other pants as well as underwear, even though doing so is a bit silly. They coexist with socks and shoes.
%% Pants
(clothing *(pants $))
(possession name (pants $))
pants
(dict (pants $))
pant
(plural (pants $))
((pants $) can go underneath (underwear $))
((pants $) can go underneath (pants $))
((pants $) can coexist with (socks $))
((pants $) can coexist with (shoes $))
((pants $) can coexist with (necklace $))
The prevent rule is complicated, it collects all the exposed clothing and if none of them can go under the clothing being put on nor coexist with them, wearing is prevented. EDIT - Informative error message.
%% Wearing rules
(prevent [wear $new-clothing])
(current player $actor)
(collect $worn-clothing)
*($worn-clothing is #wornby $actor)
~($worn-clothing is underneath $)
(into $exposed-clothing)
~(empty $exposed-clothing)
*($choice is one of $exposed-clothing)
~($choice can go underneath $new-clothing)
~($choice can coexist with $new-clothing)
You can't wear (the $new-clothing)
without first removing (the $choice).
(perform [wear $new-clothing])
(current player $actor)
*($old-clothing is #wornby $actor)
~($old-clothing is underneath $)
($old-clothing can go underneath $new-clothing)
(narrate wearing $new-clothing over $old-clothing)
(now) ($new-clothing is #wornby $actor)
(now) ($new-clothing is handled)
(now) ($old-clothing is underneath $new-clothing)
(narrate wearing $new-clothing over $old-clothing)
You put on (the $new-clothing)
over (the $old-clothing).
Removing layered clothes is simpler.
%% Removing rules
(prevent [remove $covered])
($covered is underneath $covering)
You can't remove (the $covered)
without first removing (the $covering).
(perform [remove $covering])
(current player $actor)
*($covered is #wornby $actor)
($covered is underneath $covering)
(narrate removing $covering exposing $covered)
(now) ($covering is #heldby $actor)
(now) ($covering is handled)
(now) ~($covered is underneath $)
(narrate removing $covering exposing $covered)
You take off (the $covering),
exposing (the $covered).
One issue is initialization at the start of the game, if you want the player to start clothed in layers you have to manually set up the ($ is underneath $)
relationships, which isn’t hard but tedious.
EDIT: Tried something new, a necklace subclass that can coexist with itself, allowing you to put on and remove them in any order without them layering. This seems to work fine, but it’s becoming clear that having to write coexist rules for every pair of subclass is going to get unwieldy. I’m trying to think of a way to infer coexist rules without having to write them all out.
%% Necklace
(clothing *(necklace $))
(possession name (necklace $))
necklace
(plural dict (necklace $))
necklaces
((necklace $) can coexist with (socks $))
((necklace $) can coexist with (shoes $))
((necklace $) can coexist with (underwear $))
((necklace $) can coexist with (pants $))
((necklace $) can coexist with (necklace $))