Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (defun inventory-menu (header)
- "Show a menu with each item of the inventory as an option."
- (let* ((items (loop for item in *inventory*
- ;; show additional information, in case it's equipped
- if (and (typep item 'equipment) (is-equipped item))
- collect (format nil "~a (on ~(~a~))" (name item) (equip-slot item))
- else collect (name item)))
- (options (if (zerop (length *inventory*))
- (list "Inventory is empty.")
- items))
- (index (menu header options *inventory-width*)))
- ;; if an item was chosen, return it
- (if (or (not index) (zerop (length *inventory*)))
- nil
- (nth index *inventory*))))
- (defun make-rect (x y w h)
- (let ((r (make-instance 'rect :x1 x :y1 y)))
- (setf (x2 r) (+ (x1 r) width)
- (y2 r) (+ (y1 r) height)
- (center r) (cons (floor (/ (+ (x1 r) (x2 r)) 2)) (floor (/ (+ (y1 r) (y2 r)) 2))))
- rect))
- (defun place-objects (room)
- ;; this is where we decide the chance of each monster or item appearing.
- ;; maximum number of monsters per room
- (let ((objects '())
- (max-monsters (from-dungeon-level '((2 . 1) (3 . 4) (5 . 6))))
- ;; chance of each monster
- ;; orc always shows up, even if all other monsters have 0 chance
- (monster-chances `((:orc . 80)
- (:troll . ,(from-dungeon-level '(( 15 . 3) (30 . 5) (60 . 7)))))))
- ;; choose random number of monsters
- (dotimes (i (tcod:random-get-int tcod:+null+ 0 max-monsters))
- ;; choose random spot for this monster
- (let ((x (tcod:random-get-int tcod:+null+ (+ (x1 room) 1) (- (x2 room) 1)))
- (y (tcod:random-get-int tcod:+null+ (+ (y1 room) 1) (- (y2 room) 1))))
- (unless (is-blocked x y)
- (let ((monster
- (case (random-choice monster-chances)
- (:orc (make-instance 'basic-fighter-monster
- :x x :y y :cha #\o :name "orc" :color :pale-green
- :blocks t :max-hp 20 :defense 0 :power 4 :xp 35
- :death-fun #'monster-death))
- (:troll (make-instance 'basic-fighter-monster
- :x x :y y :cha #\T :name "troll"
- :color :dark-sea-green :blocks t :max-hp 30
- :defense 2 :power 8 :xp 100
- :death-fun #'monster-death)))))
- (push monster objects))))))
- ;; maximum number of items per room
- (let ((max-items (from-dungeon-level '((1 . 1) (2 . 4))))
- ;; chance of each item (be default they have a chance of 0 at level 1,
- ;; which then goes up
- ;; healing potion always shows up, even if all other items have 0 chance
- (item-chances `((:heal . 35)
- (:lightning . ,(from-dungeon-level '((25 . 4))))
- (:fireball . ,(from-dungeon-level '((25 . 6))))
- (:confuse . ,(from-dungeon-level '((10 . 2))))
- (:sword . ,(from-dungeon-level '((5 . 4))))
- (:shield . ,(from-dungeon-level '((15 . 8))))))
- (item-stats (list (list :heal :cha #\!
- :name "healing potion"
- :use-function #'cast-heal
- :color :purple
- :always-visible t)
- (list :lightning :cha #\#
- :name "scroll of lightning bolt"
- :use-function #'cast-lightning
- :color :light-yellow
- :always-visible t)
- (list :fireball :cha #\#
- :name "scroll of fireball"
- :use-function #'cast-fireball
- :color :light-yellow
- :always-visible t)
- (list :confuse :cha #\#
- :name "scroll of confusion"
- :use-function #'cast-confuse
- :color :light-yellow
- :always-visible t)
- (list :sword :cha #\/
- :name "sword"
- :equip-slot :right-hand
- :power-bonus 3
- :color :blue
- :always-visible t)
- (list :shield :cha #\[
- :name "shield"
- :equip-slot :left-hand
- :defense-bonus 1
- :color :orange
- :always-visible t))))
- ;; items appear below other objects
- (loop for i below (tcod:random-get-int tcod:+null+ 0 max-items) ; choose random number of items
- ;; choose random spot for this item
- for x = (tcod:random-get-int tcod:+null+
- (+ (x1 room) 1) (- (x2 room) 1))
- for y = (tcod:random-get-int tcod:+null+
- (+ (y1 room) 1) (- (y2 room) 1))
- for choice = (random-choice item-chances)
- ;; only place it if the tile is not blocked
- unless (is-blocked x y)
- do (push (apply #'make-item x y (cdr (assoc choice item-stats)))
- objects))
- (setf *objects* (append (nreverse objects) *objects*))))
- (defun make-map ()
- ;; the list of objects with just the player
- (setf *objects* (list *player*))
- (setf *map* (make-array (list *map-height* *map-width*)))
- (dotimes (i *map-height*)
- (dotimes (j *map-width*)
- (setf (aref *map* i j) (make-instance 'tile :blocked t))))
- (let ((rooms (list (make-rect x y w h))))
- (create-room (first rooms))
- (destructuring-bind (new-x . new-y) (center (first rooms))
- (setf (x *player*) new-x
- (y *player*) new-y))
- (loop repeat *max-rooms* do
- ;; random width and height
- (let* ((w (tcod:random-get-int tcod:+null+ *room-min-size* *room-max-size*))
- (h (tcod:random-get-int tcod:+null+ *room-min-size* *room-max-size*))
- ;; random position without going out of the boundaries of the map
- (x (tcod:random-get-int tcod:+null+ 0 (- *map-width* w 1)))
- (y (tcod:random-get-int tcod:+null+ 0 (- *map-height* h 1)))
- (new-room (make-rect x y w h)))
- ;; run through the other rooms and see if they intersect with this one
- (unless (some (lambda (r) (intersect new-room r))
- rooms)
- ;; this means there are no intersections, so this room is valid
- (create-room new-room) ; "paint" it to the map's tiles
- ;; connect it to the previous room with a tunnel
- (destructuring-bind (new-x . new-y) (center new-room)
- (destructuring-bind (prev-x . prev-y) (center (first rooms))
- ;; draw a coin (random number that is either 0 or 1)
- (if (plusp (tcod:random-get-int tcod:+null+ 0 1))
- (progn ; first move horizontally, then vertically
- (create-h-tunnel prev-x new-x prev-y)
- (create-v-tunnel prev-y new-y new-x))
- (progn ; first move vertically, then horizontally
- (create-v-tunnel prev-y new-y prev-x)
- (create-h-tunnel prev-x new-x new-y)))))
- ;; add some contents to this room, such as monsters
- (place-objects new-room)
- ;; finally, add the new room to the list
- (push new-room rooms))))
- ;; create stairs at the center of the last room
- (destructuring-bind (new-x . new-y) (center (first rooms))
- (setf *stairs* (make-instance 'object :x new-x :y new-y :cha #\>
- :name "stairs" :color :white
- :always-visible t))
- (push *stairs* *objects*))))
Advertisement
Add Comment
Please, Sign In to add comment