Skip to content

Instantly share code, notes, and snippets.

@schmalz
Created January 10, 2018 09:34
Show Gist options
  • Save schmalz/53dc9413ccdc10394f83a354149145fb to your computer and use it in GitHub Desktop.
Save schmalz/53dc9413ccdc10394f83a354149145fb to your computer and use it in GitHub Desktop.
Land of Lisp: Orc Battle
(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