X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;ds=sidebyside;f=mudsync%2Fplayer.scm;h=bf19a16a6b0e1a0a4716f70333cddaec2a757b8e;hb=7525c62ccdf9e3480214831fb14d9a2d30ab139d;hp=42359bd47db3a116391a788ed8bb39964d787ace;hpb=d13325f5f6eba20c808636948432dcdff4e138f6;p=mudsync.git
diff --git a/mudsync/player.scm b/mudsync/player.scm
index 42359bd..bf19a16 100644
--- a/mudsync/player.scm
+++ b/mudsync/player.scm
@@ -17,16 +17,39 @@
;;; along with Mudsync. If not, see .
(define-module (mudsync player)
+ #:use-module (mudsync command)
#:use-module (mudsync gameobj)
+ #:use-module (mudsync game-master)
+ #:use-module (mudsync parser)
#:use-module (8sync systems actors)
#:use-module (8sync agenda)
+ #:use-module (ice-9 control)
#:use-module (ice-9 format)
+ #:use-module (ice-9 match)
#:use-module (oop goops)
- #:export ())
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
+ #:export (
+ player-self-commands))
;;; Players
;;; =======
+(define player-actions
+ (build-actions
+ (init (wrap-apply player-init!))
+ (handle-input (wrap-apply player-handle-input))
+ (tell (wrap-apply player-tell))
+ ;; @@: We really need to unify / make sensible this look stuff
+ (look-room (wrap-apply player-look-room))))
+
+(define player-actions*
+ (append player-actions
+ gameobj-actions))
+
+(define player-dispatcher
+ (simple-dispatcher player-actions*))
+
(define-class ()
(username #:init-keyword #:username
#:accessor player-username)
@@ -39,20 +62,43 @@
(message-handler
#:init-value
- (make-action-dispatch
- (set-loc! (wrap-apply player-set-loc!))
- (init (wrap-apply player-init!)))))
+ ;; @@: We're gonna need action inheritance real awful soon, huh?
+ (wrap-apply player-dispatcher)))
-;;; player message handlers
-(define-mhandler (player-set-loc! player message id)
- (format #t "DEBUG: Location set to ~s for player ~s\n"
- id (actor-id-actor player))
- (set! (gameobj-loc player) id))
+;;; player message handlers
(define-mhandler (player-init! player message)
(player-look-around player))
+
+(define-mhandler (player-handle-input player message input)
+ (define split-input (split-verb-and-rest input))
+ (define input-verb (pk 'input-verb (car split-input)))
+ (define input-rest (pk 'input-rest (cdr split-input)))
+
+ (define command-candidates
+ (pk 'candidates
+ (player-gather-command-handlers player input-verb)))
+
+ (define winner
+ (pk 'winner (find-command-winner command-candidates input-rest)))
+
+ (match winner
+ ((cmd-action winner-id message-args)
+ (apply send-message player (pk 'winner-id winner-id) (pk 'cmd-action cmd-action) (pk 'message-args message-args)))
+ (#f
+ (<- player (gameobj-gm player) 'write-home
+ #:text "Huh?\n"))))
+
+(define-mhandler (player-tell player message text)
+ (<- player (gameobj-gm player) 'write-home
+ #:text text))
+
+(define-mhandler (player-look-room player message)
+ (player-look-around player))
+
+
;;; player methods
(define (player-look-around player)
@@ -68,3 +114,104 @@
(format #f "**~a**\n~a\n" room-name room-desc))
(<- player (gameobj-gm player) 'write-home #:text message-text))
+
+
+;;; Command handling
+;;; ================
+
+;; @@: Hard to know whether this should be in player.scm or here...
+;; @@: This could be more efficient as a stream...!?
+(define (player-gather-command-handlers player verb)
+ (define player-loc
+ (let ((result (gameobj-loc player)))
+ (if result
+ result
+ (throw 'player-has-no-location
+ "Player ~a has no location! How'd that happen?\n"
+ #:player-id (actor-id player)))))
+
+ ;; Ask the room for its commands
+ (define room-commands
+ ;; TODO: Map room id and sort
+ (message-ref
+ (<-wait player player-loc
+ 'get-container-commands
+ #:verb verb)
+ 'commands))
+
+ ;; All the co-occupants of the room (not including ourself)
+ (define co-occupants
+ (remove
+ (lambda (x) (equal? x (actor-id player)))
+ (message-ref
+ (<-wait player player-loc 'get-occupants)
+ 'occupants)))
+
+ ;; @@: There's a race condition here if someone leaves the room
+ ;; during this, heh...
+ ;; I'm not sure it can be solved, but "lag" on the race can be
+ ;; reduced maybe?
+
+ ;; Get all the co-occupants' commands
+ (define co-occupant-commands
+ ;; TODO: Switch this to a fold. Ignore a result if it
+ ;; returns false for in the command response
+ (map
+ (lambda (co-occupant)
+ (let ((result (<-wait player co-occupant 'get-commands
+ #:verb verb)))
+ (list
+ (message-ref result 'commands)
+ (message-ref result 'goes-by)
+ co-occupant)))
+ co-occupants))
+
+ ;; Append our own command handlers
+ (define our-commands
+ (player-self-commands player))
+
+ ;; TODO: Append our inventory's relevant command handlers
+
+ ;; Now return a big ol sorted list of ((actor-id . command))
+ (append
+ (sort-commands-append-actor (pk 'room-commands room-commands)
+ player-loc '()) ; room doesn't go by anything
+ (sort-commands-multi-actors co-occupant-commands)
+ (sort-commands-append-actor our-commands
+ (actor-id player) '()))) ; nor does player
+
+(define (sort-commands-append-actor commands actor-id goes-by)
+ (sort-commands-multi-actors
+ (map (lambda (command) (list command goes-by actor-id)) commands)))
+
+(define (sort-commands-multi-actors actors-and-commands)
+ (sort
+ actors-and-commands
+ (lambda (x y)
+ (> (command-priority (car (pk 'x x)))
+ (command-priority (car (pk 'y y)))))))
+
+
+(define (find-command-winner sorted-candidates line)
+ "Find a command winner from a sorted list of candidates"
+ ;; A cache of results from matchers we've already seen
+ ;; TODO: fill this in
+ (define matcher-cache '())
+ (call/ec
+ (lambda (return)
+ (for-each
+ (match-lambda
+ ((command actor-goes-by actor-id)
+ (let* ((matcher (command-matcher command))
+ (matched (matcher line)))
+ (if (and matched
+ ;; Great, it matched, but does it also pass
+ ;; should-handle?
+ (apply (command-should-handle command)
+ actor-goes-by
+ matched)) ; matched is kwargs if truthy
+ (return (list (command-action command)
+ (pk 'earlier-actor-id actor-id) matched))
+ #f))))
+ sorted-candidates)
+ #f)))