@create $thing named Generic Combination Lock:Generic Combination Lock,GCL @prop GCL."copyright" "Generic Combination Lock written by yduJ@LambdaMOO Spring 91" @prop GCL."locked" 0 r @prop GCL."so_far" 0 r @prop GCL."combination" {} @prop GCL."position" 12 r @prop GCL."top" 20 rc ;GCL.("key") = 0 ;GCL.("aliases") = {"Generic Combination Lock"} ;GCL.("description") = "A combination lock that you can to manipulate by 'turn lock to '." @verb GCL:"description" this none this @program GCL:description return ((((pass() + " It sports a dial ranging from 1 to ") + tostr(this.top)) + ". The number under the hashmark at the top is ") + tostr(this.position)) + "."; . @verb GCL:"turn" this at any @program GCL:turn iobjlist = $string_utils:explode(iobjstr); if (length(iobjlist) == 2) number = tonum(iobjlist[1]); direction = iobjlist[2]; dirOK = 0; for x in (this.combination) if (direction == x[2]) dirOK = 1; endif endfor if ((dirOK && number) && (number < (this.top + 1))) player:tell("You set the lock to ", number, " turning ", direction, "."); player.location:announce(player.name, " turns the dial on ", this.name, " to the ", direction, "."); this:tumbler(number, direction); this.position = number; else if (dirOK) player:tell("The dial goes from 1 to ", this.top, "."); else player:tell(direction, " is not an allowable direction for this lock."); endif endif else player:tell("You must turn the lock a position and a direction, e.g. '5 right'."); endif . @verb GCL:"change" this at any @program GCL:change "Must be alternating numbers and directions."; if (this.owner != player) player:tell("You can't change the combination if you don't own the lock!"); return 0; endif combo = $string_utils:explode(iobjstr); if ((length(combo) / 2) != ((length(combo) + 1) / 2)) player:tell("Odd length list: must be alternating numbers and directions"); return 0; endif newcombo = {}; for x in [1..length(combo) / 2] newcombo = {@newcombo, {tonum(combo[(x * 2) - 1]), combo[x * 2]}}; endfor for x in (newcombo) if ((x[1] > this.top) || (x[1] == 0)) player:tell("Valid numbers range from 1 to ", this.top, "."); return 0; endif endfor text = ""; for x in (newcombo) text = (text + tostr(" '", x[1], " ", x[2], "'")); endfor player:tell("New combination:", text, "."); this.combination = newcombo; . @verb GCL:"tumbler" this none this @program GCL:tumbler this.so_far = (this.so_far + 1); if ((args[1] == this.combination[this.so_far][1]) && (args[2] == this.combination[this.so_far][2])) this:success_msg(@args); else this.so_far = 0; endif if (this.so_far == length(this.combination)) this:unlock_msg(); this.locked = 0; this.so_far = 0; endif . @verb GCL:"unlock_msg" this none this @program GCL:unlock_msg player.location:announce_all("The lock slips open."); . @verb GCL:"success_msg" this none this @program GCL:success_msg player.location:announce_all("You hear an audible click as a tumbler falls home."); . @verb GCL:"spin" this none none @program GCL:spin player:tell("You spin the dial around several times, causing it to forget any state."); player.location:announce(player.name, " spins the dial madly around on ", this.name, "."); this.so_far = 0; . @verb GCL:"show" this none none @program GCL:show if (this.owner != player) player:tell("You are not allowed to peek at the combination."); else player:tell("Current combination: "); for x in (this.combination) player:tell(" ", x[1], " ", x[2]); endfor endif . @create $note named Instructions on the Generic Combination Lock (GCL) ;Instructions.("text") = {"The Generic Combination Lock is object number #4019. You may @create a lock for yourself. Combinations are specified as 'number direction' pairs. Verbs on the GCL are, for the owner of the lock, 'change lock to ', and for all, 'turn lock to ' and 'spin lock' (which forgets any state the lock might have had). An example of use would be 'change lock to 5 right 15 left 3 right', and 'turn lock to 8 left'.", "", "To increase or decrease the range of the dial, set the property lock.top to any number you choose. The default is 20. (Sorry, you have to use ; programming to set it...)", "", "Implementation details: ", " Properties: lock.combination contains the current combination. Only the owner of the lock may look at this. Lock.so_far contains an integer defining how far through the combination the player has gotten. Lock.position defines the current position of the dial. Lock.locked specifies whether the player has unlocked the lock.", " Verbs: lock:tumbler(number,direction) is called by lock:turn just before changing the current position. The default sets lock.so_far if appropriate and calls lock:success_msg(number,direction) and lock:unlock_msg() if the combination was advanced or completed. The default success message prints a message in the room that a tumbler clicked home. If you specialize :tumbler, you should call pass(@args) to ensure that the lock.so_far processing gets done. Your specialization of lock:unlock_msg may wish to inform another object (whatever was being locked...) of the success."}