For the lisp game jam http://itch.io/jam/january-2016-lisp-game-jam. Also practice for my future forever project game (not yet named). This is a roguelike where you play a necromancer able to summon skeletons and any other powers I have time for.

crypts-and-corpses.lisp 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. ;;;; crypts-and-corpses.lisp
  2. (in-package #:crypts-and-corpses)
  3. (defstruct game-map
  4. (width 100 :type fixnum :read-only t)
  5. (height 40 :type fixnum :read-only t)
  6. (mobiles (make-hash-table) :type hash-table :read-only t))
  7. (defclass entity ()
  8. ((location :initarg :location :initform 0 :type fixnum)))
  9. (defclass tile-entity (entity)
  10. ((codepoint :initarg :codepoint :initform #x3f :type fixnum)))
  11. (defclass viewport (entity)
  12. ((width :initarg :width :type fixnum :initform 100)
  13. (height :initarg :height :type fixnum :initform 40)
  14. (location :initarg :location :type fixnum :initform 0)))
  15. (defclass mobile (tile-entity)
  16. ((health :initarg :health :type fixnum)
  17. (mana :initarg :mana :type fixnum)
  18. (health-regen :initarg :health-regen :initform 0 :type fixnum)
  19. (mana-regen :initarg :mana-regen :initform 0 :type fixnum)))
  20. (defclass player-character (mobile)
  21. ((ranged-attack-damage :initarg :ranged-attack-damage :initform 5 :type fixnum)
  22. (ranged-attack-cost :initarg :ranged-attack-cost :initform 5 :type fixnum)))
  23. (defclass enemy (mobile) ())
  24. (defclass minion (mobile) ())
  25. (defun calc-coord (location map)
  26. (values (mod location (game-map-width map)) (floor (/ location (game-map-width map)))))
  27. (defun get-window-size ()
  28. (apply 'values (mapcar #'parse-integer (split-sequence #\x (terminal-get "window.size" "0x0")))))
  29. ;; DEPRECATED until I find a use for it
  30. ;; (defun calc-location (x y map)
  31. ;; (+ (* (game-map-width map) (cdr y)) (car x)))
  32. ;; (defgeneric set-location (object x y))
  33. ;; (defmethod set-location ((object tile-entity) x y)
  34. ;; (setf (slot-value object 'location) (calc-location x y)))
  35. (defgeneric end-of-turn (object))
  36. (defmethod end-of-turn ((object mobile))
  37. (incf (slot-value object 'health) (slot-value object 'health-regen))
  38. (incf (slot-value object 'mana) (slot-value object 'mana-regen)))
  39. (defgeneric move-left (object map))
  40. (defgeneric move-right (object map))
  41. (defgeneric move-up (object map))
  42. (defgeneric move-down (object map))
  43. (defgeneric update-location (object map old-locaiton new-location))
  44. (defmethod update-location ((object entity) map old-location new-location)
  45. (declare (ignore old-location))
  46. (unless (out-of-bounds-p new-location map)
  47. (setf (slot-value object 'location) new-location)))
  48. (defmethod update-location ((object mobile) map old-location new-location)
  49. (unless (out-of-bounds-p new-location map)
  50. (setf (slot-value object 'location) new-location)
  51. (setf (gethash new-location (game-map-mobiles map)) object)
  52. (remhash old-location (game-map-mobiles map))))
  53. (defun out-of-bounds-p (new-location map)
  54. (multiple-value-bind (x y) (calc-coord new-location map)
  55. (or (> 0 x)
  56. (> 0 y)
  57. (>= x (game-map-width map))
  58. (>= y (game-map-height map)))))
  59. (defmethod move-left ((object entity) map)
  60. (let ((old-location (slot-value object 'location))
  61. (new-location (1- (slot-value object 'location))))
  62. (unless (= 0 (calc-coord old-location map))
  63. (update-location object map old-location new-location))))
  64. (defmethod move-up ((object entity) map)
  65. (let ((old-location (slot-value object 'location))
  66. (new-location (- (slot-value object 'location) (game-map-width map))))
  67. (update-location object map old-location new-location)))
  68. (defmethod move-down ((object entity) map)
  69. (let ((old-location (slot-value object 'location))
  70. (new-location (+ (slot-value object 'location) (game-map-width map))))
  71. (update-location object map old-location new-location)))
  72. (defmethod move-right ((object entity) map)
  73. (let ((old-location (slot-value object 'location))
  74. (new-location (1+ (slot-value object 'location))))
  75. (unless (= 0 (calc-coord new-location map))
  76. (update-location object map old-location new-location))))
  77. (defun intro-message ()
  78. (loop as key = (terminal-read) do
  79. (multiple-value-bind (win-width win-height) (get-window-size)
  80. (terminal-print (floor (- (/ win-width 2) 10)) (floor (1- (/ win-height 2))) "Crypts and Corpses")
  81. (terminal-print (floor (- (/ win-width 2) 11)) (floor (1+ (/ win-height 2))) "Press enter to start"))
  82. (terminal-refresh)
  83. until (= key bearlibterminal-ffi:+tk-enter+)))
  84. (defun write-map-to-terminal (map viewport)
  85. (labels ((write-cell (key tile) (multiple-value-bind (x y) (calc-coord (- key (slot-value viewport 'location)) map)
  86. (terminal-put x y (slot-value tile 'codepoint)))))
  87. (maphash #'write-cell (game-map-mobiles map))))
  88. (defun initialize-map (map player)
  89. (setf (gethash (slot-value player 'location) (game-map-mobiles map)) player)
  90. map)
  91. (defun handle-input (key map viewport player)
  92. (cond
  93. ((= key bearlibterminal-ffi:+tk-up+) (move-up player map))
  94. ((= key bearlibterminal-ffi:+tk-down+) (move-down player map))
  95. ((= key bearlibterminal-ffi:+tk-right+) (move-right player map))
  96. ((= key bearlibterminal-ffi:+tk-left+) (move-left player map))
  97. ((= key bearlibterminal-ffi:+tk-w+) (move-up viewport map))
  98. ((= key bearlibterminal-ffi:+tk-a+) (move-left viewport map))
  99. ((= key bearlibterminal-ffi:+tk-d+) (move-right viewport map))
  100. ((= key bearlibterminal-ffi:+tk-s+) (move-down viewport map))))
  101. (defun create-viewport ()
  102. (multiple-value-bind (width height) (get-window-size)
  103. (make-instance 'viewport :width width :height height)))
  104. (defun main-loop ()
  105. (let ((player (make-instance
  106. 'player-character
  107. :codepoint #x263a
  108. :location 0)))
  109. (loop with map = (initialize-map (make-instance 'game-map) player)
  110. with viewport = (create-viewport)
  111. as key = (terminal-read) do
  112. (handle-input key map viewport player)
  113. (terminal-clear)
  114. (write-map-to-terminal map viewport)
  115. (terminal-refresh)
  116. until (or (= key bearlibterminal-ffi:+tk-close+)
  117. (= key bearlibterminal-ffi:+tk-escape+)))))
  118. (defun start ()
  119. (terminal-open)
  120. (terminal-set "window: size=100x40, title='Crypts and Corpses'")
  121. (terminal-set "font: ./fonts/DejaVuSansMono.ttf, size=16")
  122. (intro-message)
  123. (main-loop)
  124. (terminal-close))