generic lockable doored exit, $door
- $door
- $detailed_room:here_huh
- so the player can invoke open, close, lock, and unlock (but there's hopefully a way to directly invoke those verbs, so they don't have to be set +x)
- $xplayer:last_huh
- general, to handle open, close, lock, and unlock verbs with no arguments.
@create $exit called "generic lockable doored exit",door
@prop door.open_succeeded_msg ""
@prop door.open_failed_msg ""
@prop door.close_succeeded_msg ""
@prop door.close_failed_msg ""
@prop door.seal_succeeded_msg ""
@prop door.seal_failed_msg ""
@prop door.unseal_succeeded_msg ""
@prop door.unseal_failed_msg ""
@prop $door.autoclose_msg ""
@prop door.is_door 1
@prop door.is_closed 0
@prop door.is_sealed 0
@prop door.seal_key #-1 rc
@prop door.automatic 0 rc
@prop door.autoclose_id 0 r
@prop door.close_time -1 rc
@prop door.other_side #-1 r
@prop door.hidden 0 rc
@prop door.door_name "the door" rc
@verb door:invoke tnt rxd
@verb door:move tnt rxd
@verb door:title tnt rxd
@verb door:open this none none
@verb door:close this none none
@verb door:lock this none none
@verb door:lock this with any
@verb door:unlock this none none
@verb door:unlock this with any
@verb door:_open tnt rxd
@verb door:_close tnt rxd
@verb $door:_autoclose tnt rxd
@verb door:_seal tnt rxd
@verb door:_unseal tnt rxd
@verb door:pair_set tnt rxd
@verb door:"open_succeeded_msg open_failed_msg close_succeeded_msg close_failed_msg seal_succeeded_msg seal_failed_msg unseal_succeeded_msg unseal_failed_msg autoclose_msg" tnt rxd
@program $door:invoke
if (this.is_door && this.is_closed)
if (this.automatic && !this.is_sealed)
this:_open();
pass(@args);
elseif (this.hidden > 1)
player:tell("You can't go that way.");
else
player:tell(this:nogo_msg() || tostr("You can't go that way; ", this.door_name, " is closed."));
if (msg = this:onogo_msg())
this:announce_msg(player.location, player, msg);
endif
endif
else
pass(@args);
endif
.
@program $door:move
what = args[1];
if (this.is_closed)
what:tell_lines(this:nogo_msg() || "You can't go that way.");
if (msg = this:onogo_msg())
this:announce_msg(what.location, what, msg);
endif
else
pass(@args);
endif
.
@program $door:title
if (this.is_door)
return $ansi_utils:make_clean(this.door_name);
else
return pass(@args);
endif
.
@program $door:open
this:_open();
.
@program $door:close
this:_close();
.
@program# $door:6
this:_seal(player);
.
@program# $door:7
if (valid(iobj) && iobj.location == player)
this:_seal(iobj);
endif
.
@program# $door:8
this:_unseal(player);
.
@program# $door:9
if (valid(iobj) && iobj.location == player)
this:_unseal(iobj);
endif
.
@program $door:pair_set
{pair} = args;
if (this.other_side == #-1)
this.other_side = pair;
else
return E_PERM;
endif
.
@program $door:_open
{?repeat = 1} = args;
if (!(player.location in {this.source, this.dest}))
"...lose...";
return;
endif
if (!this.is_door)
player:tell ("You can't open that!");
return;
endif
if (this.is_closed)
if (this.is_sealed || !this:is_unlocked_for(player))
$you:say_action(this.open_failed_msg ? this.open_failed_msg | "%N %<tries> to open %t, but %<fails>!", player, this, player.location);
return;
endif
if (this.close_time >= 0)
fork autoclose (this.close_time)
this:_autoclose();
endfork
this.autoclose_id = autoclose;
endif
this.is_closed = 0;
if (repeat)
$you:say_action(this.open_succeeded_msg ? this.open_succeeded_msg | "%N %<opens> %t.", player, this, player.location);
if (!valid(this.other_side))
for e in (`this.dest.exits ! E_INVIND => {}')
if (`e.dest == this.source ! ANY => 0' && `e.other_side == #-1 ! E_PROPNF => 0')
e:pair_set(this);
this.other_side = e;
endif
endfor
endif
try
this.other_side:_open(0);
except (ANY)
endtry
else
"door closed from other side. maybe say something?";
endif
if (this.hidden >= 1)
this.obvious = 1;
endif
else
player:tell("That's already open.");
endif
.
@program $door:_close
if (!(player.location in {this.source, this.dest}))
"...lose...";
return;
endif
{?repeat = 1} = args;
if (!this.is_door)
player:tell ("You can't close that!");
return;
endif
if (this.is_closed == 0)
if (!this:is_unlocked_for(player))
$you:say_action(this.close_failed_msg ? this.close_failed_msg | "%N %<tries> to close %t, but %<fails>!", player, this, player.location);
return;
endif
this.is_closed = 1;
if (repeat)
$you:say_action(this.close_succeeded_msg ? this.close_succeeded_msg | "%N %<closes> %t.", player, this, player.location);
if (!valid(this.other_side))
for e in (`this.dest.exits ! E_INVIND => {}')
"the ANY catches the regrettible $two_way, which is an exit without a dest/source";
if (`e.dest == this.source ! ANY => 0' && `e.other_side == #-1 ! E_PROPNF => 0')
e:pair_set(this);
this.other_side = e;
endif
endfor
endif
try
this.other_side:_close(0);
except (ANY)
endtry
else
"door closed from other side. maybe say something?";
endif
if (this.hidden >= 1)
this.obvious = 0;
endif
if (this.autoclose_id != 0)
kill_task(this.autoclose_id);
this.autoclose_id = 0;
endif
else
player:tell("That's already closed.");
endif
.
@program $door:_autoclose
{?repeat = 1} = args;
if (this.autoclose_id == task_id())
this.autoclose_id = 0;
endif
if (this.is_closed == 0)
this.is_closed = 1;
this.source:announce_all(this:autoclose_msg() || tostr($string_utils:capitalize(this.door_name), " closes."));
if (repeat)
if (!valid(this.other_side))
for e in (`this.dest.exits ! E_INVIND => {}')
"the ANY catches the regrettible $two_way, which is an exit without a dest/source";
if (`e.dest == this.source ! ANY => 0' && `e.other_side == #-1 ! E_PROPNF => 0')
e:pair_set(this);
this.other_side = e;
endif
endfor
endif
try
this.other_side:_autoclose(0);
except (ANY)
endtry
endif
if (this.hidden >= 1)
this.obvious = 0;
endif
endif
.
@program $door:_seal
if (!(player.location in {this.source, this.dest}))
"...lose...";
return;
endif
{what, ?repeat = 1} = args;
if (this.is_closed == 0)
player:tell("You can't lock that; you'd have to close it first.");
elseif (this.is_sealed == 0)
if (this:is_unlocked_for(what) && $lock_utils:eval_key(this.seal_key, what))
this.is_sealed = 1;
if (repeat)
$you:say_action(this.seal_succeeded_msg ? this.seal_succeeded_msg | "%N %<locks> %t.", player, this, player.location);
if (!valid(this.other_side))
for e in (`this.dest.exits ! E_INVIND => {}')
if (`e.dest == this.source ! ANY => 0' && `e.other_side == #-1 ! E_PROPNF => 0')
e:pair_set(this);
this.other_side = e;
endif
endfor
endif
try
this.other_side:_seal(what, 0);
except (ANY)
endtry
else
"door locked from other side. maybe say something?";
endif
else
player:tell(this:seal_failed_msg() || "You don't have the key.");
endif
else
player:tell("That's already locked.");
endif
.
@program $door:_unseal
if (!(player.location in {this.source, this.dest}))
"...lose...";
return;
endif
{what, ?repeat = 1} = args;
if (this.is_sealed == 1)
if (this:is_unlocked_for(what) && $lock_utils:eval_key(this.seal_key, what))
this.is_sealed = 0;
if (repeat)
$you:say_action(this.unseal_succeeded_msg ? this.unseal_succeeded_msg | "%N %<unlocks> %t.", player, this, player.location);
if (!valid(this.other_side))
for e in (`this.dest.exits ! E_INVIND => {}')
if (`e.dest == this.source ! ANY => 0' && `e.other_side == #-1 ! E_PROPNF => 0')
e:pair_set(this);
this.other_side = e;
endif
endfor
endif
try
this.other_side:_unseal(what, 0);
except (ANY)
endtry
else
"door unlocked from other side. maybe say something?";
endif
else
player:tell(this:unseal_failed_msg() || "You don't have the key.");
endif
else
player:tell("That's not locked.");
endif
.
@program $door:open_succeeded_msg
return $string_utils:pronoun_sub(this.(verb));
.
@verb $detailed_room:here_huh tnt rxd
@program $detailed_room:here_huh
if ((verb = args[1]) in {"open", "close", "lock", "unlock"} && length(args[2]) >= 1)
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 $xplayer:last_huh tnt rxd
@program $xplayer:last_huh
{verb, vargs} = args;
if (verb in {"open", "close", "lock", "unlock"} && length(vargs) == 0)
player:tell(tostr($string_utils:capitalize(verb), " what?"));
return 1;
endif
return pass(@args);
.