[...]

 

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); .