diff --git a/TODO b/TODO index dfac010..fa6aeb4 100644 --- a/TODO +++ b/TODO @@ -23,10 +23,12 @@ * error handling! * create help window + +* implement "command" window for extended user commands * remove char & colour attribute from map transfer -* generate secondary seeds to smoothen landscape +* generate secondary seeds to smoothen landscape (make world prettier) * split `naledi-ya-africa` package into `naledi-server` and `naledi-client`? @@ -42,6 +44,8 @@ -> SEVERE * `terminate` hangs when a player is still logged in + +* cannot start two local games one after the other -> "ERROR: player exists" * world thread type error: "The value -1 is not of type unsigned-byte when binding sb-impl::n" -> if several players log on? / if one player quits? diff --git a/TODO b/TODO index dfac010..fa6aeb4 100644 --- a/TODO +++ b/TODO @@ -23,10 +23,12 @@ * error handling! * create help window + +* implement "command" window for extended user commands * remove char & colour attribute from map transfer -* generate secondary seeds to smoothen landscape +* generate secondary seeds to smoothen landscape (make world prettier) * split `naledi-ya-africa` package into `naledi-server` and `naledi-client`? @@ -42,6 +44,8 @@ -> SEVERE * `terminate` hangs when a player is still logged in + +* cannot start two local games one after the other -> "ERROR: player exists" * world thread type error: "The value -1 is not of type unsigned-byte when binding sb-impl::n" -> if several players log on? / if one player quits? diff --git a/client/user-interface.lisp b/client/user-interface.lisp index 13c3aa8..497b298 100644 --- a/client/user-interface.lisp +++ b/client/user-interface.lisp @@ -23,7 +23,7 @@ (defun splash-screen (scr) "Display the splash screen with the `Naledi ya Africa' logo" (let* ((width (croatoan:.width scr)) (height (croatoan:.height scr)) - ;;FIXME fails when not in the naledi directory + ;;XXX fails when not in the naledi directory (logo (load-text-file "LOGO")) (y (halve (- height (length logo)))) (xoff (halve (- width 80)))) @@ -90,8 +90,9 @@ :center t :border t :width 50 :max-item-length 42 :input-blocking t :cyclic-selection t :current-item-mark "* " + ;;TODO change to 250, 500, 1000, 5000 :items '("Small (100)" "Standard (250)" "Medium (500)" - "Large (1000)")))) ; "Huge (5000)")))) + "Large (1000)")))) ;"Huge (5000)")))) ;;XXX I have to effectively reimplement (select-item menu) because ;; the screen grabs all user input and none arrives at the window (setf (croatoan:.current-item-number mw) 1) @@ -107,8 +108,8 @@ (1 (setf *world-size* 250)) (2 (setf *world-size* 500)) (3 (setf *world-size* 1000))) - ;;XXX uses >1GB RAM -> heap exhaustion - ;;(4 (setf *world-size* 5000))) + ;;XXX uses >1GB RAM -> heap exhaustion + ;;(4 (setf *world-size* 5000))) (return-from croatoan:event-case))))) (defun connect-remote-game (scr) @@ -147,7 +148,6 @@ (playerwin :position (list 0 (- width 50)) :input-blocking *framerate* :border t :width 50 :height (round (* 0.6 height))) - ;;:height (halve height 'down)) (placewin :input-blocking *framerate* :border t :position (list (round (* 0.6 height)) @@ -157,36 +157,55 @@ :position (list height 0) :width width :height 1)) (update-ui mapwin playerwin placewin newswin) - ;;TODO - (croatoan:event-case (scr event) - (#\q (disconnect) - ;;terminate if we're running a local game - (when (member "server-thread" (bt:all-threads) :test - #'(lambda (nm th) - (equalp nm (bt:thread-name th)))) - (terminate)) - (return-from croatoan:event-case)) - (#\n (croatoan:draw-menu (message-window))) - ;;XXX How about moving diagonally? - ;;TODO remove the duplicated `update-ui' calls - ;;TODO also `flushinp' (clears input to prevent inertia effect) - (:up (query-server "move n") (de.anvi.ncurses:%flushinp) - (update-ui mapwin playerwin placewin newswin)) - (:down (query-server "move s") (de.anvi.ncurses:%flushinp) - (update-ui mapwin playerwin placewin newswin)) - (:left (query-server "move w") (de.anvi.ncurses:%flushinp) - (update-ui mapwin playerwin placewin newswin)) - (:right (query-server "move e") (de.anvi.ncurses:%flushinp) - (update-ui mapwin playerwin placewin newswin)) - ((nil) (update-ui mapwin playerwin placewin newswin)) - (otherwise (notify (string event))))))) ;;DEBUG + ;;XXX This function is too long - shift the `event-case' elsewhere? + (flet ((ui-update () + (de.anvi.ncurses:%flushinp) ;discard excessive key events + (update-ui mapwin playerwin placewin newswin))) + (croatoan:event-case (scr event) + ;;TODO add other commands + ;;(#\a -> toggle attack mode + ;;(#\c -> command console + ;;(#\p -> pickup item + ;;(#\i -> manage inventory + (#\q (disconnect) + ;;terminate if we're running a local game + (when (member "server-thread" (bt:all-threads) :test + #'(lambda (nm th) + (equalp nm (bt:thread-name th)))) + (terminate)) + (return-from croatoan:event-case)) + (#\n (set-popup 'NEWS) (ui-update)) + ;;XXX How about moving diagonally? + (:up (query-server "move n") (ui-update)) + (:down (query-server "move s") (ui-update)) + (:left (query-server "move w") (ui-update)) + (:right (query-server "move e") (ui-update)) + ((nil) (ui-update))))))) -(defun update-ui (mapwin playerwin placewin newswin) - "Update all four UI elements" - (draw-map mapwin) - (draw-descriptive-panel playerwin "describe-player") - (draw-descriptive-panel placewin "describe-patch") - (draw-news-panel newswin)) +(let ((popup nil) (popup-modes '(NEWS CONSOLE INVENTORY))) + (defun set-popup (&optional next-popup) + "Which popup window should be shown?" + (if (or (null next-popup) (member next-popup popup-modes)) + (setf popup next-popup) + (error "~S is not a permitted popup mode." next-popup))) + + (defun update-ui (mapwin playerwin placewin newswin) + "Update all four UI elements" + (draw-map mapwin) + (draw-descriptive-panel playerwin "describe-player") + (draw-descriptive-panel placewin "describe-patch") + (draw-news-panel newswin) + (draw-popup-window)) + + ;;TODO This is not yet a good solution. First, window objects are + ;; constantly created. Secondly, these windows cannot be controlled, + ;; because all key events are still handled by the main UI... + (defun draw-popup-window () + "Draw the current popup window, if appropriate" + (case popup + ('NEWS (croatoan:draw-menu (message-window))) + ('CONSOLE ) + ('NEWSWIN )))) (defun draw-map (win) "Draw a portion of the game map in an ncurses window" @@ -254,7 +273,7 @@ ;;XXX use `user-inform' instead of dialog-window? (make-instance 'croatoan:dialog-window :input-blocking t - :items (break-lines (mapcar #'(lambda (n) (sconc "* " n)) news) 50) + :items (break-lines (mapcar #'(lambda (n) (sconc "* " n)) news) 49) :center t :border t :stacked t @@ -264,7 +283,7 @@ :message-height 2 :message-text "Press b to go back."))) ;;:event-handlers '((#\b #'exit-event-loop))))) - + ;;TODO command/chat window (defun process-command (event)