diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/client/user-interface.lisp b/client/user-interface.lisp index b779719..77c82e7 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -183,42 +183,6 @@ (draw-place-panel placewin) (draw-news-panel newswin)) -(defun draw-map-old (win me) - "Draw a portion of the game map in an ncurses window" - (setf (croatoan:.color-pair win) '(:white :black)) - (croatoan:box win) - (croatoan:move win 1 1) - (let ((x0 (- (first me) (round (/ (croatoan:.width win) 4)))) - (y0 (- (second me) (halve (croatoan:.height win))))) - ;; NB. x0 and w are calculated differently to y0 and h because we insert - ;; a space after each character - (dotimes (h (1- (croatoan:.height win))) - (dotimes (w (- (halve (croatoan:.width win) 'floor) 2)) - ;;TODO replace `coord' with `query-server' - (let ((p (coord (+ w x0 3) (+ h y0 1)))) - (if (null p) (croatoan:add-char win #\space) - (if (and (= (first (patch-pos p)) (first me)) - (= (second (patch-pos p)) (second me))) - (progn (setf (croatoan:.color-pair win) - '(:white :black)) - (croatoan:add-char win #\@)) - (if (patch-occupant p) - (progn - (setf (croatoan:.color-pair win) - (list (.color (patch-occupant p)) - :black)) - (croatoan:add-char win - (.char (patch-occupant p)))) - (progn - (setf (croatoan:.color-pair win) - (list (biome-col (patch-biome p)) - :black)) - (croatoan:add-char win - (biome-char (patch-biome p))))))) - (croatoan:add-char win #\space))) - (croatoan:move win (1+ h) 1)) - (croatoan:refresh win))) - (defun draw-map (win) "Draw a portion of the game map in an ncurses window" ;;XXX request each patch char singly from the server - doing it all @@ -261,28 +225,24 @@ (1+ (first (croatoan:.cursor-position win))) 1)) (croatoan:refresh win))) -;;FIXME needs to be overhauled for client/server (let ((news '("Press h for help."))) (defun draw-news-panel (win) "Draw a thin panel at the bottom of the screen to display news items." + (collect-news) (croatoan:clear win) (croatoan:move win 0 0) - ;;TODO get news from server (croatoan:add-string win (car news)) (croatoan:refresh win)) - (defun notify (news-string &rest formats) - "Append a string to the news to notify the user." - ;;TODO needs to be moved to the server - ;;A bit of a kluge, but means that `notify' supports formatting - (setf news - (cons (apply #'format (cons NIL (cons news-string formats))) - news))) + (defun collect-news () + "Collect news for this player from the server" + ;;XXX I don't quite understand why I need to do `read-from-string' here + (let ((messages (read-from-string (query-server "messages")))) + (when messages (setf news (append messages news))))) (defun message-window () "Return a dialog window with the last game messages." - ;;TODO complete - ;;TODO get news from server + ;;TODO complete - stop the window disappearing ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/client/user-interface.lisp b/client/user-interface.lisp index b779719..77c82e7 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -183,42 +183,6 @@ (draw-place-panel placewin) (draw-news-panel newswin)) -(defun draw-map-old (win me) - "Draw a portion of the game map in an ncurses window" - (setf (croatoan:.color-pair win) '(:white :black)) - (croatoan:box win) - (croatoan:move win 1 1) - (let ((x0 (- (first me) (round (/ (croatoan:.width win) 4)))) - (y0 (- (second me) (halve (croatoan:.height win))))) - ;; NB. x0 and w are calculated differently to y0 and h because we insert - ;; a space after each character - (dotimes (h (1- (croatoan:.height win))) - (dotimes (w (- (halve (croatoan:.width win) 'floor) 2)) - ;;TODO replace `coord' with `query-server' - (let ((p (coord (+ w x0 3) (+ h y0 1)))) - (if (null p) (croatoan:add-char win #\space) - (if (and (= (first (patch-pos p)) (first me)) - (= (second (patch-pos p)) (second me))) - (progn (setf (croatoan:.color-pair win) - '(:white :black)) - (croatoan:add-char win #\@)) - (if (patch-occupant p) - (progn - (setf (croatoan:.color-pair win) - (list (.color (patch-occupant p)) - :black)) - (croatoan:add-char win - (.char (patch-occupant p)))) - (progn - (setf (croatoan:.color-pair win) - (list (biome-col (patch-biome p)) - :black)) - (croatoan:add-char win - (biome-char (patch-biome p))))))) - (croatoan:add-char win #\space))) - (croatoan:move win (1+ h) 1)) - (croatoan:refresh win))) - (defun draw-map (win) "Draw a portion of the game map in an ncurses window" ;;XXX request each patch char singly from the server - doing it all @@ -261,28 +225,24 @@ (1+ (first (croatoan:.cursor-position win))) 1)) (croatoan:refresh win))) -;;FIXME needs to be overhauled for client/server (let ((news '("Press h for help."))) (defun draw-news-panel (win) "Draw a thin panel at the bottom of the screen to display news items." + (collect-news) (croatoan:clear win) (croatoan:move win 0 0) - ;;TODO get news from server (croatoan:add-string win (car news)) (croatoan:refresh win)) - (defun notify (news-string &rest formats) - "Append a string to the news to notify the user." - ;;TODO needs to be moved to the server - ;;A bit of a kluge, but means that `notify' supports formatting - (setf news - (cons (apply #'format (cons NIL (cons news-string formats))) - news))) + (defun collect-news () + "Collect news for this player from the server" + ;;XXX I don't quite understand why I need to do `read-from-string' here + (let ((messages (read-from-string (query-server "messages")))) + (when messages (setf news (append messages news))))) (defun message-window () "Return a dialog window with the last game messages." - ;;TODO complete - ;;TODO get news from server + ;;TODO complete - stop the window disappearing ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t diff --git a/params.lisp b/params.lisp index 3b1f3fa..0519bb9 100644 --- a/params.lisp +++ b/params.lisp @@ -28,7 +28,7 @@ (defparameter *framerate* 1000) ;;Localhost defaults -(defparameter *defaulthost* '("127.0.0.1" 21895)) ;default port: 21895 +(defparameter *defaulthost* '("127.0.0.1" 21892)) ;default port: 21895 ;;Host server address to connect to - XXX global variable! (defparameter *host* (first *defaulthost*)) diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/client/user-interface.lisp b/client/user-interface.lisp index b779719..77c82e7 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -183,42 +183,6 @@ (draw-place-panel placewin) (draw-news-panel newswin)) -(defun draw-map-old (win me) - "Draw a portion of the game map in an ncurses window" - (setf (croatoan:.color-pair win) '(:white :black)) - (croatoan:box win) - (croatoan:move win 1 1) - (let ((x0 (- (first me) (round (/ (croatoan:.width win) 4)))) - (y0 (- (second me) (halve (croatoan:.height win))))) - ;; NB. x0 and w are calculated differently to y0 and h because we insert - ;; a space after each character - (dotimes (h (1- (croatoan:.height win))) - (dotimes (w (- (halve (croatoan:.width win) 'floor) 2)) - ;;TODO replace `coord' with `query-server' - (let ((p (coord (+ w x0 3) (+ h y0 1)))) - (if (null p) (croatoan:add-char win #\space) - (if (and (= (first (patch-pos p)) (first me)) - (= (second (patch-pos p)) (second me))) - (progn (setf (croatoan:.color-pair win) - '(:white :black)) - (croatoan:add-char win #\@)) - (if (patch-occupant p) - (progn - (setf (croatoan:.color-pair win) - (list (.color (patch-occupant p)) - :black)) - (croatoan:add-char win - (.char (patch-occupant p)))) - (progn - (setf (croatoan:.color-pair win) - (list (biome-col (patch-biome p)) - :black)) - (croatoan:add-char win - (biome-char (patch-biome p))))))) - (croatoan:add-char win #\space))) - (croatoan:move win (1+ h) 1)) - (croatoan:refresh win))) - (defun draw-map (win) "Draw a portion of the game map in an ncurses window" ;;XXX request each patch char singly from the server - doing it all @@ -261,28 +225,24 @@ (1+ (first (croatoan:.cursor-position win))) 1)) (croatoan:refresh win))) -;;FIXME needs to be overhauled for client/server (let ((news '("Press h for help."))) (defun draw-news-panel (win) "Draw a thin panel at the bottom of the screen to display news items." + (collect-news) (croatoan:clear win) (croatoan:move win 0 0) - ;;TODO get news from server (croatoan:add-string win (car news)) (croatoan:refresh win)) - (defun notify (news-string &rest formats) - "Append a string to the news to notify the user." - ;;TODO needs to be moved to the server - ;;A bit of a kluge, but means that `notify' supports formatting - (setf news - (cons (apply #'format (cons NIL (cons news-string formats))) - news))) + (defun collect-news () + "Collect news for this player from the server" + ;;XXX I don't quite understand why I need to do `read-from-string' here + (let ((messages (read-from-string (query-server "messages")))) + (when messages (setf news (append messages news))))) (defun message-window () "Return a dialog window with the last game messages." - ;;TODO complete - ;;TODO get news from server + ;;TODO complete - stop the window disappearing ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t diff --git a/params.lisp b/params.lisp index 3b1f3fa..0519bb9 100644 --- a/params.lisp +++ b/params.lisp @@ -28,7 +28,7 @@ (defparameter *framerate* 1000) ;;Localhost defaults -(defparameter *defaulthost* '("127.0.0.1" 21895)) ;default port: 21895 +(defparameter *defaulthost* '("127.0.0.1" 21892)) ;default port: 21895 ;;Host server address to connect to - XXX global variable! (defparameter *host* (first *defaulthost*)) diff --git a/server/item-methods.lisp b/server/item-methods.lisp index c1260e4..6a97a58 100644 --- a/server/item-methods.lisp +++ b/server/item-methods.lisp @@ -11,17 +11,21 @@ (in-package :naledi-ya-africa) (defmethod move ((a animal) dir) + "An animal moves one space in the specified direction, if possible" (let* ((here (coord (.x a) (.y a))) (target (coordsindir (.x a) (.y a) dir)) (target-patch (coord (first target) (second target)))) (cond ((null target-patch) - (logf 3 "~S is attempting to move out of bounds ~S" a target)) + (logf 3 "~S is attempting to move out of bounds ~S" a target) + 'OUT-OF-BOUNDS) ((patch-occupant target-patch) (logf 3 "~S is moving onto occupied patch ~S (~S)" - a target (patch-occupant target-patch))) + a target (patch-occupant target-patch)) + 'PATCH-OCCUPIED) (T (setf (patch-occupant here) NIL) (setf (patch-occupant target-patch) a) - (setf (.x a) (first target) (.y a) (second target)))))) + (setf (.x a) (first target) (.y a) (second target)) + T)))) ;; Default `update' and `action' methods are NOP (defmethod update ((i item))) diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/client/user-interface.lisp b/client/user-interface.lisp index b779719..77c82e7 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -183,42 +183,6 @@ (draw-place-panel placewin) (draw-news-panel newswin)) -(defun draw-map-old (win me) - "Draw a portion of the game map in an ncurses window" - (setf (croatoan:.color-pair win) '(:white :black)) - (croatoan:box win) - (croatoan:move win 1 1) - (let ((x0 (- (first me) (round (/ (croatoan:.width win) 4)))) - (y0 (- (second me) (halve (croatoan:.height win))))) - ;; NB. x0 and w are calculated differently to y0 and h because we insert - ;; a space after each character - (dotimes (h (1- (croatoan:.height win))) - (dotimes (w (- (halve (croatoan:.width win) 'floor) 2)) - ;;TODO replace `coord' with `query-server' - (let ((p (coord (+ w x0 3) (+ h y0 1)))) - (if (null p) (croatoan:add-char win #\space) - (if (and (= (first (patch-pos p)) (first me)) - (= (second (patch-pos p)) (second me))) - (progn (setf (croatoan:.color-pair win) - '(:white :black)) - (croatoan:add-char win #\@)) - (if (patch-occupant p) - (progn - (setf (croatoan:.color-pair win) - (list (.color (patch-occupant p)) - :black)) - (croatoan:add-char win - (.char (patch-occupant p)))) - (progn - (setf (croatoan:.color-pair win) - (list (biome-col (patch-biome p)) - :black)) - (croatoan:add-char win - (biome-char (patch-biome p))))))) - (croatoan:add-char win #\space))) - (croatoan:move win (1+ h) 1)) - (croatoan:refresh win))) - (defun draw-map (win) "Draw a portion of the game map in an ncurses window" ;;XXX request each patch char singly from the server - doing it all @@ -261,28 +225,24 @@ (1+ (first (croatoan:.cursor-position win))) 1)) (croatoan:refresh win))) -;;FIXME needs to be overhauled for client/server (let ((news '("Press h for help."))) (defun draw-news-panel (win) "Draw a thin panel at the bottom of the screen to display news items." + (collect-news) (croatoan:clear win) (croatoan:move win 0 0) - ;;TODO get news from server (croatoan:add-string win (car news)) (croatoan:refresh win)) - (defun notify (news-string &rest formats) - "Append a string to the news to notify the user." - ;;TODO needs to be moved to the server - ;;A bit of a kluge, but means that `notify' supports formatting - (setf news - (cons (apply #'format (cons NIL (cons news-string formats))) - news))) + (defun collect-news () + "Collect news for this player from the server" + ;;XXX I don't quite understand why I need to do `read-from-string' here + (let ((messages (read-from-string (query-server "messages")))) + (when messages (setf news (append messages news))))) (defun message-window () "Return a dialog window with the last game messages." - ;;TODO complete - ;;TODO get news from server + ;;TODO complete - stop the window disappearing ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t diff --git a/params.lisp b/params.lisp index 3b1f3fa..0519bb9 100644 --- a/params.lisp +++ b/params.lisp @@ -28,7 +28,7 @@ (defparameter *framerate* 1000) ;;Localhost defaults -(defparameter *defaulthost* '("127.0.0.1" 21895)) ;default port: 21895 +(defparameter *defaulthost* '("127.0.0.1" 21892)) ;default port: 21895 ;;Host server address to connect to - XXX global variable! (defparameter *host* (first *defaulthost*)) diff --git a/server/item-methods.lisp b/server/item-methods.lisp index c1260e4..6a97a58 100644 --- a/server/item-methods.lisp +++ b/server/item-methods.lisp @@ -11,17 +11,21 @@ (in-package :naledi-ya-africa) (defmethod move ((a animal) dir) + "An animal moves one space in the specified direction, if possible" (let* ((here (coord (.x a) (.y a))) (target (coordsindir (.x a) (.y a) dir)) (target-patch (coord (first target) (second target)))) (cond ((null target-patch) - (logf 3 "~S is attempting to move out of bounds ~S" a target)) + (logf 3 "~S is attempting to move out of bounds ~S" a target) + 'OUT-OF-BOUNDS) ((patch-occupant target-patch) (logf 3 "~S is moving onto occupied patch ~S (~S)" - a target (patch-occupant target-patch))) + a target (patch-occupant target-patch)) + 'PATCH-OCCUPIED) (T (setf (patch-occupant here) NIL) (setf (patch-occupant target-patch) a) - (setf (.x a) (first target) (.y a) (second target)))))) + (setf (.x a) (first target) (.y a) (second target)) + T)))) ;; Default `update' and `action' methods are NOP (defmethod update ((i item))) diff --git a/server/player.lisp b/server/player.lisp index 76a462c..30cc756 100644 --- a/server/player.lisp +++ b/server/player.lisp @@ -14,7 +14,8 @@ (name "") (password "") (online NIL) - (human NIL)) + (human NIL) + (messages NIL)) (defclass human (animal) ;; The game entity representing a human player @@ -35,6 +36,32 @@ ;;TODO ) +(defmethod move ((h human) dir) + "A human moves one space in the specified direction, if possible." + ;;TODO allow for attack/explore mode + (let ((p (get-player (.name h)))) + (logf 4 "Moving player ~A (~S)" (.name h) p) + (case (call-next-method) + ('OUT-OF-BOUNDS (msg-player p "Out of bounds.") NIL) + ('PATCH-OCCUPIED + (msg-player p "This patch is occupied by ~A." + (leading-vowel (.name (patch-occupant + (patchindir (.x h) (.y h) dir))))) + NIL) + (T T)))) + +(defun msg-player (player msg &rest format-args) + "Send a message to a player (adds it to the queue)" + (setf (player-messages player) + (append (player-messages player) + (list (apply #'format (append (list NIL msg) format-args)))))) + +(defun collect-messages (player) + "Collect this player's messages and clear the queue" + (let ((msgs (player-messages player))) + (setf (player-messages player) NIL) + msgs)) + ;; INVENTORY HANDLING FUNCTIONS ;;TODO convert to methods diff --git a/TODO b/TODO index b4d2b52..00f554e 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,9 @@ GAME - + +* display player panel information + * implement look/walk/attack modes * expand player implementation diff --git a/client/crt-ext.lisp b/client/crt-ext.lisp index 3d64869..974cac9 100644 --- a/client/crt-ext.lisp +++ b/client/crt-ext.lisp @@ -11,7 +11,7 @@ (defun query-user (scr msg &key (cls NIL) (val-width 30) (default "")) "Display a popup asking the user to enter a value, then return that value" - ;; I found croatoan's field/form to complicated to use (:form-default-keymap + ;; I found croatoan's field/form too complicated to use (:form-default-keymap ;; doesn't seem to work), so I hacked up my own alternative ;; TODO display additional lines of text (when cls (croatoan:clear scr) diff --git a/client/networking.lisp b/client/networking.lisp index aa89563..ad66491 100644 --- a/client/networking.lisp +++ b/client/networking.lisp @@ -24,7 +24,7 @@ "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. - ;;TODO the client should handle errors gracefully! + ;;TODO the client should handle errors gracefully (unless naledi-server ;XXX do this with exceptions (return-from query-server "You are not connected to a server!")) (let* ((servstr (usocket:socket-stream naledi-server)) diff --git a/client/user-interface.lisp b/client/user-interface.lisp index b779719..77c82e7 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -183,42 +183,6 @@ (draw-place-panel placewin) (draw-news-panel newswin)) -(defun draw-map-old (win me) - "Draw a portion of the game map in an ncurses window" - (setf (croatoan:.color-pair win) '(:white :black)) - (croatoan:box win) - (croatoan:move win 1 1) - (let ((x0 (- (first me) (round (/ (croatoan:.width win) 4)))) - (y0 (- (second me) (halve (croatoan:.height win))))) - ;; NB. x0 and w are calculated differently to y0 and h because we insert - ;; a space after each character - (dotimes (h (1- (croatoan:.height win))) - (dotimes (w (- (halve (croatoan:.width win) 'floor) 2)) - ;;TODO replace `coord' with `query-server' - (let ((p (coord (+ w x0 3) (+ h y0 1)))) - (if (null p) (croatoan:add-char win #\space) - (if (and (= (first (patch-pos p)) (first me)) - (= (second (patch-pos p)) (second me))) - (progn (setf (croatoan:.color-pair win) - '(:white :black)) - (croatoan:add-char win #\@)) - (if (patch-occupant p) - (progn - (setf (croatoan:.color-pair win) - (list (.color (patch-occupant p)) - :black)) - (croatoan:add-char win - (.char (patch-occupant p)))) - (progn - (setf (croatoan:.color-pair win) - (list (biome-col (patch-biome p)) - :black)) - (croatoan:add-char win - (biome-char (patch-biome p))))))) - (croatoan:add-char win #\space))) - (croatoan:move win (1+ h) 1)) - (croatoan:refresh win))) - (defun draw-map (win) "Draw a portion of the game map in an ncurses window" ;;XXX request each patch char singly from the server - doing it all @@ -261,28 +225,24 @@ (1+ (first (croatoan:.cursor-position win))) 1)) (croatoan:refresh win))) -;;FIXME needs to be overhauled for client/server (let ((news '("Press h for help."))) (defun draw-news-panel (win) "Draw a thin panel at the bottom of the screen to display news items." + (collect-news) (croatoan:clear win) (croatoan:move win 0 0) - ;;TODO get news from server (croatoan:add-string win (car news)) (croatoan:refresh win)) - (defun notify (news-string &rest formats) - "Append a string to the news to notify the user." - ;;TODO needs to be moved to the server - ;;A bit of a kluge, but means that `notify' supports formatting - (setf news - (cons (apply #'format (cons NIL (cons news-string formats))) - news))) + (defun collect-news () + "Collect news for this player from the server" + ;;XXX I don't quite understand why I need to do `read-from-string' here + (let ((messages (read-from-string (query-server "messages")))) + (when messages (setf news (append messages news))))) (defun message-window () "Return a dialog window with the last game messages." - ;;TODO complete - ;;TODO get news from server + ;;TODO complete - stop the window disappearing ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t diff --git a/params.lisp b/params.lisp index 3b1f3fa..0519bb9 100644 --- a/params.lisp +++ b/params.lisp @@ -28,7 +28,7 @@ (defparameter *framerate* 1000) ;;Localhost defaults -(defparameter *defaulthost* '("127.0.0.1" 21895)) ;default port: 21895 +(defparameter *defaulthost* '("127.0.0.1" 21892)) ;default port: 21895 ;;Host server address to connect to - XXX global variable! (defparameter *host* (first *defaulthost*)) diff --git a/server/item-methods.lisp b/server/item-methods.lisp index c1260e4..6a97a58 100644 --- a/server/item-methods.lisp +++ b/server/item-methods.lisp @@ -11,17 +11,21 @@ (in-package :naledi-ya-africa) (defmethod move ((a animal) dir) + "An animal moves one space in the specified direction, if possible" (let* ((here (coord (.x a) (.y a))) (target (coordsindir (.x a) (.y a) dir)) (target-patch (coord (first target) (second target)))) (cond ((null target-patch) - (logf 3 "~S is attempting to move out of bounds ~S" a target)) + (logf 3 "~S is attempting to move out of bounds ~S" a target) + 'OUT-OF-BOUNDS) ((patch-occupant target-patch) (logf 3 "~S is moving onto occupied patch ~S (~S)" - a target (patch-occupant target-patch))) + a target (patch-occupant target-patch)) + 'PATCH-OCCUPIED) (T (setf (patch-occupant here) NIL) (setf (patch-occupant target-patch) a) - (setf (.x a) (first target) (.y a) (second target)))))) + (setf (.x a) (first target) (.y a) (second target)) + T)))) ;; Default `update' and `action' methods are NOP (defmethod update ((i item))) diff --git a/server/player.lisp b/server/player.lisp index 76a462c..30cc756 100644 --- a/server/player.lisp +++ b/server/player.lisp @@ -14,7 +14,8 @@ (name "") (password "") (online NIL) - (human NIL)) + (human NIL) + (messages NIL)) (defclass human (animal) ;; The game entity representing a human player @@ -35,6 +36,32 @@ ;;TODO ) +(defmethod move ((h human) dir) + "A human moves one space in the specified direction, if possible." + ;;TODO allow for attack/explore mode + (let ((p (get-player (.name h)))) + (logf 4 "Moving player ~A (~S)" (.name h) p) + (case (call-next-method) + ('OUT-OF-BOUNDS (msg-player p "Out of bounds.") NIL) + ('PATCH-OCCUPIED + (msg-player p "This patch is occupied by ~A." + (leading-vowel (.name (patch-occupant + (patchindir (.x h) (.y h) dir))))) + NIL) + (T T)))) + +(defun msg-player (player msg &rest format-args) + "Send a message to a player (adds it to the queue)" + (setf (player-messages player) + (append (player-messages player) + (list (apply #'format (append (list NIL msg) format-args)))))) + +(defun collect-messages (player) + "Collect this player's messages and clear the queue" + (let ((msgs (player-messages player))) + (setf (player-messages player) NIL) + msgs)) + ;; INVENTORY HANDLING FUNCTIONS ;;TODO convert to methods diff --git a/server/server.lisp b/server/server.lisp index a1d0baf..5eba089 100644 --- a/server/server.lisp +++ b/server/server.lisp @@ -25,7 +25,7 @@ (defun add-player (name passwd) (let ((np (make-player :name name :password passwd :online NIL - :human (make-instance 'human + :human (make-instance 'human :name name :x (random *world-size*) :y (random *world-size*))))) (setf players (cons np players)))) @@ -251,7 +251,7 @@ (x0 (- (.x plr) (halve width))) (y0 (- (.y plr) (halve height))) (submap (make-array (list width height 2)))) - (dotimes (h height submap) ;;XXX remove submap again of doesn't work + (dotimes (h height submap) (dotimes (w width) (let ((p (coord (+ w x0 1) (+ h y0 1))) (next-char #\space) (next-col ':black)) @@ -262,13 +262,6 @@ next-col (biome-col (patch-biome p))))) (setf (aref submap w h 0) next-char (aref submap w h 1) next-col)))))) - ;;XXX Arrays are pretty-printed with linebreaks, this causes a - ;; client-side error (as the client only expects one line). - ;; The following code takes apart such a pretty print and puts it - ;; back together without linebreaks. However, this means that the - ;; server returns a map string enclosed in _two_ quotation marks, - ;; so the client has to perform an additional call to `read-from-string` - ;;(string-from-list (split-string (to-string submap) #\newline) ""))) (defun describe-patch (&optional (x 0) (y 0)) "Return a set of lines describing the patch at these coordinates." @@ -312,4 +305,6 @@ (list "signup" #'create-player) (list "map" #'get-map) (list "describe-patch" #'describe-patch) - (list "move" #'move-player))) + (list "move" #'move-player) + (list "messages" + #'(lambda () (collect-messages (get-player (thread-player)))))))