diff --git a/lisp/atlantis.lisp b/lisp/atlantis.lisp index 74fbeaa..0cec79a 100644 --- a/lisp/atlantis.lisp +++ b/lisp/atlantis.lisp @@ -11,7 +11,7 @@ (load 'util.lisp) (load 'interpreter.lisp) -;(load 'client.lisp) +(load 'client.lisp) (defun start-server () @@ -26,17 +26,18 @@ (defun join-game () "Join a running game on the server" - (format t "~&What is the IP address of the server you want to join?") - (input-string ip) - (while (not (= (count-instances #\. (to-list ip)) 3)) - (format t "~&Not an IP address: ~A. Please reenter:" ip) - (input-string ip)) - (format t "~&What port does the game run on?") - (while (not (numberp (input port))) - (format t "~&Not a number: ~A. Please reenter:" port)) + ;; XXX while developing... + ;; (format t "~&What is the IP address of the server you want to join?") + ;; (input-string ip) + ;; (while (not (= (count-instances #\. (to-list ip)) 3)) + ;; (format t "~&Not an IP address: ~A. Please reenter:" ip) + ;; (input-string ip)) + ;; (format t "~&What port does the game run on?") + ;; (while (not (numberp (input port))) + ;; (format t "~&Not a number: ~A. Please reenter:" port)) (format t "~&What is your player name?") (input-string name) - (format t "~&Joining game on ~A:~A as ~A" ip port name) + ;; (format t "~&Joining game on ~A:~A as ~A" ip port name) (play-game name)) @@ -54,7 +55,6 @@ (defun start-menu () "Show the start menu and take a choice from the user" -; (let ((logo (load-text-file "banner.txt"))) (dolist (line (load-text-file "banner.txt")) (unless (null line) (format t "~%~A" line))) (format t "~&~%Welcome! What do you want to do?") diff --git a/lisp/atlantis.lisp b/lisp/atlantis.lisp index 74fbeaa..0cec79a 100644 --- a/lisp/atlantis.lisp +++ b/lisp/atlantis.lisp @@ -11,7 +11,7 @@ (load 'util.lisp) (load 'interpreter.lisp) -;(load 'client.lisp) +(load 'client.lisp) (defun start-server () @@ -26,17 +26,18 @@ (defun join-game () "Join a running game on the server" - (format t "~&What is the IP address of the server you want to join?") - (input-string ip) - (while (not (= (count-instances #\. (to-list ip)) 3)) - (format t "~&Not an IP address: ~A. Please reenter:" ip) - (input-string ip)) - (format t "~&What port does the game run on?") - (while (not (numberp (input port))) - (format t "~&Not a number: ~A. Please reenter:" port)) + ;; XXX while developing... + ;; (format t "~&What is the IP address of the server you want to join?") + ;; (input-string ip) + ;; (while (not (= (count-instances #\. (to-list ip)) 3)) + ;; (format t "~&Not an IP address: ~A. Please reenter:" ip) + ;; (input-string ip)) + ;; (format t "~&What port does the game run on?") + ;; (while (not (numberp (input port))) + ;; (format t "~&Not a number: ~A. Please reenter:" port)) (format t "~&What is your player name?") (input-string name) - (format t "~&Joining game on ~A:~A as ~A" ip port name) + ;; (format t "~&Joining game on ~A:~A as ~A" ip port name) (play-game name)) @@ -54,7 +55,6 @@ (defun start-menu () "Show the start menu and take a choice from the user" -; (let ((logo (load-text-file "banner.txt"))) (dolist (line (load-text-file "banner.txt")) (unless (null line) (format t "~%~A" line))) (format t "~&~%Welcome! What do you want to do?") diff --git a/lisp/client.lisp b/lisp/client.lisp index 3e56313..11bddd7 100644 --- a/lisp/client.lisp +++ b/lisp/client.lisp @@ -8,12 +8,15 @@ ;;; ;;; Licensed under the terms of the MIT license. ;;; author: Daniel Vedder -;;; date: 09/05/2015 +;;; date: 21/05/2015 ;;; (let ((player NIL)) (defun play-game (&optional player-name) "The main game loop" + ;; XXX Development + (when (y-or-n-p "~&Load the test world?") + (load-file "../ATL/lisp-test.atl")) ;; Initialize the player if necessary (when (null player) (if player-name @@ -24,8 +27,65 @@ (defun create-player (player-name) "The user creates a new player" - (let ((race NIL) (class NIL) + ;; This function feels somewhat inelegant - lot's of repetetive stuff. + ;; Is it worth cleaning up? + (let ((player (make-player :name player-name)) + (race NIL) (character-class NIL) (strength 0) (dexterity 0) (constitution 0) (intelligence 0) - (items NIL) (weapons NIL) (character-points NIL)) - )) ;; TODO + (items NIL) (weapons NIL) + (character-attributes '(strength dexterity + constitution intelligence)) + (character-points NIL)) + (format t "~&The name you have chosen is not registered on this game.") + (unless (y-or-n-p "~&Create a new player?") (start-menu)) + ;; Chose race and class + (format t "~&Please chose a race:") + (format t "~&Options: ~A" (string-from-list (list-objects 'race) " - ")) + (setf race (input-string)) + (while (not (member race (list-objects 'race) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf race (input-string))) + (setf race (get-game-object 'race race)) + (format t "~&Please chose a class:") + (format t "~&Options: ~A" (string-from-list + (list-objects 'character-class) " - ")) + (setf character-class (input-string)) + (while (not (member character-class + (list-objects 'character-class) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf character-class (input-string))) + (setf character-class + (get-game-object 'character-class character-class)) + ;; Set character attributes + (while (< (reduce #'+ character-points) 24) ; Warning: magic number! + (set-list (random 20) a b c d) + (setf character-points (list a b c d))) + (setf text " +Now distribute your attribute points. Random numbers have been chosen, +you may assign one number to each of the following attributes:") + (format t "~&~A~%~A~%~%The numbers are: ~%~A" + text (string-from-list character-attributes " - ") + (string-from-list character-points " - ")) + ;; FIXME Rewrite this section ? >>> + (dolist (attr character-attributes) + (simple-input (symbol-value attr) + (concatenate 'string (string-downcase (symbol-name attr)) ":")) + ;(break) + (while (not (member attr character-points)) + (format t "~&Sorry, invalid number chosen. Please reenter:") + (simple-input attr + (concatenate 'string + (string-downcase (symbol-name attr)) ":"))) + (setf character-points + (remove-if #'(lambda (x) + (= x (symbol-value attr))) + character-points))) + ;; Update the player + (setf (player-race player) race) + (setf (player-class player) character-class) + (setf (player-strength player) strength) + (setf (player-constitution player) constitution) + (setf (player-dexterity player) dexterity) + (setf (player-intelligence player) intelligence) + player)) diff --git a/lisp/atlantis.lisp b/lisp/atlantis.lisp index 74fbeaa..0cec79a 100644 --- a/lisp/atlantis.lisp +++ b/lisp/atlantis.lisp @@ -11,7 +11,7 @@ (load 'util.lisp) (load 'interpreter.lisp) -;(load 'client.lisp) +(load 'client.lisp) (defun start-server () @@ -26,17 +26,18 @@ (defun join-game () "Join a running game on the server" - (format t "~&What is the IP address of the server you want to join?") - (input-string ip) - (while (not (= (count-instances #\. (to-list ip)) 3)) - (format t "~&Not an IP address: ~A. Please reenter:" ip) - (input-string ip)) - (format t "~&What port does the game run on?") - (while (not (numberp (input port))) - (format t "~&Not a number: ~A. Please reenter:" port)) + ;; XXX while developing... + ;; (format t "~&What is the IP address of the server you want to join?") + ;; (input-string ip) + ;; (while (not (= (count-instances #\. (to-list ip)) 3)) + ;; (format t "~&Not an IP address: ~A. Please reenter:" ip) + ;; (input-string ip)) + ;; (format t "~&What port does the game run on?") + ;; (while (not (numberp (input port))) + ;; (format t "~&Not a number: ~A. Please reenter:" port)) (format t "~&What is your player name?") (input-string name) - (format t "~&Joining game on ~A:~A as ~A" ip port name) + ;; (format t "~&Joining game on ~A:~A as ~A" ip port name) (play-game name)) @@ -54,7 +55,6 @@ (defun start-menu () "Show the start menu and take a choice from the user" -; (let ((logo (load-text-file "banner.txt"))) (dolist (line (load-text-file "banner.txt")) (unless (null line) (format t "~%~A" line))) (format t "~&~%Welcome! What do you want to do?") diff --git a/lisp/client.lisp b/lisp/client.lisp index 3e56313..11bddd7 100644 --- a/lisp/client.lisp +++ b/lisp/client.lisp @@ -8,12 +8,15 @@ ;;; ;;; Licensed under the terms of the MIT license. ;;; author: Daniel Vedder -;;; date: 09/05/2015 +;;; date: 21/05/2015 ;;; (let ((player NIL)) (defun play-game (&optional player-name) "The main game loop" + ;; XXX Development + (when (y-or-n-p "~&Load the test world?") + (load-file "../ATL/lisp-test.atl")) ;; Initialize the player if necessary (when (null player) (if player-name @@ -24,8 +27,65 @@ (defun create-player (player-name) "The user creates a new player" - (let ((race NIL) (class NIL) + ;; This function feels somewhat inelegant - lot's of repetetive stuff. + ;; Is it worth cleaning up? + (let ((player (make-player :name player-name)) + (race NIL) (character-class NIL) (strength 0) (dexterity 0) (constitution 0) (intelligence 0) - (items NIL) (weapons NIL) (character-points NIL)) - )) ;; TODO + (items NIL) (weapons NIL) + (character-attributes '(strength dexterity + constitution intelligence)) + (character-points NIL)) + (format t "~&The name you have chosen is not registered on this game.") + (unless (y-or-n-p "~&Create a new player?") (start-menu)) + ;; Chose race and class + (format t "~&Please chose a race:") + (format t "~&Options: ~A" (string-from-list (list-objects 'race) " - ")) + (setf race (input-string)) + (while (not (member race (list-objects 'race) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf race (input-string))) + (setf race (get-game-object 'race race)) + (format t "~&Please chose a class:") + (format t "~&Options: ~A" (string-from-list + (list-objects 'character-class) " - ")) + (setf character-class (input-string)) + (while (not (member character-class + (list-objects 'character-class) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf character-class (input-string))) + (setf character-class + (get-game-object 'character-class character-class)) + ;; Set character attributes + (while (< (reduce #'+ character-points) 24) ; Warning: magic number! + (set-list (random 20) a b c d) + (setf character-points (list a b c d))) + (setf text " +Now distribute your attribute points. Random numbers have been chosen, +you may assign one number to each of the following attributes:") + (format t "~&~A~%~A~%~%The numbers are: ~%~A" + text (string-from-list character-attributes " - ") + (string-from-list character-points " - ")) + ;; FIXME Rewrite this section ? >>> + (dolist (attr character-attributes) + (simple-input (symbol-value attr) + (concatenate 'string (string-downcase (symbol-name attr)) ":")) + ;(break) + (while (not (member attr character-points)) + (format t "~&Sorry, invalid number chosen. Please reenter:") + (simple-input attr + (concatenate 'string + (string-downcase (symbol-name attr)) ":"))) + (setf character-points + (remove-if #'(lambda (x) + (= x (symbol-value attr))) + character-points))) + ;; Update the player + (setf (player-race player) race) + (setf (player-class player) character-class) + (setf (player-strength player) strength) + (setf (player-constitution player) constitution) + (setf (player-dexterity player) dexterity) + (setf (player-intelligence player) intelligence) + player)) diff --git a/lisp/interpreter.lisp b/lisp/interpreter.lisp index 2c5b87d..22c1c37 100644 --- a/lisp/interpreter.lisp +++ b/lisp/interpreter.lisp @@ -76,14 +76,14 @@ ;; this is a kludge to work around a clisp bug (not ;; recognizing the :start keyword in read-from-string) (read-from-string (second - (cut-string line (find-char #\space line))))))) + (cut-string line (position #\space line))))))) ;; interpret an option command ((or (eql (aref line 0) #\Space) (eql (aref line 0) #\Tab)) (setf line (string-left-trim '(#\Space #\Tab) line)) (set-object-attribute current-object (read-from-string line) (read-from-string - (second (cut-string line (find-char #\space line)))))) + (second (cut-string line (position #\space line)))))) (T (format t "~&ERROR: unrecognized syntax on line ~A: '~A'" ;; can't happen (1+ line-nr) line)))))) diff --git a/lisp/atlantis.lisp b/lisp/atlantis.lisp index 74fbeaa..0cec79a 100644 --- a/lisp/atlantis.lisp +++ b/lisp/atlantis.lisp @@ -11,7 +11,7 @@ (load 'util.lisp) (load 'interpreter.lisp) -;(load 'client.lisp) +(load 'client.lisp) (defun start-server () @@ -26,17 +26,18 @@ (defun join-game () "Join a running game on the server" - (format t "~&What is the IP address of the server you want to join?") - (input-string ip) - (while (not (= (count-instances #\. (to-list ip)) 3)) - (format t "~&Not an IP address: ~A. Please reenter:" ip) - (input-string ip)) - (format t "~&What port does the game run on?") - (while (not (numberp (input port))) - (format t "~&Not a number: ~A. Please reenter:" port)) + ;; XXX while developing... + ;; (format t "~&What is the IP address of the server you want to join?") + ;; (input-string ip) + ;; (while (not (= (count-instances #\. (to-list ip)) 3)) + ;; (format t "~&Not an IP address: ~A. Please reenter:" ip) + ;; (input-string ip)) + ;; (format t "~&What port does the game run on?") + ;; (while (not (numberp (input port))) + ;; (format t "~&Not a number: ~A. Please reenter:" port)) (format t "~&What is your player name?") (input-string name) - (format t "~&Joining game on ~A:~A as ~A" ip port name) + ;; (format t "~&Joining game on ~A:~A as ~A" ip port name) (play-game name)) @@ -54,7 +55,6 @@ (defun start-menu () "Show the start menu and take a choice from the user" -; (let ((logo (load-text-file "banner.txt"))) (dolist (line (load-text-file "banner.txt")) (unless (null line) (format t "~%~A" line))) (format t "~&~%Welcome! What do you want to do?") diff --git a/lisp/client.lisp b/lisp/client.lisp index 3e56313..11bddd7 100644 --- a/lisp/client.lisp +++ b/lisp/client.lisp @@ -8,12 +8,15 @@ ;;; ;;; Licensed under the terms of the MIT license. ;;; author: Daniel Vedder -;;; date: 09/05/2015 +;;; date: 21/05/2015 ;;; (let ((player NIL)) (defun play-game (&optional player-name) "The main game loop" + ;; XXX Development + (when (y-or-n-p "~&Load the test world?") + (load-file "../ATL/lisp-test.atl")) ;; Initialize the player if necessary (when (null player) (if player-name @@ -24,8 +27,65 @@ (defun create-player (player-name) "The user creates a new player" - (let ((race NIL) (class NIL) + ;; This function feels somewhat inelegant - lot's of repetetive stuff. + ;; Is it worth cleaning up? + (let ((player (make-player :name player-name)) + (race NIL) (character-class NIL) (strength 0) (dexterity 0) (constitution 0) (intelligence 0) - (items NIL) (weapons NIL) (character-points NIL)) - )) ;; TODO + (items NIL) (weapons NIL) + (character-attributes '(strength dexterity + constitution intelligence)) + (character-points NIL)) + (format t "~&The name you have chosen is not registered on this game.") + (unless (y-or-n-p "~&Create a new player?") (start-menu)) + ;; Chose race and class + (format t "~&Please chose a race:") + (format t "~&Options: ~A" (string-from-list (list-objects 'race) " - ")) + (setf race (input-string)) + (while (not (member race (list-objects 'race) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf race (input-string))) + (setf race (get-game-object 'race race)) + (format t "~&Please chose a class:") + (format t "~&Options: ~A" (string-from-list + (list-objects 'character-class) " - ")) + (setf character-class (input-string)) + (while (not (member character-class + (list-objects 'character-class) :test #'equalp)) + (format t "~&Invalid choice. Please reenter:") + (setf character-class (input-string))) + (setf character-class + (get-game-object 'character-class character-class)) + ;; Set character attributes + (while (< (reduce #'+ character-points) 24) ; Warning: magic number! + (set-list (random 20) a b c d) + (setf character-points (list a b c d))) + (setf text " +Now distribute your attribute points. Random numbers have been chosen, +you may assign one number to each of the following attributes:") + (format t "~&~A~%~A~%~%The numbers are: ~%~A" + text (string-from-list character-attributes " - ") + (string-from-list character-points " - ")) + ;; FIXME Rewrite this section ? >>> + (dolist (attr character-attributes) + (simple-input (symbol-value attr) + (concatenate 'string (string-downcase (symbol-name attr)) ":")) + ;(break) + (while (not (member attr character-points)) + (format t "~&Sorry, invalid number chosen. Please reenter:") + (simple-input attr + (concatenate 'string + (string-downcase (symbol-name attr)) ":"))) + (setf character-points + (remove-if #'(lambda (x) + (= x (symbol-value attr))) + character-points))) + ;; Update the player + (setf (player-race player) race) + (setf (player-class player) character-class) + (setf (player-strength player) strength) + (setf (player-constitution player) constitution) + (setf (player-dexterity player) dexterity) + (setf (player-intelligence player) intelligence) + player)) diff --git a/lisp/interpreter.lisp b/lisp/interpreter.lisp index 2c5b87d..22c1c37 100644 --- a/lisp/interpreter.lisp +++ b/lisp/interpreter.lisp @@ -76,14 +76,14 @@ ;; this is a kludge to work around a clisp bug (not ;; recognizing the :start keyword in read-from-string) (read-from-string (second - (cut-string line (find-char #\space line))))))) + (cut-string line (position #\space line))))))) ;; interpret an option command ((or (eql (aref line 0) #\Space) (eql (aref line 0) #\Tab)) (setf line (string-left-trim '(#\Space #\Tab) line)) (set-object-attribute current-object (read-from-string line) (read-from-string - (second (cut-string line (find-char #\space line)))))) + (second (cut-string line (position #\space line)))))) (T (format t "~&ERROR: unrecognized syntax on line ~A: '~A'" ;; can't happen (1+ line-nr) line)))))) diff --git a/lisp/util.lisp b/lisp/util.lisp index 03f8092..c7721eb 100644 --- a/lisp/util.lisp +++ b/lisp/util.lisp @@ -44,7 +44,7 @@ (magic (first (list ,@vars))) (first (list ,@vars)))) -(defmacro input-string (var) +(defmacro input-string (&optional (var (gensym))) "Read a string input line" `(progn (format t "~&>>> ") @@ -52,12 +52,6 @@ (magic (read-from-string ,var)) ,var)) -(defmacro simple-input (var &optional (prompt ">>>")) - "Take input from terminal and store it in var" - `(progn - (format t "~&~A " ,prompt) - (setf ,var (read)))) - (defmacro while (condition &body body) "An implementation of a while loop as found in other languages" `(do () @@ -96,27 +90,39 @@ ; Some of these functions are probably quite inefficient (lots of consing) +(defun simple-input (var &optional (prompt ">>>")) + "Take input from terminal and store it in var" + (format t "~&~A " prompt) + (setf var (read))) + +(defun string-from-list (lst &optional (separator " ")) + "Put all elements of lst into a single string, separated by the separator" + (let ((str (to-string (first lst)))) + (dolist (item (cdr lst) str) + (setf str (concatenate 'string str separator (to-string item)))))) + (defun cut-string (s i) "Cut string s in two at index i and return the two substrings in a list" (do* ((c 0 (1+ c)) (letter (aref s c) (aref s c)) (letter-list-1 NIL) (letter-list-2 NIL)) ((= c (1- (length s))) - (list (to-string (append letter-list-1)) - (to-string (append letter-list-2 (list letter))))) + (list (list-to-string (append letter-list-1)) + (list-to-string (append letter-list-2 (list letter))))) (if (< c i) (setf letter-list-1 (append letter-list-1 (list letter))) (setf letter-list-2 (append letter-list-2 (list letter)))))) -(defun to-string (char-list) +(defun list-to-string (char-list) "Convert a character list to a string" (let ((s (make-string (length char-list) :initial-element #\SPACE))) (dotimes (i (length char-list) s) (setf (aref s i) (nth i char-list))))) -(defun find-char (c s) - "Find character c in string s and return the index (or NIL if non-existent)" - (dotimes (letter (length s) NIL) - (when (eql (char s letter) c) (return letter)))) +(defun to-string (x) + "Whatever x is, convert it into a string" + (if (or (stringp x) (symbolp x)) (string x) + (format NIL "~S" x))) +;; The next two functions might be simplified into one using the elt function (defun count-instances (search-term search-list &key (test #'eql)) "Count the number of instances of search-term in search-list" (let ((count 0))