In XVAN, the interpreter checks if you try to move something into itself, but not if you move something into a contained object (as in CPB’s cup example). So I made a test story how I could handle this.
The approach is that if you want to move something in a contained object, you take the contained object out first. Consequence is that if you are holding neither object you will end up holding the contained object with the other object in it. But this seems fair to me: if there are two stacked bowls on the floor and you want to put the lower one in the upper one, you must pick up the upper one first.
Here’s transcript output:
=====================================
XVAN transcript for: Containment
version: 1.0
=====================================
> look
Laboratory
You are in the laboratory.
There is a wooden table here.
On the wooden table is a red bowl.
In the red bowl is a blue bowl.
> * now, let's put the red bowl in the blue bowl and see what happens
> put red in blue
Taking the blue bowl out of the red bowl first...
Blue bowl: taken.
Taking the red bowl...
Red bowl: taken.
The red bowl is now in the blue bowl.
> i
You are carrying:
a blue bowl
in the blue bowl is a red bowl
> * we are carrying both bowls, because we took the blue bowl out first
> put bowls on table
The blue bowl is now on the wooden table.
> get red
Red bowl: taken.
> l
Laboratory
You are in the laboratory.
There is a wooden table here.
On the wooden table is a blue bowl.
> * now put the red bowl in the blue bowl and see that it doesn't take the blue bowl first
> put red in blue
The red bowl is now in the blue bowl.
> l
Laboratory
You are in the laboratory.
There is a wooden table here.
On the wooden table is a blue bowl.
In the blue bowl is a red bowl.
> take blue
Blue bowl: taken.
> i
You are carrying:
a blue bowl
in the blue bowl is a red bowl
> * now put the blue bowl in the red bowl while we are carrying it
> put blue in red
Taking the red bowl out of the blue bowl first...
Red bowl: taken.
The blue bowl is now in the red bowl.
> q
Do you really want to quit?
Y/n: y
And here’s the source text, trigger t_put does the work.
TITLE "Containment"
VERSION "1.0"
AUTHOR "Marnix van den Bos"
$insert "XVAN Library v1-3-1.lib"
#-------------------------------------------------------------------------------
$LOCATION l_laboratory
DESCRIPTIONS
d_sys "the laboratory"
d_entr_long "\nYou are in the laboratory.\n\n"
d_entr_short "\nYou are in the laboratory.\n\n"
TRIGGERS
"put [o_subject] in [o_spec]" -> t_put
t_put
if owns(o_spec, o_subject) then
print("[the] [o_subject] is already in [the] [o_spec].\n")
disagree()
endif
if owns(o_subject, o_spec) then
# the specifier is in the subject
print("\nTaking the [o_spec] out of [the] [o_subject] first...\n")
if not(try(o_actor, 0, 1, "take [o_spec]")) then
# forget the whole thing
disagree()
endif
endif
# maybe we were not holding the subject
# we must hold something before we can put it in something else
if not(owns(o_actor, o_subject)) then
print("\nTaking the [o_subject]...\n")
if not(try(o_actor, 0, 1, "take [o_subject]")) then
disagree()
endif
endif
# finally, put the subject in the specifier
if not(try(o_actor, 0, 1, "put [o_subject] in [o_spec]")) then
disagree()
endif
END_LOC
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
$OBJECT o_table
DESCRIPTIONS
d_sys "the wooden table"
d_exa "A wooden table.\n"
d_entr_long "There is a wooden table here.\n"
d_entr_short "There is a wooden table here.\n"
CONTAINED in l_laboratory
FLAGS
f_supporter = 1
END_OBJ
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
$OBJECT o_red_bowl
DESCRIPTIONS
d_sys "the red bowl"
d_exa "A red bowl, with rooom for another bowl.\n"
d_entr_long "There is a red bowl here.\n"
d_entr_short "There is red bowl here.\n"
CONTAINED on o_table
FLAGS
f_takeable = 1
f_container = 1
f_open = 1
TRIGGERS
"i" -> t_i
END_OBJ
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
$OBJECT o_blue_bowl
DESCRIPTIONS
d_sys "the blue bowl"
d_exa "A blue bowl, with rooom for another bowl.\n"
d_entr_long "There is a blue bowl here.\n"
d_entr_short "There is blue bowl here.\n"
CONTAINED in o_red_bowl
FLAGS
f_takeable = 1
f_container = 1
f_open = 1
TRIGGERS
"i" -> t_i
END_OBJ
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
$OBJECT o_player
# The o_player object is mandatory and represents the human player.
DESCRIPTIONS
d_sys "You", "me", "I", "head"
d_exa "The average adventurer.\n"
d_init "Test game for containment.\n\n"
CONTAINED in l_laboratory
FLAGS
f_lit = 1
f_seenbefore = 1
f_alive = 1
f_quenched = 0
f_may_save = 1
f_verbose = 0
f_first = 1
f_fixed = 0
f_any = 0 # exclude from t_reveal
f_verb_help = 1
f_exits = 0 # for the 'exits' command
ATTRIBUTES
r_is = are
r_have = have
r_do = do
r_nr_to_reveal = 0
r_next_dir = %none
r_dest = %none
r_random = 0
r_score = 0
r_max_score = 250 # 5 times 50
r_key_blocked = 0
TRIGGERS
t_entrance
agree()
t_init
background(blue)
printcr(d_init)
printcr("Hit enter...\n")
hitanykey()
clearscreen()
entrance(owner(%this)) # act as if the player just entered the room
stoptimer(m_init) # served its purpose
t_move
if valdir(l_location, %dir) then
# it's a valid direction
if exit(l_location) then
# no object objects to the player leaving the room
move(o_player, %dir) # move updates current location
entrance(l_location)
endif
else
nomatch() # let other objects or verb default code react.
endif
agree()
END_OBJ
#-------------------------------------------------------------------------------