Browse Source

WIP commit

Lily Carpenter 9 years ago
parent
commit
51540c5a81
1 changed files with 226 additions and 44 deletions
  1. 226 44
      src/crypts-and-corpses.lisp

+ 226 - 44
src/crypts-and-corpses.lisp

@@ -18,40 +18,54 @@
18 18
 (in-package #:crypts-and-corpses)
19 19
 
20 20
 (defstruct game-map
21
-  (width 100 :type fixnum :read-only t)
22
-  (height 40 :type fixnum :read-only t)
21
+  (width  99 :type fixnum :read-only t)
22
+  (height 39 :type fixnum :read-only t)
23 23
   (mobiles (make-hash-table) :type hash-table :read-only t))
24 24
 
25 25
 (defclass entity ()
26 26
   ((width :initarg :width :type fixnum :initform 1)
27 27
    (height :initarg :height :type fixnum :initform 1)
28
-   (location :initarg :location :initform 0 :type fixnum)))
28
+   (location :initarg :location :initform 0 :type fixnum)
29
+   (color :initarg :color :initform (color-from-name "white"))))
29 30
 
30 31
 (defclass tile-entity (entity)
31 32
   ((codepoint :initarg :codepoint :initform #x3f :type fixnum)))
32 33
 
33 34
 (defclass wall (tile-entity)
34
-  ((codepoint :initarg :codepoint :initform #x23 :type fixnum)))
35
+  ((codepoint :initarg :codepoint :initform #x23 :type fixnum)
36
+   (color :initarg :color :initform (color-from-name "grey"))))
35 37
 
36 38
 (defclass viewport (entity)
37
-  ((width :initarg :width :type fixnum :initform 100)
39
+  ((width :initarg :width :type fixnum :initform 99)
38 40
    (height :initarg :height :type fixnum :initform 40)
39 41
    (location :initarg :location :type fixnum :initform 0)))
40 42
 
41 43
 (defclass mobile (tile-entity)
42
-  ((health :initarg :health :type fixnum)
43
-   (mana :initarg :mana :type fixnum)
44
+  ((health :initarg :health :type fixnum :initform 10)
45
+   (mana :initarg :mana :type fixnum :initform 0)
46
+   (max-health :initarg :health :type fixnum :initform 10)
47
+   (max-mana :initarg :mana :type fixnum :initform 10)
44 48
    (health-regen :initarg :health-regen :initform 0 :type fixnum)
45 49
    (mana-regen :initarg :mana-regen :initform 0 :type fixnum)))
46 50
 
47 51
 (defclass player-character (mobile)
48
-  ((codepoint :initform #x263a)
52
+  ((health :initarg :health :type fixnum :initform 100)
53
+   (mana :initarg :mana :type fixnum :initform 10)
54
+   (codepoint :initform #x263a)
49 55
    (ranged-attack-damage :initarg :ranged-attack-damage :initform 5 :type fixnum)
50
-   (ranged-attack-cost :initarg :ranged-attack-cost :initform 5 :type fixnum)))
56
+   (melee-attack-damage :initarg :ranged-attack-damage :initform 2 :type fixnum)
57
+   (ranged-attack-cost :initarg :ranged-attack-cost :initform 5 :type fixnum)
58
+   (mana-regen :initarg :mana-regen :initform 3 :type fixnum)
59
+   (color :initarg :color :initform (color-from-name "green"))))
51 60
 
52
-(defclass enemy (mobile) ())
61
+(defclass enemy (mobile)
62
+  ((codepoint :initform #x263a)
63
+   (melee-attack-damage :initarg :ranged-attack-damage :initform 1 :type fixnum)
64
+   (health-regen :initarg :health-regen :initform 1 :type fixnum)
65
+   (color :initarg :color :initform (color-from-name "red"))))
53 66
 
54
-(defclass minion (mobile) ())
67
+(defclass minion (mobile)
68
+  ((color :initarg :color :initform (color-from-name "yellow"))))
55 69
 
56 70
 (defun calc-coord (location map)
57 71
   (values (mod location (game-map-width map)) (floor (/ location (game-map-width map)))))
@@ -66,12 +80,15 @@
66 80
 (defmethod set-location ((object tile-entity) x y map)
67 81
   (setf (slot-value object 'location) (calc-location x y map)))
68 82
 
69
-
70 83
 (defgeneric end-of-turn (object))
71 84
 
72 85
 (defmethod end-of-turn ((object mobile))
73 86
   (incf (slot-value object 'health) (slot-value object 'health-regen))
74
-  (incf (slot-value object 'mana) (slot-value object 'mana-regen)))
87
+  (incf (slot-value object 'mana) (slot-value object 'mana-regen))
88
+  (when (> (slot-value object 'health) (slot-value object 'max-health))
89
+    (setf (slot-value object 'health) (slot-value object 'max-health)))
90
+  (when (> (slot-value object 'mana) (slot-value object 'max-mana))
91
+    (setf (slot-value object 'mana) (slot-value object 'max-mana))))
75 92
 
76 93
 (defgeneric move-left (object map))
77 94
 (defgeneric move-right (object map))
@@ -99,11 +116,14 @@
99 116
    (1- (slot-value object 'width))
100 117
    (* (1- (slot-value object 'height)) (game-map-width map))))
101 118
 
119
+(defun collision-p (new-location map)
120
+  (gethash new-location (game-map-mobiles map)))
121
+
102 122
 (defun bad-move-p (object map old-location new-location)
103 123
   (let ((old-effective-location (calculate-effective-location object map old-location))
104 124
         (new-effective-location (calculate-effective-location object map new-location)))
105 125
     (or (out-of-bounds-p new-effective-location map)
106
-        (out-of-bounds-p new-location map)
126
+        (collision-p new-effective-location map)
107 127
         (overrun-p old-effective-location new-effective-location map))))
108 128
 
109 129
 (defmethod update-location ((object entity) map old-location new-location)
@@ -136,21 +156,130 @@
136 156
         (new-location (1+ (slot-value object 'location))))
137 157
     (update-location object map old-location new-location)))
138 158
 
159
+(defun find-mobile-left (location map)
160
+  (let ((found-object nil))
161
+    (loop for i from (1- location) downto 0 do
162
+      (setf found-object (gethash i (game-map-mobiles map)))
163
+      (when (not (typep found-object 'mobile))
164
+        (setf found-object nil))
165
+          until found-object)
166
+    found-object))
167
+
168
+(defun find-mobile-right (location map)
169
+  (let ((found-object nil))
170
+    (loop for i from (1+ location) to (* (game-map-width map) (game-map-height map)) do
171
+      (setf found-object (gethash i (game-map-mobiles map)))
172
+      (when (not (typep found-object 'mobile))
173
+        (setf found-object nil))
174
+          until found-object)
175
+    found-object))
176
+
177
+(defun find-mobile-up (location map)
178
+  (let ((found-object nil))
179
+    (loop for i from (- location (game-map-width map)) downto 0 by (game-map-width map) do
180
+      (setf found-object (gethash i (game-map-mobiles map)))
181
+      (when (not (typep found-object 'mobile))
182
+        (setf found-object nil))
183
+          until found-object)
184
+    found-object))
185
+
186
+(defun find-mobile-down (location map)
187
+  (let ((found-object nil))
188
+    (loop for i from (+ location (game-map-width map)) to (* (game-map-width map) (game-map-height map)) by (game-map-width map) do
189
+      (setf found-object (gethash i (game-map-mobiles map)))
190
+      (when (not (typep found-object 'mobile))
191
+        (setf found-object nil))
192
+          until found-object)
193
+    found-object))
194
+
195
+(defgeneric shoot-left (object map))
196
+(defgeneric shoot-right (object map))
197
+(defgeneric shoot-up (object map))
198
+(defgeneric shoot-down (object map))
199
+
200
+(defmethod shoot-left ((object player-character) map)
201
+  (let ((target (find-mobile-left (slot-value object 'location) map)))
202
+    (when target
203
+      (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
204
+      (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
205
+
206
+(defmethod shoot-right ((object player-character) map)
207
+  (let ((target (find-mobile-right (slot-value object 'location) map)))
208
+    (when target
209
+      (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
210
+      (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
211
+
212
+(defmethod shoot-up ((object player-character) map)
213
+  (let ((target (find-mobile-up (slot-value object 'location) map)))
214
+    (when target
215
+      (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
216
+      (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
217
+
218
+(defmethod shoot-down ((object player-character) map)
219
+  (let ((target (find-mobile-down (slot-value object 'location) map)))
220
+    (when target
221
+      (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
222
+      (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
223
+
224
+(defgeneric bash-left (object map))
225
+(defgeneric bash-right (object map))
226
+(defgeneric bash-up (object map))
227
+(defgeneric bash-down (object map))
228
+
229
+(defmethod bash-left ((object player-character) map)
230
+  (let* ((location (1- (slot-value object 'location)))
231
+         (potential-target (gethash location (game-map-mobiles map)))
232
+         (target (and potential-target (typep potential-target 'mobile))))
233
+    (when target
234
+      (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
235
+
236
+(defmethod bash-right ((object player-character) map)
237
+  (let* ((location (1+ (slot-value object 'location)))
238
+         (potential-target (gethash location (game-map-mobiles map)))
239
+         (target (and potential-target (typep potential-target 'mobile))))
240
+    (when target
241
+      (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
242
+
243
+(defmethod bash-up ((object player-character) map)
244
+  (let* ((location (- (slot-value object 'location) (game-map-width map)))
245
+         (potential-target (gethash location (game-map-mobiles map)))
246
+         (target (and potential-target (typep potential-target 'mobile))))
247
+    (when target
248
+      (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
249
+
250
+(defmethod bash-down ((object player-character) map)
251
+  (let* ((location (+ (slot-value object 'location) (game-map-width map)))
252
+         (potential-target (gethash location (game-map-mobiles map)))
253
+         (target (and potential-target (typep potential-target 'mobile))))
254
+    (when target
255
+      (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
256
+
139 257
 (defun intro-message ()
140
-  (loop as key = (terminal-read) do
141
-    (multiple-value-bind (win-width win-height) (get-window-size)
142
-      (terminal-print (floor (- (/ win-width 2) 10)) (floor (1- (/ win-height 2))) "Crypts and Corpses")
143
-      (terminal-print (floor (- (/ win-width 2) 11)) (floor (1+ (/ win-height 2))) "Press enter to start"))
144
-    (terminal-refresh)
145
-        until (= key bearlibterminal-ffi:+tk-enter+)))
258
+  (multiple-value-bind (win-width win-height) (get-window-size)
259
+    (terminal-print (floor (- (/ win-width 2) 10)) (floor (1- (/ win-height 2))) "Crypts and Corpses")
260
+    (terminal-print (floor (- (/ win-width 2) 11)) (floor (1+ (/ win-height 2))) "Press enter to start"))
261
+  (terminal-refresh))
146 262
 
147 263
 (defun write-map-to-terminal (map viewport)
148 264
   (labels ((write-cell (key tile)
149 265
              (multiple-value-bind (x y) (calc-coord (- key (slot-value viewport 'location)) map)
266
+               (terminal-color (slot-value tile 'color))
150 267
                (terminal-put x y (slot-value tile 'codepoint)))))
151 268
     (maphash #'write-cell (game-map-mobiles map))))
152 269
 
153
-(defun fill-map-from-crawler (dungeon map)
270
+(defun nearest-open-tile (location map)
271
+  (let ((left (1- location))
272
+        (right (1+ location))
273
+        (up (- (game-map-width map) location))
274
+        (down (+ (game-map-width map) location))
275
+        (mobiles (game-map-mobiles map)))
276
+    (cond
277
+      ((eq :not-found (gethash left mobiles :not-found)) left)
278
+      ((eq :not-found (gethash up mobiles :not-found)) up)
279
+      ((eq :not-found (gethash right mobiles :not-found)) right)
280
+      ((eq :not-found (gethash down mobiles :not-found)) down))))
281
+
282
+(defun fill-map-from-crawler (dungeon map player)
154 283
   (with-slots ((width crawler:width) (height crawler:height)) dungeon
155 284
     (dotimes (x width)
156 285
       (dotimes (y height)
@@ -158,24 +287,52 @@
158 287
           (unless (crawler:walkablep tile)
159 288
             (let ((wall (make-instance 'wall)))
160 289
               (set-location wall x y map)
161
-              (setf (gethash (calc-location x y map) (game-map-mobiles map)) wall))))))))
290
+              (setf (gethash (calc-location x y map) (game-map-mobiles map)) wall)))
291
+          (when (eq (crawler:map-feature tile) :stairs-up)
292
+            (set-location player x y map)
293
+            (setf (gethash (calc-location x y map) (game-map-mobiles map)) player)
294
+            (let* ((location (nearest-open-tile (calc-location x y map) map))
295
+                   (enemy (make-instance 'enemy :location location)))
296
+              (setf (gethash location (game-map-mobiles map)) enemy))))))))
162 297
 
163 298
 (defun initialize-map (map player)
164 299
   (setf (gethash (slot-value player 'location) (game-map-mobiles map)) player)
165
-  (fill-map-from-crawler (crawler:make-dungeon (1- (game-map-width map)) (1- (game-map-height map))) map)
300
+  (fill-map-from-crawler (crawler:make-dungeon (game-map-width map) (game-map-height map)) map player)
166 301
   map)
167 302
 
168
-(defun handle-input (key map viewport player)
303
+(defun handle-input (key map viewport player prev-key)
169 304
   (cond
170
-    ((= key bearlibterminal-ffi:+tk-up+) (move-up player map))
171
-    ((= key bearlibterminal-ffi:+tk-down+) (move-down player map))
172
-    ((= key bearlibterminal-ffi:+tk-right+) (move-right player map))
173
-    ((= key bearlibterminal-ffi:+tk-left+) (move-left player map))
174
-    ((= key bearlibterminal-ffi:+tk-w+) (move-up viewport map))
175
-    ((= key bearlibterminal-ffi:+tk-a+) (move-left viewport map))
176
-    ((= key bearlibterminal-ffi:+tk-d+) (move-right viewport map))
177
-    ((= key bearlibterminal-ffi:+tk-s+) (move-down viewport map))
178
-    ((= key bearlibterminal-ffi:+tk-space+) (update-location viewport map (slot-value viewport 'location) (slot-value player 'location)))))
305
+    ;; Ranged attack
306
+    ((equal prev-key bearlibterminal-ffi:+tk-r+)
307
+     (cond
308
+       ((= key bearlibterminal-ffi:+tk-up+) (shoot-up player map))
309
+       ((= key bearlibterminal-ffi:+tk-down+) (shoot-down player map))
310
+       ((= key bearlibterminal-ffi:+tk-right+) (shoot-right player map))
311
+       ((= key bearlibterminal-ffi:+tk-left+) (shoot-left player map))
312
+       ((= key bearlibterminal-ffi:+tk-enter+) t))) ; cancel
313
+    ;; Melee attack
314
+    ((equal prev-key bearlibterminal-ffi:+tk-m+)
315
+     (cond
316
+       ((= key bearlibterminal-ffi:+tk-up+) (bash-up player map))
317
+       ((= key bearlibterminal-ffi:+tk-down+) (bash-down player map))
318
+       ((= key bearlibterminal-ffi:+tk-right+) (bash-right player map))
319
+       ((= key bearlibterminal-ffi:+tk-left+) (bash-left player map))
320
+       ((= key bearlibterminal-ffi:+tk-enter+) t))) ; cancel
321
+    ;; Not a stateful command
322
+    (:otherwise
323
+     (cond
324
+       ((= key bearlibterminal-ffi:+tk-r+) t) ; Prepare for ranged
325
+       ((= key bearlibterminal-ffi:+tk-m+) t) ; Prepare for melee
326
+       ((= key bearlibterminal-ffi:+tk-enter+) t) ; idle
327
+       ((= key bearlibterminal-ffi:+tk-up+) (move-up player map))
328
+       ((= key bearlibterminal-ffi:+tk-down+) (move-down player map))
329
+       ((= key bearlibterminal-ffi:+tk-right+) (move-right player map))
330
+       ((= key bearlibterminal-ffi:+tk-left+) (move-left player map))
331
+       ((= key bearlibterminal-ffi:+tk-w+) (move-up viewport map))
332
+       ((= key bearlibterminal-ffi:+tk-a+) (move-left viewport map))
333
+       ((= key bearlibterminal-ffi:+tk-d+) (move-right viewport map))
334
+       ((= key bearlibterminal-ffi:+tk-s+) (move-down viewport map))
335
+       ((= key bearlibterminal-ffi:+tk-space+) (update-location viewport map (slot-value viewport 'location) (slot-value player 'location)))))))
179 336
 
180 337
 (defun create-viewport (map)
181 338
   (multiple-value-bind (width height) (get-window-size)
@@ -185,23 +342,48 @@
185 342
       (setf height (game-map-height map)))
186 343
     (make-instance 'viewport :width width :height height)))
187 344
 
345
+(defun end-of-turn-tasks (player map)
346
+  (declare (ignore player))
347
+  (maphash (lambda (location object)
348
+             (when (typep object 'mobile)
349
+               (if (>= 0 (slot-value object 'health))
350
+                   (progn
351
+                     (format t "~S~%" (slot-value object 'health))
352
+                     (setf (slot-value object 'location) nil)
353
+                     (remhash location (game-map-mobiles map)))
354
+                   (end-of-turn object)))) (game-map-mobiles map)))
355
+
356
+(defun write-status-to-terminal (player prev-key)
357
+  (declare (ignore prev-key))
358
+  (multiple-value-bind (width height) (get-window-size)
359
+    (declare (ignore width))
360
+    (terminal-color (color-from-name "white"))
361
+    (terminal-print 0 (1- height) (format nil "H: ~d M: ~d"
362
+                                          (slot-value player 'health)
363
+                                          (slot-value player 'mana)))))
364
+
188 365
 (defun main-loop ()
189
-  (let ((player (make-instance
190
-                 'player-character
191
-                 :location 0)))
192
-    (loop with map = (initialize-map (make-instance 'game-map) player)
193
-          with viewport = (create-viewport map)
194
-          as key = (terminal-read) do
195
-            (handle-input key map viewport player)
366
+  (loop with player = (make-instance 'player-character)
367
+        with map = (initialize-map (make-instance 'game-map) player)
368
+        with viewport = (create-viewport map)
369
+        with prev-key = nil
370
+        as key = (terminal-read) do
371
+          (when (handle-input key map viewport player prev-key)
372
+            (setf prev-key key)
196 373
             (terminal-clear)
374
+            (unless (or (= key bearlibterminal-ffi:+tk-r+)
375
+                        (= key bearlibterminal-ffi:+tk-m+))
376
+              (end-of-turn-tasks player map))
197 377
             (write-map-to-terminal map viewport)
198
-            (terminal-refresh)
199
-          until (or (= key bearlibterminal-ffi:+tk-close+)
200
-                    (= key bearlibterminal-ffi:+tk-escape+)))))
378
+            (write-status-to-terminal player prev-key)
379
+            (terminal-refresh))
380
+        until (or (= key bearlibterminal-ffi:+tk-close+)
381
+                  (= key bearlibterminal-ffi:+tk-escape+)
382
+                  (eq (slot-value player 'location) nil))))
201 383
 
202 384
 (defun start ()
203 385
   (terminal-open)
204
-  (terminal-set "window: size=100x40, title='Crypts and Corpses'")
386
+  (terminal-set "window: size=99x40, title='Crypts and Corpses'")
205 387
   (terminal-set "font: ./fonts/DejaVuSansMono.ttf, size=16")
206 388
   (intro-message)
207 389
   (main-loop)