@q
@program jlook.muf
1 99999 d
i
( jlook.muf    v1.2    Jessy @ FurryMUCK    11/99
  
  A cmd-look with looktrap support, false objects, MUSH emultation 
  for +view, %r, %t, and %b, and extensive user-preference options.
  
  INSTALLATION:
  
  Set the program M3 and link a global action to it.
    
    @act look;loo;lo;l;lookat;@bdescribe;@bdesc;+view=#0
    @link look=jlook.muf
  
  If you are using fb6 or later, or a modified server that has an
  autolook_cmd system parameter, you should @tune the parameter to
  something *different* than 'look', and append that string to 
  the command name:
  
    @act look;loo;lo;l;lookat;@bdescribe;@bdesc;+view;rlook=#0
    @tune autolook_cmd=rlook
  
  This will allow jlook to determine whether a player is looking at
  a room in repsonse to an explicit user command or as a result of
  moving to a different room. This allows a cleaner syntax.
  
  CONFIGURATION:
  
  Default user preferences are inherited from the flags automatically
  set in jlook.muf's _prefs/look/flags property. After the program
  has been installed and used at least once, you can manaually edit
  this property to change default user preferences. See preference
  below.
  
  USE:
  
    look ................................ Show your location
    look <obj|detail|item> .............. Show <obj|detail|item>
    look #detail <obj>/<detail>=<desc> .. Create detail on <obj>
    look #item <obj>/<item>=<desc> ...... Create item on <obj>
    look #mask <detail|item> ............ Mask <detail|item>
    look #!mask <obj>/<detail|item> ..... Unmask <detail|item>
    look #unmask <obj>/<detail|item> .... Unmask <detail|item>
    look #!detail <obj>/<detail> ........ Remove <detail> from <obj>
    look #!item <obj>/<item> ............ Remove <item> from <obj>
    +view ............................... List all unmasked details
    +view <obj> ......................... List all details on <obj>
    +view <obj>=<detail ................. Show <detail> on <obj>
    look #prefs <option>=<value> ........ Set pref <option> to <value>
  
  'Details' are lookable features of an item. When masked, they do not 
  appear in a Details list. 'Items' are false objects. When masked, 
  they do not appear in a Contents or Carrying list. Details and items 
  may be looked at whether masked or unmasked.
  
  Valid preference settings include:
    
    connections = <yes|no> ... Yes = show connection info w/ player names
    details = <yes|no> ....... Yes = show detail list with descs
    exits = <yes|no> ......... Yes = show exit list with descs
    horizontal = <yes|no> .... Yes = format contents lists horizonatlly
    static = <yes|no> ........ Yes = don't use dynamic descs
    quell = <yes|no> ......... Yes = Do not show room descs in travel
  
  To set defaults, set the _prefs/look/flags property on the program
  object to a string that includes the first letter of each preference
  you want set 'yes' by default. For example, to enable Connections,
  Details, and Exits by default, do...
    
    @set jlook=_prefs/look/flags:CDE
  
  Detail data is stored in an object's _details/ propdir. False object
  data is stored in an object's _items/ propdir.
  
  jlook.muf may be freely ported. Please comment any changes.
    
                                        jessydupres@yahoo.com
)
  
$define ourVersion "1.0" $enddef
 
$define Tell me @ swap notify $enddef
 
$define
  DoClearStack begin depth while pop repeat
$enddef
  
$define                               (* add a type check for puppets *)
  puppet?
  dup "Z" flag?
  swap thing? and if
    1
  else
    0
  then
$enddef
 
lvar lib
lvar ourArg
lvar ourObj
lvar ourOpt
lvar ourBool
 
(2345678901234567890123456789012345678901234567890123456789012345678901) 
 
: DoInitProgram  (  --  )         (* set default program config props *)
  
  prog "_prefs/look/flags" "CDSE"   setprop
  prog "_version"       ourVersion setprop
;
  
: DoInitPlayer  (  --  )            (* set default player config prop *)
  
  me @ "_prefs/look/flags"
  prog "_prefs/look/flags"
  getpropstr setprop
  me @ "_prefs/look/version" 
  ourVersion setprop
;
 
: DoInsertControls  ( s -- s' )  (* replace chars that would confuse
                                    directory system or allow setting
                                    wizprops with harmless strings   *)
  dup "/" instr if
    "=$sl$=" "/" subst
  then
    
  dup ":" instr if
    "=$co$=" ":" subst
  then
    
  dup "*" instr if
    "=$a$=" "*" subst
  then
    
  dup "." instr if
    "=$p$=" "." subst
  then
    
  dup "@" instr if
    "=$at$=" "@" subst
  then
    
  dup "~" instr if
    "=$t$=" "~" subst
  then
;
 
