Created
January 10, 2018 09:34
-
-
Save schmalz/53dc9413ccdc10394f83a354149145fb to your computer and use it in GitHub Desktop.
Land of Lisp: Orc Battle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defparameter *player-health* NIL) | |
(defparameter *player-agility* NIL) | |
(defparameter *player-strength* NIL) | |
(defparameter *monsters* NIL) | |
(defparameter *monster-builders* NIL) | |
(defparameter *monster-count* 12) | |
(defun randval (n) | |
"A random number between one and `N`. The number returned is guaranteed to be greater than or equal to one." | |
(1+ (random (max 1 n)))) | |
;; Monsters. | |
(defstruct monster (health (randval 10))) | |
(defstruct (orc (:include monster)) (club-level (randval 8))) | |
(defstruct (hydra (:include monster))) | |
(defstruct (slime-mould (:include monster)) (sliminess (randval 5))) | |
(defstruct (brigand (:include monster))) | |
;; Monster builders. | |
(push #'make-orc *monster-builders*) | |
(push #'make-hydra *monster-builders*) | |
(push #'make-slime-mould *monster-builders*) | |
(push #'make-brigand *monster-builders*) | |
;; Show me the monsters. | |
(defmethod monster-show (m) | |
(princ "A fierce ") | |
(princ (type-of m))) | |
(defmethod monster-show ((m orc)) | |
(princ "A wicked orc with a level ") | |
(princ (orc-club-level m)) | |
(princ " club.")) | |
(defmethod monster-show ((m hydra)) | |
(princ "A malicious hydra with ") | |
(princ (monster-health m)) | |
(princ " heads. ")) | |
(defmethod monster-show ((m slime-mould)) | |
(princ "A slime mould with a sliminess of ") | |
(princ (slime-mould-sliminess m))) | |
;; When monsters attack. | |
(defmethod monster-attack (m)) | |
(defmethod monster-attack ((m orc)) | |
(let ((x (randval (orc-club-level m)))) | |
(princ "An orc swing his club at you and knocks off ") | |
(princ x) | |
(princ "of your health points. ") | |
(decf *player-health* x))) | |
(defmethod monster-attack ((m hydra)) | |
(let ((x (randval (ash (monster-health m) -1)))) | |
(princ "A hydra attacks you with ") | |
(princ x) | |
(princ " of its heads! It also grows one more head! ") | |
(incf (monster-health m)) | |
(decf *player-health* x))) | |
(defmethod monster-attack ((m slime-mould)) | |
(let ((x (randval (slime-mould-sliminess m)))) | |
(princ "A slime mould wraps around your legs and decreases your agility by ") | |
(princ x) | |
(princ "! ") | |
(decf *player-agility* x) | |
(when (zerop (random 2)) | |
(princ "It also squirts in your face, taking away a health point! ") | |
(decf *player-health*)))) | |
(defmethod monster-attack ((m brigand)) | |
(let ((x (max *player-health* *player-agility* *player-strength*))) | |
(cond ((= x *player-health*) | |
(princ "A brigand hits you with his slingshot, taking off two health points! ") | |
(decf *player-health* 2)) | |
((= x *player-agility*) | |
(princ "A brigand catches your leg with his whip, taking off two agility points! ") | |
(decf *player-agility* 2)) | |
((= x *player-strength*) | |
(princ "A brigand cuts your arm with his whip, taking off two strength points! ") | |
(decf *player-strength* 2))))) | |
;; Hit back at the monsters. | |
(defmethod monster-hit (m x) | |
(decf (monster-health m) x) | |
(if (monster-dead m) | |
(progn (princ "You killed the ") | |
(princ (type-of m)) | |
(princ "! ")) | |
(progn (princ "You hit the ") | |
(princ (type-of m)) | |
(princ ", knocking off ") | |
(princ x) | |
(princ " health points ")))) | |
(defmethod monster-hit ((m hydra) x) | |
(decf (monster-health m) x) | |
(if (monster-dead m) | |
(princ "The corpse of the fully decapitated hydra falls to the floor!") | |
(progn (princ "You lop off ") | |
(princ x) | |
(princ " of the hydra's heads!")))) | |
;; Player. | |
(defun init-player () | |
(setf *player-health* 30) | |
(setf *player-agility* 30) | |
(setf *player-strength* 30)) | |
(defun player-dead () | |
(<= *player-health* 0)) | |
(defun show-player () | |
(fresh-line) | |
(princ "You are a valiant knight with a health of ") | |
(princ *player-health*) | |
(princ ", an agility of ") | |
(princ *player-agility*) | |
(princ " and a strength of ") | |
(princ *player-strength*)) | |
(defun init-monsters () | |
(setf *monsters* | |
(map 'vector | |
(lambda (x) | |
(declare (ignore x)) | |
(funcall (nth (random (length *monster-builders*)) *monster-builders*))) | |
(make-array *monster-count*)))) | |
(defun monster-dead (m) | |
(<= (monster-health m) 0)) | |
(defun monsters-dead () | |
(every #'monster-dead *monsters*)) | |
(defun show-monsters () | |
(fresh-line) | |
(princ "Yours foes:") | |
(let ((x 0)) | |
(map 'list | |
(lambda (m) | |
(fresh-line) | |
(princ " ") | |
(princ (incf x)) | |
(princ ". ") | |
(if (monster-dead m) | |
(princ "** dead **") | |
(progn (princ "Health ") | |
(princ (monster-health m)) | |
(princ ". ") | |
(monster-show m)))) | |
*monsters*))) | |
(defun random-monster () | |
(let ((m (aref *monsters* (random (length *monsters*))))) | |
(if (monster-dead m) | |
(random-monster) | |
m))) | |
(defun pick-monster () | |
(fresh-line) | |
(princ "Monster #: ") | |
(let ((x (read))) | |
(if (not (and (integerp x) (<= 1 x *monster-count*))) | |
(progn (princ "That is not a valid monster number.") | |
(pick-monster)) | |
(let ((m (aref *monsters* (1- x)))) | |
(if (monster-dead m) | |
(progn (princ "That monster is already dead.") | |
(pick-monster)) | |
m))))) | |
(defun player-attack () | |
(fresh-line) | |
(princ "Attack style: [s]tab [d]ouble swing [r]oundhouse: ") | |
(case (read) | |
(s (monster-hit (pick-monster) (+ 2 (randval (ash *player-strength* -1))))) | |
(d (let ((x (randval (truncate (/ *player-strength* 6))))) | |
(princ "Your double swing has a strength of ") | |
(princ x) | |
(fresh-line) | |
(monster-hit (pick-monster) x) | |
(unless (monsters-dead) | |
(monster-hit (pick-monster) x)))) | |
(otherwise (dotimes (x (1+ (randval (truncate (/ *player-strength* 3))))) | |
(unless (monsters-dead) | |
(monster-hit (random-monster) 1)))))) | |
(defun game-loop () | |
"The main game loop. Continually calls itself until either the player or all the monsters are dead." | |
(unless (or (player-dead) (monsters-dead)) | |
(show-player) | |
(dotimes (k (1+ (truncate (/ (max 0 *player-agility*) 15)))) | |
(unless (monsters-dead) | |
(show-monsters) | |
(player-attack))) | |
(fresh-line) | |
(map 'list | |
(lambda (m) | |
(or (monster-dead m) (monster-attack m))) | |
*monsters*) | |
(game-loop))) | |
(defun orc-battle () | |
"Start a new game of Orc Battle." | |
(init-monsters) | |
(init-player) | |
(game-loop) | |
(when (player-dead) | |
(princ "You have been killed. Game Over!")) | |
(when (monsters-dead) | |
(princ "Congratulations! You have vanquished all your foes."))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment