(define-module (mudsync command)
#:use-module (mudsync parser)
#:use-module (8sync actors)
+ #:use-module (8sync rmeta-slot)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (ice-9 control)
command-action
command-priority
+ build-commands
+
direct-command
prep-indir-command
prep-direct-command
(action command-action)
(priority command-priority))
+(define-syntax %build-command
+ (syntax-rules ()
+ ((_ (verb ...) ((cmd-proc action-sym args ...) ...))
+ (list (cons verb
+ (list (cmd-proc (list verb ...)
+ (quote action-sym)
+ args ...)
+ ...))
+ ...))
+ ((_ verb ((cmd-proc action-sym args ...) ...))
+ (list (cons verb
+ (list (cmd-proc (list verb)
+ (quote action-sym)
+ args ...)
+ ...))))))
+
+(define-syntax-rule (build-commands (verb-or-verbs cmd-defs ...) ...)
+ (wrap-rmeta-slot
+ (append (%build-command verb-or-verbs cmd-defs ...) ...)))
+
(define (direct-command verbs action)
(make-command verbs
#:use-module (mudsync command)
#:use-module (8sync actors)
#:use-module (8sync agenda)
+ #:use-module (8sync rmeta-slot)
#:use-module (srfi srfi-1)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
#:init-keyword #:desc)
;; Commands we can handle
- (commands #:init-value '())
+ (commands #:allocation #:each-subclass
+ #:init-thunk (build-commands))
;; Commands we can handle by being something's container
- (container-commands #:init-value '())
+ (container-commands #:allocation #:each-subclass
+ #:init-thunk (build-commands))
;; Commands we can handle by being contained by something else
- (contained-commands #:init-value '())
+ (contained-commands #:allocation #:each-subclass
+ #:init-thunk (build-commands))
;; Most objects are generally visible by default
(generally-visible #:init-value #t
(val-or-proc)
val-or-proc))
-(define (filter-commands commands verb)
- (filter
- (lambda (cmd)
- (equal? (command-verbs cmd)
- verb))
- commands))
+(define (get-candidate-commands actor rmeta-sym verb)
+ (class-rmeta-ref (class-of actor) rmeta-sym verb
+ #:dflt '()))
(define* (gameobj-get-commands actor message #:key verb)
"Get commands a co-occupant of the room might execute for VERB"
- (define filtered-commands
- (filter-commands (val-or-run (slot-ref actor 'commands))
- verb))
+ (define candidate-commands
+ (get-candidate-commands actor 'commands verb))
(<-reply message
- #:commands filtered-commands
+ #:commands candidate-commands
#:goes-by (gameobj-goes-by actor)))
(define* (gameobj-get-container-commands actor message #:key verb)
"Get commands as the container / room of message's sender"
- (define filtered-commands
- (filter-commands (val-or-run (slot-ref actor 'container-commands))
- verb))
- (<-reply message #:commands filtered-commands))
+ (define candidate-commands
+ (get-candidate-commands actor 'container-commands verb))
+ (<-reply message #:commands candidate-commands))
(define* (gameobj-get-contained-commands actor message #:key verb)
"Get commands as being contained (eg inventory) of commanding gameobj"
- (define filtered-commands
- (filter-commands (val-or-run (slot-ref actor 'contained-commands))
- verb))
+ (define candidate-commands
+ (get-candidate-commands actor 'contained-commands verb))
(<-reply message
- #:commands filtered-commands
+ #:commands candidate-commands
#:goes-by (gameobj-goes-by actor)))
(define* (gameobj-add-occupant! actor message #:key who)
#:use-module (mudsync parser)
#:use-module (8sync actors)
#:use-module (8sync agenda)
+ #:use-module (8sync rmeta-slot)
#:use-module (ice-9 control)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
#:use-module (oop goops)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
- #:export (<player>
- player-self-commands))
+ #:export (<player>))
;;; Players
;;; =======
-(define player-self-commands
- (list
- (empty-command "inventory" 'cmd-inventory)
- ;; aliases...
- ;; @@: Should use an "alias" system for common aliases?
- (empty-command "inv" 'cmd-inventory)
- (empty-command "i" 'cmd-inventory)
- (empty-command "help" 'cmd-help)))
-
(define-class <player> (<gameobj>)
(username #:init-keyword #:username
#:getter player-username)
- (self-commands #:init-value (wrap player-self-commands))
+ (self-commands #:allocation #:each-subclass
+ #:init-thunk
+ (build-commands
+ (("inventory" "inv" "i") ((empty-command cmd-inventory)))
+ ("help" ((empty-command cmd-help)))))
(actions #:allocation #:each-subclass
#:init-thunk
;; Append our own command handlers
(define our-commands
- (filter
- (lambda (cmd)
- (equal? (command-verbs cmd) verb))
- (val-or-run
- (slot-ref player 'self-commands))))
+ (class-rmeta-ref (class-of player) 'self-commands verb
+ #:dflt '()))
;; Append our inventory's relevant command handlers
(define inv-items
;;; Rooms
;;; =====
-(define %room-contain-commands
- (list
- (loose-direct-command "look" 'cmd-look-at)
- (empty-command "look" 'cmd-look-room)
- (empty-command "go" 'cmd-go-where)
- (loose-direct-command "go" 'cmd-go)
- (greedy-command "say" 'cmd-say)
- (greedy-command "\"" 'cmd-say)
- (greedy-command "'" 'cmd-say)
- (greedy-command "emote" 'cmd-emote)
- (greedy-command "/me" 'cmd-emote)))
-
;; TODO: Subclass from container?
(define-class <room> (<gameobj>)
;; A list of <exit>
#:getter room-exits)
(container-commands
- #:init-value (wrap %room-contain-commands))
+ #:allocation #:each-subclass
+ #:init-thunk
+ (build-commands
+ ("look" ((loose-direct-command cmd-look-at)
+ (empty-command cmd-look-room)))
+ ("go" ((empty-command cmd-go-where)
+ (loose-direct-command cmd-go)))
+ (("say" "\"" "'") ((greedy-command cmd-say)))
+ (("emote" "/me") ((greedy-command cmd-emote)))))
(actions #:allocation #:each-subclass
#:init-thunk
#:use-module (oop goops)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
- #:export (<thing>
- thing-commands
- thing-commands*
- thing-contained-commands
- thing-contained-commands*))
-
-(define thing-commands
- (list
- (direct-command "take" 'cmd-take)))
-
-;; Doesn't inherit anything (gameobj has no commands)
-;; so it's an alias.
-(define thing-commands* thing-commands)
-
-(define thing-contained-commands
- (list
- (direct-command "drop" 'cmd-drop)))
-
-;; Doesn't inherit anything (gameobj has no contained-commands)
-;; so it's an alias.
-(define thing-contained-commands* thing-contained-commands)
+ #:export (<thing>))
(define-class <thing> (<gameobj>)
;; Can be a boolean or a procedure accepting two arguments
(dropable #:init-value #t
#:init-keyword #:dropable)
(commands
- #:init-value (wrap thing-commands))
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ ("take" ((direct-command cmd-take)))))
(contained-commands
- #:init-value (wrap thing-contained-commands))
+ #:allocation #:each-subclass
+ #:init-value (build-commands
+ ("drop" ((direct-command cmd-drop)))))
(actions #:allocation #:each-subclass
#:init-thunk
(build-actions
;;; Some simple object types.
;;; =========================
-(define readable-commands
- (list
- (direct-command "read" 'cmd-read)))
-
-(define readable-commands*
- (append readable-commands
- thing-commands))
-
(define-class <readable> (<thing>)
(read-text #:init-value "All it says is: \"Blah blah blah.\""
#:init-keyword #:read-text)
(commands
- #:init-value readable-commands*)
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ ("read" ((direct-command cmd-read)))))
(actions #:allocation #:each-subclass
#:init-thunk (build-actions
(cmd-read readable-cmd-read))))
(<- (message-from message) 'tell
#:text text-to-send))
-(define chat-commands
- (list
- (direct-command "chat" 'cmd-chat)
- (direct-command "talk" 'cmd-chat)))
-
(define hotel-owner-grumps
'("Eight sinks! Eight sinks! And I couldn't unwind them..."
"Don't mind the mess. I built this place on a dare, you
(catchphrases #:init-value '("Blarga blarga blarga!")
#:init-keyword #:catchphrases)
(commands
- #:init-value chat-commands)
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ (("chat" "talk") ((direct-command cmd-chat)))))
(actions #:allocation #:each-subclass
#:init-thunk
(build-actions
(define-class <sign-in-form> (<gameobj>)
(commands
- #:init-value
- (list
- (prep-direct-command "sign" 'cmd-sign-form
- '("as"))))
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ ("sign" ((prep-direct-command cmd-sign-form '("as"))))))
(actions #:allocation #:each-subclass
#:init-thunk (build-actions
(cmd-sign-form sign-cmd-sign-in))))
character.\n")))
-(define summoning-bell-commands
- (list
- (direct-command "ring" 'cmd-ring)))
-(define summoning-bell-commands*
- (append summoning-bell-commands
- thing-commands*))
-
(define-class <summoning-bell> (<thing>)
(summons #:init-keyword #:summons)
(commands
- #:init-value summoning-bell-commands*)
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ ("ring" ((direct-command cmd-ring)))))
(actions #:allocation #:each-subclass
#:init-thunk (build-actions
(cmd-ring summoning-bell-cmd-ring))))
(sit-name #:init-keyword #:sit-name)
(commands
- #:init-value
- (list
- (direct-command "sit" 'cmd-sit-furniture)))
+ #:allocation #:each-subclass
+ #:init-thunk (build-commands
+ ("sit" ((direct-command cmd-sit-furniture)))))
(actions #:allocation #:each-subclass
#:init-thunk (build-actions
(cmd-sit-furniture furniture-cmd-sit))))
;;; Breakroom
;;; ---------
-(define clerk-commands
- (list
- (direct-command "talk" 'cmd-chat)
- (direct-command "chat" 'cmd-chat)
- (direct-command "ask" 'cmd-ask-incomplete)
- (prep-direct-command "ask" 'cmd-ask-about)
- (direct-command "dismiss" 'cmd-dismiss)))
-(define clerk-commands*
- (append clerk-commands thing-commands*))
-
(define-class <desk-clerk> (<thing>)
;; The desk clerk has three states:
;; - on-duty: Arrived, and waiting for instructions (and losing patience
;; - slacking: In the break room, probably smoking a cigarette
;; or checking text messages
(state #:init-value 'slacking)
- (commands #:init-value clerk-commands*)
+ (commands #:allocation #:each-subclass
+ #:init-thunk
+ (build-commands
+ (("talk" "chat") ((direct-command cmd-chat)))
+ ("ask" ((direct-command cmd-ask-incomplete)
+ (prep-direct-command cmd-ask-about)))
+ ("dismiss" ((direct-command cmd-dismiss)))))
(patience #:init-value 0)
(actions #:allocation #:each-subclass
#:init-thunk (build-actions