: DoRemoveControls  ( s -- s' )       (* remove control chars from s *)
    
  dup "=$sl$=" instr if
    "/" "=$sl$=" subst
  then
    
  dup "=$co$=" instr if
    ":" "=$co$=" subst
  then
    
  dup "=$a$=" instr if
    "*" "=$a$=" subst
  then
    
  dup "=$p$=" instr if
    "." "=$p$=" subst
  then
    
  dup "=$at$=" instr if
    "@" "=$at$=" subst
  then
    
  dup "=$t$=" instr if
    "~" "=$t$=" subst
  then
;
 
: DoParseThis  ( d s -- s )     (* returns d's prop s, parsed for MPI *)
 
   dup 3 pick swap getpropstr 0 parseprop
;
 
: DoMainName  ( s -- s' )   (* return name str s, stripped of aliases *)
  
  dup ";" instr if
    dup ";" instr 1 - strcut pop
  then
;
  
: DoSortStrings-d  ( s ... s' i -- s ... s' )
                                 (* sort range of strings, descending *)
    
  dup  (* dup index: one copy is inner loop counter, other outer loop *)
  begin         (* begin outer loop: will step through range i times  *)
    dup while
      over
      begin  (* begin inner loop: step through range, comparing pairs *)   
        dup 1 > while
        dup 3 + pick over 3 + pick                        (* get pair *)
        over over strcmp 0 < if                            (* compare *)
          swap                                      (* swap if needed *)
        then
        3 pick 3 + put                                (* replace pair *)
        over 3 + put
        1 -                           (* decrement inner loop counter *)
      repeat                                        (* end inner loop *)
      pop
    1 -                               (* decrement outer loop counter *)
  repeat                                            (* end outer loop *)
  pop pop                                             (* pop counters *)
;
  
: DoOurMatch  ( s -- d )           (* return dbref for object named s *)
  
  match 
  dup #-1 dbcmp if
    me @ "I don't see that here." notify pid kill
  then
  dup #-2 dbcmp if
    me @ "I don't know which on you mean!" pid kill
  then
;
 
: DoGetContents  (  -- str rng ) 
                              (* return contents of ourObj as str rng *)
  ourObj @ contents
  begin                                      (* put contents on stack *)
    dup while
    dup me @ dbcmp if                                    (* skip user *)
      next continue
    then
    dup room? if                                        (* skip rooms *)
      next continue
    then
    dup "D" flag?                        (* skip others' dark objects *)
    me @ 3 pick controls not and if
      next continue
    then
    dup program?                             (* skip others' programs *)
    me @ 3 pick controls not and if
      next continue
    then
    dup player? if                    (* handle dark_sleepers sysparm *)
      dup awake? not
      "dark_sleepers" sysparm "yes" smatch and if
        next continue
      then
    then
    dup next
    swap 
    dup player? if                            (* this way for players *)
      me @ over controls if
        dup unparseobj
      else
        dup name
      then                           (* add connection info if pref'd *)
      me @ "_prefs/look/flags" getpropstr "C" instr if
        over awake? if
          over descriptors
          begin dup 1 > while rot pop 1 - repeat
          not if -1 exit then
          descrcon conidle
          300 > if
            " [idle]"
          else
            " [awake]"
          then
        else
          " [asleep]"
        then
        strcat
        swap pop
      else
        swap pop
      then
    else
      me @ over controls if
        unparseobj
      else
        name
      then
    then  
    swap
  repeat
  pop
                                         (* add false objects to list *)
  ourObj @ "_items/" nextprop
  begin
    dup while
    ourObj @ over "_masked/" "_items/" subst
    getpropstr not if
      dup "" "_items/" subst DoMainName 
      dup "_masked/" "_items/" subst
      ourObj @ swap getpropstr if
        swap 
      else
        pop
      then
    then
    ourObj @ swap nextprop
  repeat
  pop
  depth                               (* add count... now its a range *)
;
 
: DoContentsLabel  (  -- s )   (* return 'Contents: ' or 'Carrying: ' *)
 
  ourObj @ player? if
    "Carrying: "
  else
    "Contents: "
  then
;
 
: DoAddFlag  ( s --  )            (* add flag s to user's _prefs/look/flags *)
  
  me @ "_prefs/look/flags" getpropstr over instr not if
    me @ "_prefs/look/flags" over over getpropstr
    4 rotate toupper strcat setprop
  else
    pop
  then
  me @ ">>  Set." notify
;
 
: DoDelFlag  ( s --  ) (* delete flag s from user's _prefs/look/flags *)
 
  me @ "_prefs/look/flags" over over getpropstr
  "" 5 rotate subst setprop
  me @ ">>  Set." Tell
;
 
: DoVerticalContents  ( str rng --  )     (* show contents vertically *)
 
  DoContentsLabel Tell
  begin 
    dup while
    depth rotate Tell
    1 -
  repeat
  pop
;
 
: DoContents  ( str rng --  )          (* show ourObj's contents list *)
 
                                     (* this way for horizontal lists *)
  me @ "_prefs/look/flags" getpropstr "H" instr if
    0 ourBool !
    dup 80 > if
      DoVerticalContents
      ">>  Whoa! Too many objects to show in Horizontal format." Tell
      ">>  Your preference is still set to Horizontal format." Tell
      exit
    then
    dup 1 = if
      pop DoContentsLabel swap strcat Tell
    else
    dup 2 = if
      pop swap " and " strcat swap strcat 
      DoContentsLabel swap strcat Tell
    else
      1 -
      "and " rot strcat swap
      begin
        dup while
        rot ", " strcat rot strcat
        swap 1 -
      repeat
      pop 
      DoContentsLabel swap strcat Tell
    then then
  else                                 (* this way for vertical lists *)
    DoVerticalContents
  then
;
 
: DoPrefHelp  (  --  )            (* show help for user pref settings *)
  
  me @
  "Preferences control the formatting of what is shown when you look "
  "at something. The syntax for setting preferences is:" strcat Tell
  
  " " Tell
  "  look #prefs <option> = <yes|no>" Tell " " Tell
  
  "Valid options are:" Tell " " Tell
  
  "  connections = <yes|no> ... Yes = show connection info w/ player names"
  Tell
  "  details = <yes|no> ....... Yes = show detail lists with descs"
  Tell
  "  exits = <yes|no> ......... Yes = show exit lists with descs"
  Tell
  "  horizontal = <yes|no> .... Yes = format contents lists horizonatlly"
  Tell
  "  static = <yes|no> ........ Yes = don't use variable descs"
  Tell
  "  quell = <yes|no> ......... Yes = Do not show room descs in travel"
  Tell " " Tell
  
  "If you have preferences set to Quell room descs, you can still see the "
  "description of a room by explicitly typing 'look here'. " 
  "Options and values do not have to be typed completely: the following "
  "are equivalent commands:" strcat strcat strcat Tell " " Tell
  
  "  look #preferences connections = yes" Tell
  "  l #p c=y" Tell " " Tell
  
  "Builders: set a room '_obv_exits:yes' to force exit lists." Tell
;
 
: DoDescHelp  (  --  )                  (* show help on dynamic descs *)
  
  "Jlook supports 'dynamic descs' for rooms, using the following "
  "rules: if you have seen a room five times or fewer, it shows the "
  "full desc. If you have seen the room more than five times, and "
  "have seen it at least once during the past week, and a brief desc "
  "for the room is provided, it will only show the brief desc. If you "
  "have seen the room more than 10 times, and at least once during the "
  "past week, it will only show the room name. "
  strcat strcat strcat strcat strcat strcat 
  
  "autolook_cmd" sysparm if
    "Explicitly entering a 'look' or 'l' command will force "
    "the full description. " strcat
  else
    "You can force look to show the full description by typing "
    "'l' or 'look #full'. " strcat
  then
  strcat
  
  "To enable dynamic descs, set the 'static' preference to 'no'. "
  "Builders may set rooms _full_look:yes to force a full description."
  strcat strcat Tell " " Tell
  
  "autolook_cmd" sysparm if
    "  look ........................... Show full desc of your location"
  else
    "  look #full ..................... Show full desc of your location"
  then
  Tell
  "  @bdesc ......................... Show brief desc of your location"
  Tell
  "  @bdesc here = <brief desc> ..... Set a brief room desc"
  Tell " " Tell
;
 
: DoLookatHelp  (  --  )                   (* show lookat help screen *)
  
  "The '$command' command is used to look at objects or items carried "
  "by another player." strcat command @ "$command" subst Tell " " Tell
  
  "Syntax:  $command <object>"
  command @ "$command" subst Tell " " Tell
;
 
: DoHelp  (  --  )                                (* show help screen *)
  
  me @ " " notify
  prog name "(#" strcat prog intostr strcat ")" strcat Tell " " Tell
  
  command @ "lookat" smatch if
    DoLookatHelp exit
  then
  
  ourArg @ if
    "prefs" ourArg @ stringpfx "#prefs" ourArg @ stringpfx 
    "preferences" ourArg @ stringpfx "#preferences" ourArg @ stringpfx 
    or or or if
      DoPrefHelp exit
    then
  then
  
  ourArg @ if
    "descs" ourArg @ stringpfx "#descs" ourArg @ stringpfx or if
      DoDescHelp exit
    then
  then
  
  "  look .................................. Show your location"
  Tell
  "  look <obj|detail|item> ................ Show <obj|detail|item>"
  Tell
  "  look #detail <obj>/<detail>=<desc> .... Create detail on <obj>"
  Tell
  "autolook_cmd" sysparm not if
    "  look #full ............................ Show full desc of room"
    Tell
    "  l ..................................... Show full desc of room"
    Tell
  then
  "  look #item <obj>/<item>=<desc> ........ Create item on <obj>"
  Tell
  "  look #mask <obj>/<detail|item> ........ Mask <detail|item>"
  Tell
  "  look #!mask <obj>/<detail|item> ....... Unmask <detail|item>"
  Tell
  "  look #!detail <obj>/<detail> .......... Remove <detail> from <obj>"
  Tell
  "  look #!item <obj>/<item> .............. Remove <item> from <obj>"
  Tell
  trig name "+view" instr if
  "  +view ................................. List all unmasked details"
  Tell
  "  +view <obj> ........................... List all details on <obj>"
  Tell
  "  +view <obj>/<detail> .................. Show <detail> on <obj>"
  Tell
  then
  "  look #prefs <option>=<value> .......... Set pref <option> to <value>"
  Tell " " Tell
  
  "'Details' are lookable features of an object. 'Items' are false "
  "objects. When masked, they do not appear in lists. Details and "
  "Items may still be looked at when masked.  See 'look #help prefs' "
  "for help on user-preference configurations. See 'look #help descs' "
  "for help on dynamic descs."
  strcat strcat strcat strcat Tell
;
 
: DoSetPrefs  (  --  )                      (* set user's preferences *)
  
  ourArg @ not if
    DoPrefHelp exit
  then
   
  ourArg @ "=" instr if                                      (* parse *)
    ourArg @ dup "=" instr strcut strip
    swap dup strlen 1 - strcut pop strip
    ourArg !
  else
    "" ourArg @ strip ourArg !
  then
  
  "connections" ourArg @ stringpfx if     (* turn con info off|on ... *)
    "yes" over stringpfx if
      "C" DoAddFlag pop
     else
      "no" swap stringpfx if
        "C" DoDelFlag
       else
         ">>  The 'connections' option must be either 'yes' or 'no'" Tell
       then
     then
  else
  "exits" ourArg @ stringpfx if         (* turn exit lists off|on ... *)
    "yes" over stringpfx if
      "E" DoAddFlag pop
     else
      "no" swap stringpfx if
        "E" DoDelFlag
       else
         ">>  The 'exits' option must be either 'yes' or 'no'" Tell
       then
     then
  else
  "details" ourArg @ stringpfx if     (* turn detail lists off|on ... *)
    "yes" over stringpfx if
      "D" DoAddFlag pop
     else
      "no" swap stringpfx if
        "D" DoDelFlag
       else
         ">>  The 'details' option must be either 'yes' or 'no'" Tell
       then
     then
  else                   (* turn horizonatl contents lists off|on ... *)
  "horizontal" ourArg @ stringpfx if 
    "yes" over stringpfx if
      "H" DoAddFlag pop
     else
      "no" swap stringpfx if
        "H" DoDelFlag
       else
         ">>  The 'horizontal' option must be either 'yes' or 'no'" Tell
       then
     then
  else
  "quell" ourArg @ stringpfx if (* turn room desc quelling off|on ... *)
    "yes" over stringpfx if
      "Q" DoAddFlag pop
     else
      "no" swap stringpfx if
        "Q" DoDelFlag
       else
         ">>  The 'quell' option must be either 'yes' or 'no'" Tell
       then
     then
  else
  "static" ourArg @ stringpfx if     (* turn dynamic descs off|on ... *)
    "yes" over stringpfx if
      "S" DoAddFlag pop
     else
      "no" swap stringpfx if
        "S" DoDelFlag
       else
         ">>  The 'static' option must be either 'yes' or 'no'" Tell
       then
     then
  else
    "Preference not found." Tell
  then then then then then then
;
 
: DoShowBriefDesc  (  --  )               (* show ourObj's short desc *)
  
  ourObj @ not if
    loc @ ourObj !
  then
  ourObj @ "_/bde" getpropstr if
    ourObj @ "_/bde" DoParseThis 
    " " "%b" subst
    "%" "%%" subst
    "     " "%t" subst
    "%r" explode
    begin
      dup while
      me @ rot pronoun_sub Tell
      1 -
    repeat
    pop
  else
    ourObj @ room? not if
      "You see nothing special." Tell
    then
  then
;
 
: DoSetBriefDesc  (  --  )                 (* set a brief description *) 
  
  ourArg ! ourArg @ if
    "#help" ourArg @ stringpfx if DoDescHelp exit then
  
    ourArg @ "=" instr if
      ourArg @ dup "=" instr strcut
      ourOpt !
      strip dup strlen 1 - strcut pop strip ourArg !
      ourArg @ not if
        "Syntax: $command <room>=<brief description>"
        command @ "$command" subst Tell exit
      then
      ourArg @ match
      dup #-1 dbcmp if
        "I don't see that here." Tell DoClearStack exit
      then
      dup #-2 dbcmp if
        "I don't know which one you mean!" Tell DoClearStack exit
      then
      dup #-3 dbcmp if
        "I don't see that here." Tell DoClearStack exit
      then
      ourArg !
  
      me @ ourArg @ controls not if
        "Permission denied." Tell DoClearStack exit
      then
  
      ourArg @ "_/bde" ourOpt @ setprop
      "Brief description set." Tell
      ourArg @ room? not if
        "Note: brief descriptions on non-room objects have no effect."
        Tell
      then
    else
      "Syntax: $command <room>=<brief description>"
      command @ "$command" subst Tell
    then
  else
    DoShowBriefDesc
  then
;
 
: DoSetMasked  (  --  )                        (* set a detail masked *)
  
  ourArg @ "/" instr if                                      (* parse *)
    ourArg @ dup "/" instr strcut 
    strip swap strip
    dup strlen 1 - strcut pop strip
  
    DoOurMatch
  
    me @ over controls not if                     (* check permission *)
      "Permission denied." Tell exit
    then
    "_details/" rot strcat
    over over getpropstr if
      "_masked/" "_details/" subst
      ourBool @ if
        remove_prop
        ">>  Detail unmasked." Tell
      else
        "1" setprop
        ">>  Detail masked." Tell
      then
    else
      "_items/" "_details/" subst
      over over getpropstr if
        "_masked/" "_items/" subst
        ourBool @ if
          remove_prop
          ">>  Item unmasked." Tell
        else
          "1" setprop
          ">>  Item masked." Tell
        then
      else
        "I don't see that detail or item." Tell
      then
    then
  else
    ">>  Syntax:  look #mask <object>/<detail>" Tell
  then
;
  
: DoSetUnMasked  (  --  )                          (* unhide a detail *)
  
  1 ourBool !
  DoSetMasked
;
  
: DoSetDetail  (  --  )                             (* set a looktrap *)
  
  ourArg @ "/" instr if
    ourArg @ dup "=" instr strcut 
    strip swap
    strip dup strlen 1 - strcut pop strip
    dup "/" instr if
      dup "/" instr strcut 
      strip swap
      strip dup strlen 1 - strcut pop strip
      DoOurMatch
      me @ over controls not if
        "Permission denied." Tell exit
      then
      dup exit? if
        ">>  Sorry, you may not set details on an exit."
        ourBool @ if "items" "details" subst then
        Tell
      then
      dup program? if
        ">>  Sorry, you may not set details on an program."
        ourBool @ if "items" "details" subst then
        Tell
      then
      ourBool @ if
        "_items/"
      else
        "_details/" 
      then
      rot DoInsertControls strcat rot setprop
      ">>  Set." Tell
    else
      ">>  Syntax: look #detail <object>/<name>=<description>"
      ourBool @ if "item" "detail" subst then
      Tell
    then
  else
    ">>  Syntax: look #detail <object>/<name>=<description>"
    ourBool @ if "item" "detail" subst then
    Tell
  then
;
 
: DoSetItem  (  --  )                           (* set a false object *)
  
  1 ourBool !
  DoSetDetail
;
  
: DoDelDetail  (  --  )                          (* remove a looktrap *)
  
    ourArg @ "/" instr if                                    (* parse *)
      ourArg @ dup "/" instr strcut 
      strip swap
      strip dup strlen 1 - strcut pop strip
      DoOurMatch                                      (* match object *)
      me @ over controls not if                   (* check permission *)
        "Permission denied." Tell exit
      then
      ourBool @ if                                (* find detail|item *)
        "_items/"
      else
        "_details/" 
      then                                               (* remove... *)
      rot DoInsertControls strcat over over getpropstr if 
        remove_prop
        ">>  Set." Tell
      else                              (* ... or notify couln't find *)
        pop pop
        ">>  I don't see what $thingamabob you want to remove."
        ourBool @ if
          "item"
        else
          "detail"
        then
        "$thingamabob" subst Tell
      then
    else
      ">>  Syntax: look #!detail <object>/<name>=<description>"
      ourBool @ if "item" "detail" subst then
      Tell
    then
;
 
: DoDelItem  (  --  )                        (* remove a false object *)
  
  1 ourBool !
  DoDelDetail
;
 
: DoExitList  (  --  )                  (* show list of obvious exits *)
  
  me @ location "_obv_exits" getpropstr not if
    me @ "_prefs/look/flags"                    (* check user's prefs *)
    getpropstr "E" instr not if exit then
  then
  
  DoClearStack                           (* clear stack, just in case *)
  ourObj @ exits
  begin
    dup while
    dup "D" flag? if                               (* skip dark exits *)
      next continue
    then
    dup getlink dup if                         (* skip unlinked exits *)
      room? if
        dup name DoMainName strip swap
      then
    else
      pop
    then
    next
  repeat
  pop     
  
  depth if                                            (* show results *)
    depth 1 = if
      "Exits:    " swap strcat Tell
    else
      depth 2 = if
        " and " strcat swap strcat "Exits:    " swap strcat Tell
      else
        "and " swap strcat
        begin
          depth 1 > while
          swap
          ", " strcat swap strcat
        repeat
        "Exits:    " swap strcat Tell
      then
    then
  then
;
 
: DoCommandList  (  --  )            (* show list of commands in room *)
  
  me @ location "_obv_exits" getpropstr not if
    me @ "_prefs/look/flags"                    (* check user's prefs *)
    getpropstr "E" instr not if exit then
  then
  
  DoClearStack                       (* clear the stack, just in case *)
  ourObj @ exits
  begin                                 (* put command names on stack *)
    dup while
    dup "D" flag? if                             (* skip dark actions *)
      next continue
    then
    dup getlink dup if                       (* skip unlinked actions *)
      program? if
        dup name DoMainName swap
      then
    else
      pop
    then
    next
  repeat
  pop
   
  depth if                                            (* show results *)
    depth 1 = if
      "Commands: " swap strcat Tell
    else
      depth 2 = if
        " and " swap strcat strcat
        "Commands: " swap strcat Tell
      else
        "and " swap strcat
        begin
          depth 1 > while
          swap
          ", " strcat swap strcat
        repeat
        "Commands: " swap strcat Tell
      then
    then
  then
;
 
: DoDetailList  (  --  )           (* show list of non-masked details *)
  
  me @ "_prefs/look/flags"                      (* check user's prefs *)
  getpropstr "D" instr not if exit then
  
  ourObj @ not if 
    "Syntax: $command <object>" 
    command @ "$command" subst Tell exit
  then
  
  DoClearStack                       (* clear the stack, just in case *)
  ourObj @ "_details/" nextprop
  begin
    dup while
    ourObj @ over "_masked/" "_details/" subst getprop if
      ourObj @ swap nextprop
      continue
    then
    ourObj @ over nextprop
    swap "" "_details/" subst DoRemoveControls DoMainName swap
  repeat
  pop
  
  depth if                                            (* show results *)
    depth 1 = if
      "Details:  " swap strcat Tell
    else
      depth 2 = if
        " and " swap strcat strcat 
        "Details: " swap strcat Tell
      else
        "and " swap strcat
        begin
          depth 1 > while
          swap
          ", " strcat swap strcat
        repeat
        "Details:  " swap strcat Tell
      then
    then
  then
;
 
: DoShowDetailDesc  ( d s --  )        (* show desc of details s on d *)
  
  dup not if  (* if we didn't find anything, notify with error & kill *)
    pop pop
    ourObj @ not if
      me @ "I don't see that here." Tell pid kill
    then
    ourObj @ #-2 dbcmp if
      me @ "I don't know which one you mean!" Tell pid kill
    then
    me @ "I don't see that here." Tell pid kill
  then
                                             (* show detail/item desc *)
  DoParseThis  
  " " "%b" subst
  "%" "%%" subst
  "     " "%t" subst
  "%r" explode
  begin
    dup while
    me @ rot pronoun_sub Tell
    1 -
  repeat
  pop
;
 
: DoCheckDetailObj  ( d -- s )  
  (* see if d holds detail|obj ourObj; return prop if so, or null str *)
  
  dup                                       (* check: is it a detail? *)
  "_details/" nextprop
  begin                                 (* begin detail-checking loop *)
    dup while
    dup "" "_details/" subst
    ";" explode
    begin                         (* begin detail-alias-checking loop *)
      swap ourArg @ stringpfx if
        begin                       (* begin extra-alias-popping loop *)
          dup 1 = if 
            break
          else
            swap pop
          then
          1 -
        repeat                        (* end extra-alias-popping loop *)
        pop
        1 break
      then
      1 -
      dup while
    repeat                          (* end detail-alias-checking loop *)
    if break then
    over swap nextprop
  repeat                                  (* end detail-checking loop *)
  
  dup not if                          (* check: is it a false object? *)
    pop dup
    "_items/" nextprop
    begin                                 (* begin item-checking loop *)
      dup while
      dup "" "_items/" subst
      ";" explode
      begin                         (* begin item-alias-checking loop *)
        swap ourArg @ stringpfx if
          begin                     (* begin extra-alias-popping loop *)
            dup 1 = if 
              break
            else
              swap pop
            then
            1 -
          repeat                      (* end extra-alias-popping loop *)
          pop
          1 break
        then
        1 -
        dup while
      repeat                          (* end item-alias-checking loop *)
      if break then
      over swap nextprop
    repeat                                  (* end item-checking loop *)
  then
;
 
: DoDetailObj  (  --  )    (* attempt to show object, detail, or item *)
  
  ourArg @ not if                                     (* check syntax *)
    "Syntax: $command <object|item|detail>"
    command @ "$command" subst Tell exit
  then
  
  ourArg @ "/" instr if                                 (* parse args *)
    ourArg @ dup "/" instr strcut strip
    ourArg ! dup strlen 1 - strcut pop strip ourObj !
  else
    "here" ourObj !
  then
  
  ourObj @ "*'s" smatch if
    ourObj @ dup strlen 2 - strcut pop
    strip ourObj !
  then
  
  ourObj @ match                                 (* match obj to look *)
  dup #-1 dbcmp if
    "I don't see that here." Tell pop exit
  then
  dup #-2 dbcmp if
    "I don't know which one you mean!" Tell pop exit
  then
  dup #-3 dbcmp if
    "I don't see that here." Tell pop exit
  then
  ourObj !
                                 (* check: is it an object in ourObj? *)
  ourArg @ DoInsertControls ourArg !
  
  ourObj @ DoCheckDetailObj dup if
    DoShowDetailDesc
  else
    pop ourObj @ contents
    begin
      dup while
      dup name ourArg @ stringpfx if
        dup "D" flag? if
          "You can't see that clearly." Tell pop pop exit
        else
          "_/de" DoParseThis Tell
          pop exit
        then
      then
      next
    repeat
    pop
    "I don't see that here." Tell 
  then
;
 
: DoLookat  (  --  )       (* attempt to show object, detail, or item *)
  
  ourArg @ not if                                     (* check syntax *)
    "Syntax: $command <object>"
    command @ "$command" subst Tell exit
  then
  
  ourArg @ " " instr if                                 (* parse args *)
    ourArg @ dup " " instr strcut strip
    ourArg ! strip ourObj !
  else
    ourArg @ ourObj !
  then
  
  ourObj @ "*'s" smatch if
    ourObj @ dup strlen 2 - strcut pop
    strip ourObj !
  then
  
  ourObj @ match                                 (* match obj to look *)
  dup #-1 dbcmp if
    "I don't see that here." Tell pop exit
  then
  dup #-2 dbcmp if
    "I don't know which one you mean!" Tell pop exit
  then
  dup #-3 dbcmp if
    "I don't see that here." Tell pop exit
  then
  ourObj !
                                 (* check: is it an object in ourObj? *)
  ourArg @ DoInsertControls ourArg !
  
  ourObj @ DoCheckDetailObj dup if
    DoShowDetailDesc
  else
    pop ourObj @ contents
    begin
      dup while
      dup name ourArg @ stringpfx if
        dup "D" flag? if
          "You can't see that clearly." Tell pop pop exit
        else
          "_/de" DoParseThis Tell
          pop exit
        then
      then
      next
    repeat
    pop
    "Syntax: $command <object>"
    command @ "$command" subst Tell 
    "Object not found." Tell exit
  then
;
 
: DoShowViewList  ( strrng --  )                (* show +view results *)
  
  dup if
    ourObj @ loc @ dbcmp if
      ">>  Viewable details for this location:" 
    else
      ">>  Viewable details for $name:"
      ourObj @ if
        ourObj @ name
      else
        "this location"
      then
      "$name" subst
    then
    Tell
    me @ " " notify
    begin
      dup while
      swap Tell
      1 -
    repeat
    pop
  else
    ourObj @ if
      ">>  There are no obvious details on $name."
      ourObj @ name "$name" subst Tell
    else
      ">>  There are no obvious details here." Tell
    then
  then
;
  
: DoGetViewLines  ( d -- [s1 s2 ... sx )
             (* put a view entry string on stack for each detail on d *)
  
  dup "_details/" nextprop
  begin
    dup while
    over over "_masked/" "_details/" subst getpropstr not if
      dup "" "_details/" subst DoRemoveControls DoMainName
      " :: " swap strcat
      3 pick dup loc @ dbcmp if
        pop "    Here"
      else
        name DoMainName "    " swap strcat
      then
      swap strcat
      rot rot
    then
    over swap nextprop
  repeat
  pop pop
;
  
: DoView  (  --  )        (* view or get list of details, MUSH syntax *)
  
  DoClearStack
  1 ourBool !
  ourArg @ not if 
    loc @ contents ourObj !
    begin
      ourObj @ while
      ourObj @ DoGetViewLines
      ourObj @ next ourObj !
    repeat
    depth DoSortStrings-d
    loc @ DoGetViewLines
    depth DoShowViewList
  else
    ourArg @ "/" instr if
      0 ourBool !
      ourArg @ dup "/" instr strcut strip DoInsertControls ourArg !
      strip dup strlen 1 - strcut pop strip 
      DoOurMatch ourObj ! 
      ourObj @ "_details/" nextprop
      begin                             (* begin detail-checking loop *)
        dup while
        dup "" "_details/" subst
        ";" explode
        begin                     (* begin detail-alias-checking loop *)
          swap ourArg @ stringpfx if
            begin                   (* begin extra-alias-popping loop *)
              dup 1 = if 
                break
              else
                swap pop
              then
              1 -
            repeat                    (* end extra-alias-popping loop *)
            pop
            1 break
          then
          1 -
          dup while
        repeat                      (* end detail-alias-checking loop *)
        if break then
        ourObj @ swap nextprop
      repeat                              (* end detail-checking loop *)
      
      ourObj @ swap DoShowDetailDesc
    else
      ourArg @ strip
      DoOurMatch ourObj !
      ourObj @ DoGetViewLines
      depth DoShowViewList
    then
  then
;
 
: DoShowFullDesc  (  --  )             (* show ourObj's complete desc *)
       
  ourObj @ "_/de" getpropstr if
    ourObj @ "_/de" DoParseThis 
    " " "%b" subst
    "%" "%%" subst
    "     " "%t" subst
    "%r" explode
    begin
      dup while
      me @ rot pronoun_sub Tell
      1 -
    repeat
    pop
  else
    ourObj @ room? not if
      "You see nothing special." Tell
    then
  then
;
 
: DoLook  (  --  )                                       (* do a look *)
  
  ourArg @ match ourObj !               (* find obj/detail to look at *)
   
  ourObj @ #-1 dbcmp if    (* if we can't find as object, try details *)
    DoDetailObj exit
  then
  ourObj @ #-2 dbcmp if
    DoDetailObj exit
  then
  
  ourObj @ room? if                      (* for rooms, show room name *)
    me @ ourObj @ controls if
      me @ ourObj @ unparseobj Tell
    else
      me @ ourObj @ name Tell
    then
  then
                                               (* show desc if needed *)
  ourObj @ room? if
    me @ "_prefs/look/flags" getpropstr "Q" instr not 
    ourBool @ or if           (* ourBool is true if user supplied arg *)
      "autolook_cmd" sysparm if
        "autolook_cmd" sysparm command @ smatch not
      else
        command @ "look" smatch not
      then
      me @ "_prefs/look/fulllook" getpropstr or
      me @ "_prefs/look/flags" getpropstr "S" instr or 
      me @ location "_full_look" getpropstr or and if
        DoShowFullDesc
      else
        me @ "_prefs/look/roomscount/" ourObj @ intostr strcat 
        getprop dup if
          dup 5 <= if
            pop DoShowFullDesc
          else
            10 <= if
              ourObj @ "_/bde" getpropstr if
                DoShowBriefDesc
              else
                DoShowFullDesc
              then
            then
          then
        else
          pop DoShowFullDesc
        then
      then
    then
  else
    DoShowFullDesc
  then
  
  me @ "_prefs/look/roomstimes/" nextprop
  begin
    dup while
    me @ over getprop systime 604800 - < if
      me @ over "roomscount" "roomstimes" subst remove_prop
      me @ over nextprop
      me @ rot remove_prop
    else
      me @ swap nextprop
    then
  repeat
  pop
  
  me @ "_prefs/look/roomscount/" nextprop
  begin
    dup while
    dup "" "_prefs/look/roomscount/" subst atoi dbref ok? not if
      me @ over "roomstimes" "roomscount" subst remove_prop
      me @ over nextprop
      me @ rot remove_prop
      continue
    then
    dup "" "_prefs/look/roomscount/" subst atoi dbref room? not if
      me @ over "roomstimes" "roomscount" subst remove_prop
      me @ over nextprop
      me @ rot remove_prop
      continue
    then
    me @ swap nextprop
  repeat
  pop
  
  ourObj @ room? if
    me @ "_prefs/look/roomstimes/"
    ourObj @ intostr strcat systime setprop
    me @ "_prefs/look/roomscount/"
    ourObj @ intostr strcat over over
    getprop 1 + setprop
  then
                                          (* show exit list if needed *)
  ourObj @ room? if
    DoExitList
    DoCommandList
  then
                                        (* show detail list if needed *)
  me @ "_prefs/look/flags" getpropstr "D" instr 
  ourObj @ program? not ourObj @ exit? not and and if
    DoDetailList
  then
  
  ourObj @ room?                                     (* show contents *)
  ourObj @ "D" flag?
  me @ ourObj @ controls not and and not if
    DoGetContents
    dup if
      DoContents
    else
      pop
    then
  then
  me @ "_prefs/look/fulllook" remove_prop
;
  
: DoFullLook  (  --  )                           (* force a full look *)
 
  ourArg @ not if "here" ourArg ! then
  me @ "_prefs/look/fulllook" "yes" setprop
  DoLook
;
 
: main
  
  "me" match me !
  prog "_version" getprop not if
    DoInitProgram
  then
  me @ "_prefs/look/version" getprop not if
    DoInitPlayer
  then
  
  command @ "{@briefdesc|@bdesc|@brief}" smatch if
    DoSetBriefDesc exit
  then
  
  dup if
    dup "#*" smatch if
      dup " " instr if
        dup " " instr strcut
        strip ourArg !
        strip ourOpt !
      else
        strip ourOpt !
      then
      "#help"        ourOpt @ stringpfx if DoHelp            else
      "#prefs"       ourOpt @ stringpfx if DoSetPrefs        else
      "#full"        ourOpt @ stringpfx if DoFullLook        else
      "#brief"       ourOpt @ stringpfx if DoShowBriefDesc   else
      "#preferences" ourOpt @ stringpfx if DoSetPrefs        else
      "#details"     ourOpt @ stringpfx if DoSetDetail       else
      "#!details"    ourOpt @ stringpfx if DoDelDetail       else
      "#items"       ourOpt @ stringpfx if DoSetItem         else
      "#!items"      ourOpt @ stringpfx if DoDelItem         else
      "#mask"        ourOpt @ stringpfx if DoSetMasked       else
      "#unmask"      ourOpt @ stringpfx if DoSetUnMasked     else
      "#!mask"       ourOpt @ stringpfx if DoSetUnMasked     else
                     ourOpt @ ourArg !     DoLook
  
      then then then then then then then then then then then then
    else
      ourArg ! 
      command @ "lookat" smatch if
        DoLookat exit 
      then
      command @ "+view" smatch if
        DoView
      else
        command @ "lookat" smatch if
          DoDetailObj
        else
          1 ourBool !
          DoLook
        then
      then
    then
  else
    command @ "+view" smatch if
      DoView
    else
      pop "here" ourArg ! 
      command @ "lookat" smatch if
        DoDetailList
      else
        DoLook
      then
    then
  then
;
.
c
q