xMOO object hierarchy!
" the furniture object needs much better messages (as I didn't work out how to store the multitude of sit/stand/lean/rest/sleep in/on/beside/etc messages, much less shifting [lean -> stand, rest -> sleep, &c] messages), 'cause right now it generates a generic message that doesn't refer to existing stance.
" this also needs better display: using messages are not printed in room or when looking at furniture. players aren't grouped by furniture.
" maybe also incorporate the .squeeze & other shifting/next to/shoving/fall actions from yudJ's exceptionally social furniture
" this ALSO needs to mess w/ player actions (when sleeping can't use non-@* commands aside from 'wake'; when sitting can't move, close doors; etc), but that's more of a general stance issue.
@prop $xplayer.stance "stand" r
@prop $xplayer.furniture {#-1, ""} r
@verb $xplayer:"sit stand lean rest sleep lie" none none none rd
@program $xplayer:sit
if (this.stance != verb || `this.furniture[1] != #-1 ! E_RANGE => 0')
oldstance = this.stance;
player:set_stance(verb);
$you:say_action(this:stance_action(oldstance, verb));
else
player:tell("You're already doing that.");
endif
.
@verb $xplayer:wake any none none rd
@program $xplayer:wake
if (dobjstr && dobjstr != "up")
this:my_explain_syntax(caller, verb, args);
return;
endif
if (this.stance != "sleep")
player:tell("You're not sleeping!");
else
player:set_stance("stand");
$you:say_action(this:stance_action("sleep", "stand"));
endif
.
@verb $xplayer:my_explain_syntax tnt
@program $xplayer:my_explain_syntax
{caller, verb, ?args = {}, ?msg = ""} = args;
r = 0;
if (verb == "wake")
player:tell("Try this instead: wake[ up].");
r = 1;
endif
if(msg)
player:tell(msg);
r = 1;
endif
return r;
.
@verb $xplayer:stance_action tnt
@program $xplayer:stance_action
":stance_action(, )";
"";
"what does when stance changes from to ";
{old, new} = args;
if (old == "sleep")
if (new == "sit")
return "%N % up and % %r into a sitting position.";
elseif (new == "stand")
return "%N % and % up.";
elseif (new == "lean")
return "%N % up and % over.";
elseif (new == "rest")
return "%N % up, but % resting.";
elseif (new == "lie")
return "%N % up.";
else
return "";
endif
else
if (new == "sit")
return "%N % down.";
elseif (new == "stand")
return "%N % up.";
elseif (new == "lean")
return "%N % over.";
elseif (new == "rest")
return "%N % down on the ground and %.";
elseif (new == "lie")
return "%N % down on the ground.";
else
return "%N % up on the ground and % off.";
endif
endif
.
@verb $xplayer:set_stance tnt
@program $xplayer:set_stance
if (player != this)
return E_PERM;
endif
{stance, ?furniture = #-1, ?prep = ""} = args;
this.stance = stance;
if (length(this.furniture) == 2 && `valid(this.furniture[1]) ! E_TYPE => 0')
`this.furniture[1]:drop_user(this) ! ANY';
endif
if (furniture != #-1 && prep)
"add this to furn using list?";
this.furniture = {furniture, prep};
else
this.furniture = {#-1, ""};
endif
.
@verb $xplayer:moveto tnt
@program $xplayer:moveto
if (this.stance != "stand")
$you:say_action(this:stance_action(this.stance, "stand"));
this:set_stance("stand");
endif
pass (@args);
.
@create $thing called "generic furniture",furniture
@chmod furniture +rf
@prop furniture.valid_actions {}
"looks like {{"sit", {"on"}}, {"rest", {"on"}}, {"sleep", {"on"}}}
@prop furniture.capacity 0
@prop furniture.users {}
".sit_failed_msg, .sit_succeeded_msg, .osit_failed_msg, .osit_succeeded_msg
".stand_failed_msg, .stand_succeeded_msg, .ostand_failed_msg, ostand_succeeded_msg
".sit_to_stand_msg, .sit_to_rest_msg, etc
if(`player.furniture[1] == #-1 ! ANY => 1')
"not interacting with other furniture";
return this:(verb)+"_msg";
else
"note that this is called even if player is shifting from another piece of furniture.";
shiftverb = tostr(`player.furniture[2] ! ANY => ""', "_to_", verb, "_msg");
if($object_utils:has_callable_verb(this, shiftverb))
return this:(shiftverb);
else
return this:(verb)+"_msg";
endif
endif
@verb furniture:drop_user tnt rxd
@program furniture:drop_user
user = args[1];
this.users = setremove(this.users, user);
.
@verb furniture:"g*et ta*ke" this none none rxd
@program furniture:get
if (this.users)
player:tell("You can't pick that up; there are people on it.");
else
pass(@args);
endif
.
@verb furniture:"sit stand lean rest sleep lie" any any any rd
@program $furniture:sit
actions = $list_utils:assoc(verb, this.valid_actions);
if (player.location != this.location)
player:tell("I don't see that here.");
return;
endif
if(prepstr)
prepstr = $code_utils:short_prep(prepstr);
elseif (!prepstr && actions)
try
prepstr = actions[2][1];
except (E_RANGE)
"malformed actions list-- verb with no preps";
player:tell("You can't ", verb, " on that.");
return;
endtry
endif
this:_check_users();
if (actions == {} || (actions && !(prepstr in actions[2])))
if(!prepstr)
prepstr = "on";
endif
player:tell("You can't ", verb, " ", prepstr, " that.");
return;
elseif (!this:is_unlocked_for(player))
player:tell("You can't use that.");
return;
elseif (length(this.users) >= this.capacity)
player:tell("You can't fit there.");
return;
elseif (player in this.users && `player.stance == verb && player.furniture[2] == prepstr ! E_PROPNF => 0')
player:tell("You're already doing that.");
return;
endif
player:set_stance(verb, this, prepstr);
this.users = setadd(this.users, player);
$you:say_action(tostr("%N %<", verb == "lie" ? "lies/lie" | verb + "s", "> ", prepstr, " ", this:title(), "."));
.
@verb furniture:_check_users tnt
@program furniture:_check_users
":_check_users()";
"";
"Goes through the list of current users and checks to see if 1) they're in the same room as the furniture and 2) they're using this furniture. If not, the furniture silently drops them from the users list. This is run right before anyone tries to use the furniture.";
"";
"(this is needed because despite my best efforts, certain things still send the furniture state into disarray-- most notably, a wizard using the furniture [since $wiz:moveto is very direct] or someone disconnecting into Limbo while using the furniture-- at which point the user will continue taking up a capacity slot.)";
for u in (this.users)
if(u.location != this.location || `u.furniture[1] != this ! E_PROPNF, E_RANGE => 1')
this:drop_user(u);
endif
endfor
.
"(this is "generic detailed room")
@program $detailed_room:tell_contents
{contents, ctype} = args;
if (!this.dark && contents != {} && ctype == 4)
players = things = {};
for x in (contents)
if (is_player(x))
players = {@players, x};
else
things = {@things, x};
endif
endfor
if (!this.integrate)
for t in (things)
if ($object_utils:has_readable_property(t, "look_msg"))
player:tell($string_utils:pronoun_sub(t.look_msg, player, t, this));
else
player:tell("You see ", t:title(), " here.");
endif
if ($object_utils:isa(t, $furniture) && (d = $set_utils:intersection({player, @players}, t.users)))
"ideally, this shouldn't need the player if/else block, and players who have the same stance & prep should be grouped together w/ $string_utils:title_list (along w/ player if so).";
for p in (d)
if(p == player)
player:tell($string_utils:pronoun_sub(tostr(" %N % ", p.stance == "lie" ? "ly" | p.stance, p.stance == "sit" ? "ting " | "ing ", p.furniture[2], " it."), $you, t));
else
player:tell($string_utils:pronoun_sub(tostr(" %N % here, ", p.stance == "lie" ? "ly" | p.stance, p.stance == "sit" ? "ting " | "ing ", p.furniture[2], " %t."), p, t));
endif
endfor
players = $set_utils:difference(players, t.users);
endif
endfor
endif
for p in (players)
player:tell($string_utils:pronoun_sub(tostr("%N % ", p.stance == "lie" ? "ly" | p.stance, (p.stance == "sit" ? "ting" | "ing"), " here."), p));
endfor
else
pass(@args);
endif
.
---
"huh integration for things like 'sit down' or moving onto objects that don't exist
@verb $xplayer:last_huh tnt rxd
@program $xplayer:last_huh
{verb, args} = args;
if (verb in {"sit", "stand", "lie", "lean", "rest", "sleep"})
$xplayer_huh:(verb)(@args);
return 1;
else
return 0;
endif
.
$xplayer_huh:"sit stand" tnt rxd
if