generic detailed room, $detailed_room
- $detailed_room.autoexit
- $detailed_room.listen_description
- $detailed_room.smell_description
- $detailed_room.feel_description
- $detailed_room.taste_description
- $detailed_room:"listen_self smell_self feel_self taste_self"
- $detailed_room:look_self
- $detailed_room:autoexits
- $detailed_room:tell_contents
- $detailed_room:here_huh
@create $room called "generic detailed room",detailed_room
@chmod $detailed_room +rf
@prop $detailed_room.autoexit 1
@prop $detailed_room.listen_description
@prop $detailed_room.smell_description
@prop $detailed_room.feel_description
@prop $detailed_room.taste_description
@verb $detailed_room:"listen_self smell_self feel_self taste_self" tnt
@program $detailed_room:listen_self
desc = this.(verb[1..$-5] + "_description");
if (verb == "listen_self")
report = "hear";
elseif (verb == "smell_self")
report = "smell";
elseif (verb == "feel_self")
report = "feel";
else
report = "taste";
endif
if (desc)
player:tell(desc);
else
player:tell("You ", report, " nothing special.");
endif
.
@verb $detailed_room:look_self tnt
@program $detailed_room:look_self
{?brief = 0} = args;
player:tell();
player:tell(this:title());
if (!brief)
desc = this:description();
if (desc)
player:tell_lines(desc);
else
player:tell("You see nothing special.");
endif
endif
if(this.autoexit && player.autoexit)
player:tell(this:autoexits());
endif
this:tell_contents(setremove(this:contents(), player), this.ctype);
.
@verb $detailed_room:autoexits tnt
@program $detailed_room:autoexits
exits = this:obvious_exits();
elist = " Exits: ";
if (exits)
for n in (exits)
if ($object_utils:isa(n, $exit))
exname = "`2y" + n.name + "`00";
elseif ($object_utils:isa(n, $two_way))
index = this in n.exits == 1 ? 1 | 2;
exname = "`2y" + n._aliases[index][1] + "`00";
else
exname = "`1rbad exit type (" + n + ")`00";
endif
if ($object_utils:has_property(n, "is_door") && n.is_door && n.is_closed)
exname = "`1x[`2y" + exname + "`1x]`00";
endif
if (n == exits[$])
elist = elist + exname + ".";
else
elist = elist + exname + ", ";
endif
endfor
else
elist = elist + "`2wnone`00.";
endif
return elist;
.
@verb $detailed_room:here_huh tnt rxd
@program $detailed_room:here_huh
if ((verb = args[1]) in {"open", "close", "lock", "unlock"})
exit = this:match_exit((target = args[2][1]));
if ($recycler:valid(exit) && ($object_utils:has_callable_verb(exit, verb)))
exit:(verb)();
return 1;
endif
return 0;
endif
return pass(@args);
.
@verb $detailed_room:@exits none none none rd
@program $detailed_room:@exits
if (!$perm_utils:controls(valid(caller_perms()) ? caller_perms() | player, this))
player:tell("Sorry, only the owner of a room may list its exits.");
elseif (this.exits == {})
player:tell("This room has no conventional exits.");
else
try
for exit in (this.exits)
try
player:tell(exit:title(), " (", exit, ") leads to ", valid(exit.dest) ? exit.dest:title() | "???", " (", exit.dest, ") via {", $string_utils:from_list(exit.aliases, ", "), "}.");
except (ANY)
player:tell("Bad exit or missing .dest property: ", $string_utils:nn(exit));
continue exit;
endtry
endfor
except (E_TYPE)
player:tell("Bad .exits property. This should be a list of exit objects. Please fix this.");
endtry
endif
.
@verb detailed_room:tell_contents tnt
@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
endfor
endif
for p in (players)
player:tell($string_utils:pronoun_sub(tostr("%N ", $gender_utils:get_conj("is", p), " here."), p));
endfor
else
pass(@args);
endif
.
@verb detailed_room:match_detail tnt
@program $detailed_room:match_detail
{alias, ?senses = {"look", "listen", "smell", "touch", "taste"}} = args;
senses = typeof(senses) == LIST ? senses | {senses};
match = $failed_match;
r = {};
for sense in (senses)
senseprop = sense + "_details";
for x in (`this.(senseprop) ! E_PROPNF => {}')
if (alias in x[1])
r = {@r, {sense, x in this.(senseprop)}};
if (match == $failed_match)
match = x in this.(senseprop);
else
match = $ambiguous_match;
endif
endif
endfor
endfor
if (match != $failed_match)
return {match, r};
endif
"checking for partial matches";
for sense in (senses)
senseprop = sense + "_details";
for x in (`this.(senseprop) ! E_PROPNF => {}')
for y in (x[1])
if (index(y, alias) != 1)
elseif (match == $failed_match)
r = {@r, {sense, x in this.(senseprop)}};
match = x in this.(senseprop);
else
r = {@r, {sense, x in this.(senseprop)}};
match = $ambiguous_match;
endif
endfor
endfor
endfor
return {match, r};
.
@verb $detailed_room:display_detail tnt
@program $detailed_room:display_detail
{alias, sense} = args;
senseprop = sense + "_details";
{match, r} = this:match_detail(alias, sense);
if (match == $failed_match || match == $ambiguous_match)
return match;
endif
player:tell_lines(this.(senseprop)[r[1][2]][2]);
return 1;
.
@prop $detailed_room.look_details {}
@prop $detailed_room.listen_details {}
@prop $detailed_room.smell_details {}
@prop $detailed_room.touch_details {}
@prop $detailed_room.taste_details {}
@verb $detailed_room:@de*tail any any any
@program $detailed_room:@detail
desc = `args[4..$] ! E_RANGE => iobjstr';
if (!$perm_utils:controls(player, this))
player:tell("You don't have the permissions for that.");
return E_PERM;
endif
"this manual unfolding is so we can properly handle the cases where 1) the alias has quoted spaces and 2) the alias is a preposition. args knows what's up, but :explode/:words fails in the first case and dobjstr fails in the second.";
sense = args[1];
if (args[2] != "as" || `args[3] == "as" ! E_RANGE => 0')
aliaslist = args[2];
else
aliaslist = "";
endif
if (!sense || (j = !(sense in {"look", "listen", "touch", "taste", "smell"})) || !aliaslist)
if(!aliaslist && !j)
msg = "If you want to set the room description, use @describe or @edit.";
else
msg = "";
endif
this:here_explain_syntax(caller, verb, args, msg);
return;
endif
aliaslist = $string_utils:explode(aliaslist, ",");
dups = {};
for a in (aliaslist)
{m, r} = this:match_detail(a, sense);
if (m != $failed_match)
dups = {@dups, a};
endif
endfor
if (length(dups))
player:tell("The keyword", length(dups) == 1 ? " " | "s ", $string_utils:english_list(dups), length(dups) == 1 ? " is" | " are", " already in use with that sense.");
return E_PERM;
endif
this.(sense+"_details") = {@this.(sense+"_details"), {aliaslist, desc}};
player:tell("Detail for ", sense, " with alias", length(aliaslist) == 1 ? " " | "es ", "\"", $string_utils:english_list(aliaslist), "\" created in ", this:title(), " (", this, ")." );
.
@verb $detailed_room:@rmde*tail any any any
@program $detailed_room:@rmdetail
if (prepstr && !(prepstr in {"for", "from"}))
"ack, detail w/ the name of a preposition";
match = prepstr == "for" ? "for" | "from";
if (i = match in args)
alias = `$string_utils:from_list(args[1..i-1], " ") ! E_RANGE => ""';
sense = `$string_utils:from_list(args[i+1..$], " ") ! E_RANGE => ""';
else
alias = argstr;
sense = "";
endif
elseif (prepstr == "for" || prepstr == "from")
alias = dobjstr;
sense = iobjstr;
else
alias = dobjstr;
sense = "";
endif
player:tell_lines({toliteral(args), alias, sense});
if (!$perm_utils:controls(player, this))
player:tell("You don't have the permissions for that.");
return E_PERM;
elseif (!alias)
player:tell("Remove which detail?");
return;
elseif (!sense)
player:tell("Since you didn't specify, I'm assuming you mean all details called \"", alias, "\", no matter the sense.");
sense = {"look", "listen", "smell", "touch", "taste"};
else
if (!(sense in {"sight", "sound", "touch", "taste", "smell"}))
this:here_explain_syntax(caller, verb, args);
return;
endif
if (sense == "sight")
sense = "look";
elseif (sense == "sound")
sense = "listen";
endif
endif
{match, r} = this:match_detail(alias, sense);
if (match == $failed_match)
player:tell("There's no detail called \"", alias, "\" to remove.");
return;
endif
for i in (r)
senseprop = i[1] + "_details";
aliaslist = this.(senseprop)[i[2]][1];
this.(senseprop) = setremove(this.(senseprop), this.(senseprop)[i[2]]);
player:tell("Detail for ", i[1], " with alias", length(aliaslist) == 1 ? " " | "es ", "\"", $string_utils:english_list(aliaslist), "\" has been removed from ", this:title(), " (", this, ").");
endfor
.
@verb $detailed_room:here_explain_syntax tnt
@program $detailed_room:here_explain_syntax
{caller, verb, vargs, ?msg="", @args} = args;
r = 0;
if ($code_utils:verbname_match("@rmde*tail", verb))
player:tell_lines({
"Syntax: @rmdetail [from/for ].",
" Where is one of: sight sound touch taste smell."});
r = 1;
elseif ($code_utils:verbname_match("@details", verb))
elseif ($code_utils:verbname_match("@de*tail", verb))
player:tell_lines({
"Syntax: @detail as \"\".",
" Where is one of: look listen touch taste smell."});
r = 1;
endif
if(msg)
if(r == 1)
msg = $string_utils:space(9, " ") + msg;
endif
player:tell(msg);
r = 1;
endif
return r;
.
@verb $detailed_room:@details none none none
@program $detailed_room:@details
if (!$perm_utils:controls(valid(caller_perms()) ? caller_perms() | player, this))
player:tell("Sorry, only the owner of a room may list its details.");
return E_PERM;
endif
output = 0;
limit = `player:linelen() ! ANY => 79';
for sense in ({"look", "listen", "taste", "smell", "touch"})
for detail in (this.(sense+"_details"))
start = $ansi_utils:slice(tostr(" ", sense, ": \"", typeof(detail[2]) == LIST ? detail[2][1] | detail[2], "\""), limit);
if($ansi_utils:length(start) == limit)
start = start[1..$-4] + "...`00\"";
endif
player:tell_lines({tostr($string_utils:english_list(detail[1]), ": "), start});
output = output + 1;
endfor
endfor
if (output == 0)
player:tell("This room has no details.");
endif
.
@prop $detailed_room.echo_to {}
@prop $detailed_room.estart_msg "Elsewhere, "
@prop $detailed_room.eend_msg ""
@verb $detailed_room:"announce announce_all announce_all_but" tnt
@program $detailed_room:announce
pass(@args);
if(verb == "announce_all_but")
{ignore, @text} = args;
else
ignore = {};
{@text} = args;
endif
try
for target in (this.echo_to)
if (valid(target) && target:is_unlocked_for(this))
try
if ($object_utils:isa(target, $detailed_room) || $object_utils:isa(target, $echo_room))
target:announce_noecho(ignore, this:estart(), @text, this:eend());
elseif ($object_utils:isa(target, #155))
target:announce_all_e(this:estart(), @text, this:eend());
else
target:announce(this:estart(), @text, this:eend());
endif
except (ANY)
continue target;
endtry
endif
endfor
except (E_TYPE)
this.owner:tell(this.name, " `00has a bad .echo_to property. It should be a list of rooms. Please fix this.");
endtry
.
@verb $detailed_room:announce_noecho tnt
@program $detailed_room:announce_noecho
":announce_noecho(LIST of targets to ignore, @text)";
"";
"This is $room:announce_all_but, but called to replace all :announce* verbs when dealing with an echo from another room, so we don't get infinitely bouncing echos.";
{ignore, @text} = args;
contents = this:contents();
for l in (ignore)
contents = setremove(contents, l);
endfor
for listener in (contents)
try
listener:tell(@text);
except (ANY)
"Ignore listener with bad :tell";
continue listener;
endtry
endfor
.
@verb $detailed_room:"estart eend" tnt rxd
@program $detailed_room:estart
return this.(verb+"_msg");
.
"@prop detail.help_msg ""
"@edit detail.help_msg
"A detailed room is like a room, only better!
"
"It's got capacities for the following alternative behaviours:
" - automatic listing of exits, if .autoexits is on
" - unique descriptions of objects in room, if applicable (and .ctype = 4) <-- but it is very bad
" - details. use @detail or @rmdetail to add/remove details to rooms you own. The details will be visible on a "look ", and are a way to create extra depth in a room without having everything you can look at be a seperate object. Use @details to see all the details on a room (but only if you're the owner)
" - echoes. set .echo_to to a list of rooms that will hear what happens in the room. set .estart_msg and .end_msg to alter how the message is displayed.
"
" (also, the l*ook code catches stuff like "look at foo on bar", which it doesn't normally)
"save
"done
"ideally will handle integration, later on.