;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Global Player Commands ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Reminder: a command has three parts: ;;; - a specification list that holds Scheme values or predicates, ;;; or a predicate that will be called on the whole input string, ;;; or a list that starts with :or and then specs lists; ;;; - a help string; ;;; - a function that will be applied on the player and the input ;;; list, and returns: ;;; - #f means that there shouldn't be another input event ;;; - a string will be printed and a new input will be read ;;; immediately (usually used to indicate input errors). ;;; - a number is the delay until the next input event. ;;; - any other result means use the default delay until the next ;;; input, should be #t (other values might be used differently). ;;; Show help on all commands. (add-player-command 'commands (list :or '(help) (list 'help symbol?) (list 'h symbol?)) "help get general instructions" (lambda (plyr inp) (let ((commands (and (= (length inp) 2) (filter (lambda (x) (eq? (cmd-namespace x) (second inp))) (commands plyr plyr))))) (cond ((not commands) (tell plyr "") (tell plyr (echos "Welcome to CLUE! The object of the game is to" "figure out who killed Bill. You must explore," "find objects, talk to people, look for clues. " "If you talk to someone who is not the" "murderer, you can be assured they will always" "speak the truth. The murderer, however, may" "lie or tell the truth. You must determine:" :n " (i) who the murderer is," :n " (ii) what the murder weapon was, and" :n " (iii) where the murder took place." :n "When you have determined these three things," "you must find the murder weapon, go to the" "place of the murder, and use the 'accuse'" "command to declare who you think the culprit" "is." :n "At any time you may type:" :n " 'help commands' for a list of commands" :n " 'help emotions' for a list of emotions" :n " 'help items' for commands for items" :n " 'help context' for contextual commands")) "Good luck!") ((or (empty? commands) (eq? (second inp) 'hidden)) (echos "There are no commands for" (second inp))) (else (tell plyr "") (tell plyr (echos "Available" (second inp) "( are arguments):")) (for-each (lambda (command) (tell plyr (echos-ns " | " (cmd-desc command)))) commands) "So, what will it be?"))))) ;;; Wait and do nothing. (add-player-command 'commands '(:or '(wait) '(w) '(nop)) "wait do nothing" (lambda (plyr inp) (let ((strs (random-elt '(("You wait... Time passes..." "More time passes...") ("You spend some time trying to catch flies." "Hey, just caught a fly!") ("You kill time thinking about the meaning of life." "You found the meaning of life too complicated.") ("You take some time to admire the view." "What a lovely view...."))))) (insert-immediate-event (lambda () (tell plyr (first strs)))) (insert-event 1.5 (lambda () (tell plyr (second strs))))) ;; wait 2 seconds until next input 2)) ;;; See what time is it in the game: seconds since startup. (add-player-command 'commands (list :or '(t) '(time)) "time see what is the server time (secs since started)" (lambda (plyr inp) ;; this is a little long, but it just shows the time (let* ((add0 (lambda (n) (if (< n 10) (string-append "0" (number->string n)) (number->string n)))) (curt (as (current-time))) (secs (modulo curt 60)) (mins (modulo (quotient curt 60) 60)) (hours (quotient curt 3600))) (string-append "The time is: " (if (zero? hours) "" (echos-ns hours ":")) (add0 mins) ":" (add0 secs))))) ;;; Look around. (add-player-command 'commands (list :or '(l) '(ls) '(look) (list 'l symbol?) (list 'look symbol?)) "look [] look around or at something" (lambda (plyr inp) (let* ((what (and (= 2 (length inp)) (second inp))) (place (nick-find what (exits (location plyr)))) (thing (nick-find what (contents (location plyr)))) (held (nick-find what (contents plyr)))) (cond ((or (= 1 (length inp)) (eq? (second inp) 'around) (memq (second inp) (nick (location plyr)))) ;; temporarily delete the visited places for a full description (let ((tmp (visited-places plyr))) (set! (visited-places plyr) '()) (describe plyr (location plyr)) (set! (visited-places plyr) tmp))) (place (tell plyr (echos-ns "You look there and see " (name+nick place) ":")) (describe plyr place)) (thing (tell plyr (echos-ns "You see " (name+nick thing) ":")) (describe plyr thing)) (held (tell plyr (echos-ns "You are holding " (name+nick held) ":")) (describe plyr held)) (else (tell plyr (random-elt '("You don't see it." "It is not here.")))))) ;; next input is immediate 0)) ;; See what you have. (add-player-command 'commands (list :or '(i) '(inventory)) "inventory see what you are carrying" (lambda (plyr inp) (let ((stuff (map name+nick (contents plyr)))) (if (null? stuff) (tell plyr "You have nothing!") (begin (tell plyr "Here is what you have:") (for-each (lambda (x) (tell plyr (add " " x))) stuff)))) (tell plyr (echos "Your current carrying capacity is" (maxload plyr))) 0)) ;;; Go somewhere. (add-player-command 'commands (list :or '(g) '(go) (list 'go symbol?) (list 'g symbol?) (list 'cd symbol?) (list 'go 'to symbol?) (list 'go 'to 'the symbol?)) "go go somewhere (`back' goes back if possible)" (lambda (plyr inp) ;; in all input forms, the target is always last (let ((target (nick-find (last inp) (exits (location plyr))))) (cond (target (transfer plyr (location plyr) target)) ((null? (exits (location plyr))) ;; no exits at all - return a message (random-elt '("There is no way to exit this place." "You're stuck here." "Hahahahahaaaaa..."))) ((eq? 'back (last inp)) (if (and (>= (length (visited-places plyr)) 2 ) (get-exit (location plyr) (second (visited-places plyr)))) (transfer plyr (location plyr) (second (visited-places plyr))) (echos "Can't go back."))) ((= (length inp) 1) (echos "Possible exits are:" (map (lambda (x) (first (nick x))) (exits (location plyr))))) (else ;; no such place - return a message (random-elt (let ((exits (map (lambda (x) (first (nick x))) (exits (location plyr))))) (list (echos "You look around, but" (last inp) "is not around, only" exits) (echos "You can only go to one of" exits "from here.") (echos "Try one of" exits "..." "where the hell is" (last inp) "anyway?") (echos "You try to imagine" (last inp) "and go there, but it doesn't work!"))))))))) (add-player-command 'hidden '(cd..) "cd.. Goes back to the last place" (lambda (plyr inp) (if (and (>= (length (visited-places plyr)) 2 ) (get-exit (location plyr) (second (visited-places plyr)))) (transfer plyr (location plyr) (second (visited-places plyr))) (echos "Can't go back.")))) ;;; Take something. (add-player-command 'commands (list :or '(take) '(get) (list 'take symbol?) (list 'get symbol?) (list 't symbol?) (list 'take 'the symbol?) (list 'get 'the symbol?)) "take take some object (can also use get)" (lambda (plyr inp) ;; in all input forms, the object is always last (let* ((objects (filter inanimate? (contents (location plyr)))) (object (nick-find (last inp) objects))) (cond (object (insert-immediate-event (lambda () (take object (location plyr) plyr))) #t) ((null? objects) "There is nothing to take.") ((= (length inp) 1) (echos "Possible objects are:" (map (lambda (x) (first (nick x))) (filter visible? objects)))) (else ;; no such object - return a message (random-elt (let ((objects (map (lambda (x) (first (nick x))) objects))) (list (echos "You look around, but you don't see any" (last inp) "only" objects) (echos "You can only take one of" objects "from here.") (echos "Try one of" objects "...") (echos "You try to imagine" (last inp) "and take it, but it doesn't work!"))))))))) ;;; Drop something. (add-player-command 'commands (list :or (list 'drop symbol?) (list 'put symbol?) (list 'drop 'the symbol?) (list 'put 'the symbol?)) "drop drop some object (can also use put)" (lambda (plyr inp) ;; in all input forms, the object is always last (let ((object (nick-find (last inp) (contents plyr)))) (cond (object (insert-immediate-event (lambda () (drop object plyr (location plyr)))) 0) ((contents plyr) "You have nothing to drop.") (else ;; no such object - return a message (random-elt (let ((objects (map (lambda (x) (first (nick x))) (contents plyr)))) (list (echos "You empty your pockets, but you don't find" (last inp)) (echos "You only have one of" objects) (echos "Try one of" objects "...") (echos "You try to imagine that you have" (last inp) "and drop it, but it doesn't work!"))))))))) ;;; Give something. (add-player-command 'commands (list :or (list 'give symbol? symbol?) (list 'give symbol? 'to symbol?)) "give give an object to someone (also \"give s to p\")" (lambda (plyr inp) (let* ((alt? (= (length inp) 4)) ; check the inp form used (p2nick (if alt? (fourth inp) (second inp))) (objnick (if alt? (second inp) (third inp))) (plyr2 (nick-find p2nick (filter animate? (contents (location plyr))))) (obj (nick-find objnick (contents plyr)))) (cond ((and plyr2 obj (not (eq? plyr plyr2))) (insert-immediate-event (lambda () (give obj plyr plyr2))) #t) ((eq? plyr plyr2) "You give it to yourself and say thanks...") ((not obj) (echos "You don't have" objnick)) ((not (nick-find p2nick *players*)) "There is no such player.") ((not plyr2) (echos "You don't see" p2nick "here")))))) ;;; Add a "who" command - shows the list of currently player. (add-player-command 'commands '(who) "who display the names of all current players." (lambda (plyr inp) (let ((players (remq plyr *players*))) (if (null? players) (tell plyr (random-elt '("There is no one else connected." "You are all alone." "It's only you and the mosquitos."))) (begin (tell plyr "These are the current (other) players:") (for-each (lambda (x) (tell plyr (add " " (name+nick x)))) players))) 0))) ;;; Say something. (add-player-command 'commands (list 'say string?) "say say something to everyone close (use a string)." (lambda (plyr inp) (say plyr (second inp)) #t)) (add-player-command 'hidden (lambda (s) (and (> (string-length s) 1) (or (eq? (string-ref s 0) #\") (eq? (string-ref s 0) #\')))) "" (lambda (plyr inp) (say plyr (truncate-string (substring inp 1 (string-length inp)))) #t)) ;;; Emote somethig. (add-player-command 'commands (list 'emote string?) "emote emote something (try and see what it does)." (lambda (plyr inp) (emote plyr (second inp)) #t)) (add-player-command 'hidden (lambda (s) (and (> (string-length s) 1) (or (eq? (string-ref s 0) #\;) (eq? (string-ref s 0) #\:)))) "" (lambda (plyr inp) (emote plyr (truncate-string (substring inp 1 (string-length inp)))) #t)) ;;; Shout something. (add-player-command 'commands (list 'shout string?) "shout [] shout something to everyone in the game." (lambda (plyr inp) (shout plyr (second inp)) #t)) (add-player-command 'hidden (lambda (s) (and (> (string-length s) 1) (eq? (string-ref s 0) #\!))) "" (lambda (plyr inp) (shout plyr (truncate-string (substring inp 1 (string-length inp)))) #t)) ;;; Tell something to someone specific. (add-player-command 'commands (list 'tell symbol? string?) "tell tell something to any specific player." (lambda (plyr inp) ;; look for any player or any character in the same place (let ((other (or (nick-find (second inp) *players*) (nick-find (second inp) (filter animate? (contents (location plyr))))))) (if other (begin (message other plyr 'tell (third inp)) "Said.") "No such player is logged on.")))) ;;; Quit the game. (add-player-command 'commands (list :or '(quit) '(exit) '(abort)) "quit quit the game immediately." (lambda (plyr inp) (logoff plyr) ;; Make sure there are no more events for the player #f)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Funny stuff (add-player-command 'hidden (list :or '(sta) '(ind)) "sta {or} ind Library catalog commands" (lambda (plyr inp) "You are not in the Cornell University library catalog."))