| 1 |
(in-package :bos.m2) |
|---|
| 2 |
|
|---|
| 3 |
;;;; XXX Dokumentation aus der alten Implementation |
|---|
| 4 |
|
|---|
| 5 |
;;;; TILE |
|---|
| 6 |
;;;; |
|---|
| 7 |
;;;; Kacheln sind per x-y-Koordinate ansprechbare Bloecke von Quadratmetern. |
|---|
| 8 |
;;;; An Kacheln koennen verschiedene Nutzerdaten haengen, diese sind von |
|---|
| 9 |
;;;; Unterklassen festzulegen. |
|---|
| 10 |
;;;; |
|---|
| 11 |
;;;; Kacheln sind transiente Objekte, die lazy, als nur bei Bedarf, angelegt |
|---|
| 12 |
;;;; werden. So wird vermieden, fuer das gesamte Vergabegebiet Kachelobjekte |
|---|
| 13 |
;;;; im Voraus anlegen zu muessen. |
|---|
| 14 |
;;;; |
|---|
| 15 |
;;;; Kacheln werden ueber die Quadratmeterkoordinate ihrer Nord-West-Ecke |
|---|
| 16 |
;;;; addressiert. |
|---|
| 17 |
|
|---|
| 18 |
(defclass tile () |
|---|
| 19 |
((nw-x :initarg :nw-x :reader tile-nw-x) |
|---|
| 20 |
(nw-y :initarg :nw-y :reader tile-nw-y) |
|---|
| 21 |
(width :initarg :width :reader tile-width) |
|---|
| 22 |
(objects :initarg :objects :reader tile-objects))) |
|---|
| 23 |
|
|---|
| 24 |
(defmethod print-object ((tile tile) stream) |
|---|
| 25 |
(print-unreadable-object (tile stream :type t :identity nil) |
|---|
| 26 |
(format stream "at (~D,~D) width ~D" |
|---|
| 27 |
(tile-nw-x tile) |
|---|
| 28 |
(tile-nw-y tile) |
|---|
| 29 |
(tile-width tile)))) |
|---|
| 30 |
|
|---|
| 31 |
(defmethod initialize-instance :after ((tile tile) &key width &allow-other-keys) |
|---|
| 32 |
(setf (slot-value tile 'objects) |
|---|
| 33 |
(make-array (list width width) |
|---|
| 34 |
:initial-element nil))) |
|---|
| 35 |
|
|---|
| 36 |
(defmethod validate-coords ((tile tile) x y) |
|---|
| 37 |
(unless (and (< -1 (- x (tile-nw-x tile)) (tile-width tile)) |
|---|
| 38 |
(< -1 (- y (tile-nw-y tile)) (tile-width tile))) |
|---|
| 39 |
(error "coordinates ~D/~D are out of range for ~A" x y tile))) |
|---|
| 40 |
|
|---|
| 41 |
(defmethod tile-height ((tile tile)) |
|---|
| 42 |
(tile-width tile)) ; assume quadratic tiles |
|---|
| 43 |
|
|---|
| 44 |
(defmethod tile-absolute-x ((tile tile) relative-x) |
|---|
| 45 |
(+ (tile-nw-x tile) relative-x)) |
|---|
| 46 |
|
|---|
| 47 |
(defmethod tile-absolute-y ((tile tile) relative-y) |
|---|
| 48 |
(+ (tile-nw-y tile) relative-y)) |
|---|
| 49 |
|
|---|
| 50 |
(defmethod object-at ((tile tile) x y) |
|---|
| 51 |
(validate-coords tile x y) |
|---|
| 52 |
(aref (tile-objects tile) (- x (tile-nw-x tile)) (- y (tile-nw-y tile)))) |
|---|
| 53 |
|
|---|
| 54 |
(defmethod (setf object-at) (object (tile tile) x y) |
|---|
| 55 |
(validate-coords tile x y) |
|---|
| 56 |
(setf (aref (tile-objects tile) (- x (tile-nw-x tile)) (- y (tile-nw-y tile))) object)) |
|---|
| 57 |
|
|---|
| 58 |
(defclass tiled-index () |
|---|
| 59 |
(x-slot-name |
|---|
| 60 |
y-slot-name |
|---|
| 61 |
(tiles :reader tiled-index-tiles) |
|---|
| 62 |
(width :initarg :width) |
|---|
| 63 |
(height :initarg :height) |
|---|
| 64 |
(tile-size :initarg :tile-size) |
|---|
| 65 |
(tile-class :initarg :tile-class)) |
|---|
| 66 |
(:default-initargs :tile-class 'tile)) |
|---|
| 67 |
|
|---|
| 68 |
(defmethod initialize-instance :after ((tiled-index tiled-index) &key width height tile-size slots &allow-other-keys) |
|---|
| 69 |
(with-slots (x-slot-name y-slot-name) tiled-index |
|---|
| 70 |
(setf x-slot-name (first slots)) |
|---|
| 71 |
(setf y-slot-name (second slots))) |
|---|
| 72 |
(unless (and (zerop (mod width tile-size)) |
|---|
| 73 |
(zerop (mod height tile-size))) |
|---|
| 74 |
(error "invalid tile-index dimensions (width ~D height ~D) for tile size ~D~%index dimensions must be dividable by tile size" |
|---|
| 75 |
width height tile-size)) |
|---|
| 76 |
(index-clear tiled-index)) |
|---|
| 77 |
|
|---|
| 78 |
(defmethod print-object ((tiled-index tiled-index) stream) |
|---|
| 79 |
(print-unreadable-object (tiled-index stream :type t :identity nil) |
|---|
| 80 |
(ignore-errors |
|---|
| 81 |
(with-slots (width height tile-size tile-class) tiled-index |
|---|
| 82 |
(format stream "width ~D height ~D tile-size ~D tile-class ~D" |
|---|
| 83 |
width height tile-size tile-class))))) |
|---|
| 84 |
|
|---|
| 85 |
(defmethod validate-coords ((tiled-index tiled-index) x y) |
|---|
| 86 |
(unless (and (< -1 x (slot-value tiled-index 'width)) |
|---|
| 87 |
(< -1 y (slot-value tiled-index 'height))) |
|---|
| 88 |
(error "coordinates ~D/~D are out of range for ~A" x y tiled-index))) |
|---|
| 89 |
|
|---|
| 90 |
(defmethod get-tile ((tiled-index tiled-index) x y) |
|---|
| 91 |
(validate-coords tiled-index x y) |
|---|
| 92 |
(with-slots (tiles tile-size) tiled-index |
|---|
| 93 |
(aref tiles |
|---|
| 94 |
(floor x tile-size) |
|---|
| 95 |
(floor y tile-size)))) |
|---|
| 96 |
|
|---|
| 97 |
(defmethod ensure-tile ((tiled-index tiled-index) x y) |
|---|
| 98 |
(validate-coords tiled-index x y) |
|---|
| 99 |
(with-slots (tiles tile-size tile-class) tiled-index |
|---|
| 100 |
(or (get-tile tiled-index x y) |
|---|
| 101 |
(setf (aref tiles |
|---|
| 102 |
(floor x tile-size) |
|---|
| 103 |
(floor y tile-size)) |
|---|
| 104 |
(make-instance tile-class |
|---|
| 105 |
:nw-x (* tile-size (floor x tile-size)) |
|---|
| 106 |
:nw-y (* tile-size (floor y tile-size)) |
|---|
| 107 |
:width tile-size))))) |
|---|
| 108 |
|
|---|
| 109 |
(defmethod object-at ((tiled-index tiled-index) x y) |
|---|
| 110 |
(let ((tile (get-tile tiled-index x y))) |
|---|
| 111 |
(when tile |
|---|
| 112 |
(object-at tile x y)))) |
|---|
| 113 |
|
|---|
| 114 |
(defmethod (setf object-at) (object (tiled-index tiled-index) x y) |
|---|
| 115 |
(setf (object-at (ensure-tile tiled-index x y) x y) object)) |
|---|
| 116 |
|
|---|
| 117 |
;; bknr index protocol methods |
|---|
| 118 |
|
|---|
| 119 |
(defmethod index-add ((index tiled-index) object) |
|---|
| 120 |
(with-slots (x-slot-name y-slot-name) index |
|---|
| 121 |
(unless (and (slot-boundp object x-slot-name) |
|---|
| 122 |
(slot-boundp object y-slot-name)) |
|---|
| 123 |
(return-from index-add nil)) |
|---|
| 124 |
(setf (object-at index |
|---|
| 125 |
(slot-value object x-slot-name) |
|---|
| 126 |
(slot-value object y-slot-name)) |
|---|
| 127 |
object))) |
|---|
| 128 |
|
|---|
| 129 |
(defmethod index-get ((index tiled-index) coords) |
|---|
| 130 |
(apply #'object-at index coords)) |
|---|
| 131 |
|
|---|
| 132 |
(defmethod index-remove ((index tiled-index) object) |
|---|
| 133 |
(with-slots (x-slot-name y-slot-name) index |
|---|
| 134 |
(unless (and (slot-boundp object x-slot-name) |
|---|
| 135 |
(slot-boundp object y-slot-name)) |
|---|
| 136 |
(return-from index-remove nil)) |
|---|
| 137 |
(unless (eq object |
|---|
| 138 |
(object-at index |
|---|
| 139 |
(slot-value object x-slot-name) |
|---|
| 140 |
(slot-value object y-slot-name))) |
|---|
| 141 |
(error "while removing object ~A from ~A - unexpected object ~A in index, can't remove object" |
|---|
| 142 |
object |
|---|
| 143 |
index |
|---|
| 144 |
(object-at index |
|---|
| 145 |
(slot-value object x-slot-name) |
|---|
| 146 |
(slot-value object y-slot-name)))) |
|---|
| 147 |
(setf (object-at index |
|---|
| 148 |
(slot-value object x-slot-name) |
|---|
| 149 |
(slot-value object y-slot-name)) |
|---|
| 150 |
nil))) |
|---|
| 151 |
|
|---|
| 152 |
(defmethod index-keys ((index tiled-index)) |
|---|
| 153 |
(error "An TILED-INDEX has no keys.")) |
|---|
| 154 |
|
|---|
| 155 |
(defmethod index-values ((index tiled-index)) |
|---|
| 156 |
(error "An TILED-INDEX cannot enumerate its values.")) |
|---|
| 157 |
|
|---|
| 158 |
(defmethod index-mapvalues ((index tiled-index) fun) |
|---|
| 159 |
(error "An TILED-INDEX cannot enumerate its values.")) |
|---|
| 160 |
|
|---|
| 161 |
(defmethod index-clear ((index tiled-index)) |
|---|
| 162 |
(with-slots (width height tile-size) index |
|---|
| 163 |
(setf (slot-value index 'tiles) (make-array (list (floor width tile-size) |
|---|
| 164 |
(floor height tile-size)) |
|---|
| 165 |
:initial-element nil)))) |
|---|
| 166 |
|
|---|
| 167 |
(defmethod index-reinitialize ((new-index tiled-index) (old-index tiled-index)) |
|---|
| 168 |
(unless (every #'(lambda (slot-name) (equal (slot-value old-index slot-name) |
|---|
| 169 |
(slot-value new-index slot-name))) |
|---|
| 170 |
'(width height tile-size x-slot-name y-slot-name)) |
|---|
| 171 |
(error "can't change index parameters for index ~A" old-index)) |
|---|
| 172 |
(setf (slot-value new-index 'tiles) (slot-value old-index 'tiles))) |
|---|