<html>
 <head>
  <link rel="stylesheet" type="text/css" href="/omega_lite.css"/>
  <title>xMOO pseudo-hierarchy</title>
 </head>
 <body>
  <div id="faux-header">
   <div id="faux-branding"><a href="/">[...]</a></div>
   <br/>
   <div id="faux-nav">&nbsp;</div>
   <br/>
  </div>
  <h1 id="title">xMOO object hierarchy!</h1>
  <div id="content">
  <code class="pre">
" 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(<old stance>, <new stance>)";
"";
"what <player> does when stance changes from <old> to <new>";
{old, new} = args;
if (old == "sleep")
  if (new == "sit")
    return "%N %<wakes> up and %<pulls> %r into a sitting position.";
  elseif (new == "stand")
    return "%N %<wakes> and %<stands> up.";
  elseif (new == "lean")
    return "%N %<wakes> up and %<leans> over.";
  elseif (new == "rest")
    return "%N %<wakes> up, but %<remains> resting.";
  elseif (new == "lie")
    return "%N %<wakes> up.";
  else
    return "";
  endif
else
  if (new == "sit")
    return "%N %<sits> down.";
  elseif (new == "stand")
    return "%N %<stands> up.";
  elseif (new == "lean")
    return "%N %<leans> over.";
  elseif (new == "rest")
    return "%N %<slumps> down on the ground and %<rests>.";
  elseif (new == "lie")
    return "%N %<lies/lie> down on the ground.";
  else
    return "%N %<curls> up on the ground and %<dozes> 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 %<is/are> ", 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 %<is/are> 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 %<is/are> ", 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 
   </code>
  </div>
 </body>
</html>