;;; -*- Mode:LISP; Readtable:CL; Base:10 -*- ;;;; Object system (defun get-option (option-name options default) (let ((op (assoc option-name options))) (if op (cdr op) default))) (defmacro defclass (name-or-stuff &rest slots) (let ((name (if (symbolp name-or-stuff) name-or-stuff (car name-or-stuff))) (options (if (symbolp name-or-stuff) '() (cdr name-or-stuff)))) (let ((included (get-option :include options '())) (conc-name (string (get-option :conc-name options name))) (slot-names (mapcar #'(lambda (slot) (if (symbolp slot) slot (car slot))) slots))) `(progn (defflavor ,name ,slots ,included :initable-instance-variables :settable-instance-variables :gettable-instance-variables) (defun ,(intern (format nil "MAKE-~a" name)) (&rest init-options) (apply #'make-instance ',name init-options)) ,@(mapcar #'(lambda (slot) (create-accessor slot conc-name)) slot-names))))) (defun create-accessor (slot conc-name) (let ((acc-name (intern (format nil "~a-~a" conc-name slot)))) `(progn (defsubst ,acc-name (obj) (send obj ,(intern (string slot) 'keyword))) (defsetf ,acc-name (obj) (value) `(send ,obj ,',(intern (format nil "SET-~a" slot) 'keyword) ,value))))) (setq si:*use-generic-function-as-message* t) (defclass (view (:include tv:window)) (label nil) (blinker-p nil) (x-offset 0) (y-offset 0)) (defvar *default-font* fonts:hl12b) (defvar *current-view* (make-view :left 30 :top 30 :right (- (tv:sheet-width tv:main-screen) 30) :bottom (- (tv:sheet-height tv:main-screen) 200) :borders 4)) (defun draw-character (view ch x y &optional (alu tv:alu-ior) (font *default-font*)) (tv:prepare-sheet (view) (tv:draw-char font ch x y alu view))) (defun draw-string (view string x y &optional (alu tv:alu-ior) (font *default-font*)) (send view :string-out-explicit string x y 10000 10000 font alu)) (defun frame-rectangle (view x y w h &optional (thickness 1)) (when (plusp thickness) (paint:frame-rect w h x y view tv:alu-ior thickness))) (defun pattern-rectangle (view x y w h pattern) (bitblt tv:alu-ior w h pattern 0 0 (tv:sheet-screen-array view) x y)) ;---------------------------------------------------------------- (defclass thing (x 0) (y 0)) (defgeneric draw (thing)) (defgeneric description (thing)) (defmethod (thing draw) () (draw-string *current-view* "?" x y)) (defmethod (thing description) () "A random Thing") ;---------------------------------------------------------------- (defclass (room (:include thing)) (width 10) (height 10) (wall-thickness 2) (exits '()) (objects-within '())) ;(defun rectangle-overlap (x1 y1 w1 h1 x2 y2 w2 h2) ; (declare (values x y w h)) ; (let ((right1 (+ x1 w1)) ; (bottom1 (+ y1 h1)) ; (right2 (+ x2 w2)) ; (bottom2 (+ y2 h2))) ; (let ((left (cond ((<= x1 x2 right1) x2) ; ((<= )))))))) (defmethod (room draw) () (pattern-rectangle *current-view* x y width height paint:light-gray) (frame-rectangle *current-view* x y width height wall-thickness) (dolist (exit exits)) (dolist (obj objects-within) (draw obj))) (defgeneric in? (place pt-x pt-y)) (defgeneric within? (place pt-x pt-y)) (defmethod (room in?) (pt-x pt-y) (and (> pt-x x) (> pt-y y) (< pt-x (+ x width)) (< pt-y (+ y height)))) (defmethod (room within?) (pt-x pt-y) (if (and (> pt-x x) (> pt-y y) (< pt-x (+ x width)) (< pt-y (+ y height))) self (dolist (exit exits) (when (in? exit pt-x pt-y) (return exit))))) ;---------------------------------------------------------------- (defclass (passage (:include room)) (width 16.) (length 16.) (end-1 nil) (end-2 nil)) ;---------------------------------------------------------------- (defclass (ns-passage (:include passage))) (defmethod (ns-passage draw) () (pattern-rectangle *current-view* (- x (truncate width 2)) y width length paint:gray)) (defmethod (ns-passage in?) (pt-x pt-y) (let ((left (- x (truncate width 2)))) (and (>= pt-y y) (>= pt-x left) (<= pt-y (+ y length)) (<= pt-x (+ left width))))) (defmethod (ns-passage within?) (pt-x pt-y) (let ((left (- x (truncate width 2)))) (cond ((and (>= pt-y y) (>= pt-x left) (<= pt-y (+ y length)) (<= pt-x (+ left width))) self) ((and end-1 (in? end-1 pt-x pt-y)) end-1) ((and end-2 (in? end-2 pt-x pt-y)) end-2) (t nil)))) ;---------------------------------------------------------------- (defclass (ew-passage (:include passage))) (defmethod (ew-passage draw) () (pattern-rectangle *current-view* x (- y (truncate width 2)) length width paint:gray)) (defmethod (ew-passage in?) (pt-x pt-y) (let ((top (- y (truncate width 2)))) (and (>= pt-x x) (>= pt-y top) (<= pt-x (+ x length)) (<= pt-y (+ top width))))) (defmethod (ew-passage within?) (pt-x pt-y) (let ((top (- y (truncate width 2)))) (cond ((and (>= pt-x x) (>= pt-y top) (<= pt-x (+ x length)) (<= pt-y (+ top width))) self) ((and end-1 (in? end-1 pt-x pt-y)) end-1) ((and end-2 (in? end-2 pt-x pt-y)) end-2) (t nil)))) ;---------------------------------------------------------------- (defclass (joint (:include thing)) (height 16.) (width 16.) (top nil) (bottom nil) (left nil) (right nil)) (defmethod (joint draw) () (pattern-rectangle *current-view*)) ;---------------------------------------------------------------- (defclass (moving-thing (:include thing)) (within nil)) (defgeneric erase (thing)) (defgeneric move (moving-thing new-x new-y)) (defun check-move (moving-thing new-x new-y) (let ((within (moving-thing-within moving-thing))) (let ((within? (within? within new-x new-y))) (cond ((null within?) (tv:beep) nil) ((eq within? within) t) (t (erase moving-thing) (draw within?) (draw moving-thing) (setf (moving-thing-within moving-thing) within?) t))))) (defmethod (moving-thing move) (new-x new-y) (when (check-move self new-x new-y) (erase self) (setf (thing-x self) new-x) (setf (thing-y self) new-y) (draw self))) (defun move-right (moving-thing &optional (amount 10.)) (move moving-thing (+ (thing-x moving-thing) amount) (thing-y moving-thing))) (defun move-left (moving-thing &optional (amount 10.)) (move moving-thing (- (thing-x moving-thing) amount) (thing-y moving-thing))) (defun move-up (moving-thing &optional (amount 10.)) (move moving-thing (thing-x moving-thing) (- (thing-y moving-thing) amount))) (defun move-down (moving-thing &optional (amount 10.)) (move moving-thing (thing-x moving-thing) (+ (thing-y moving-thing) amount))) (defmethod (moving-thing erase) () (draw self)) ;---------------------------------------------------------------- (defclass (character (:include moving-thing)) (strength 0) (hit-points 0) (char #\?)) (defmethod (character draw) () (draw-character *current-view* char (- x 7) (- y 7) tv:alu-xor)) ;---------------------------------------------------------------- (defclass (player (:include character))) ;---------------------------------------------------------------- (defclass (monster (:include character))) ;---------------------------------------------------------------- (defclass (money (:include moving-thing)) (amount 10.)) (defmethod (money draw) () (draw-character *current-view* #\$ (- x 7) (- y 7) tv:alu-xor)) (defmethod (money description) () (format nil "~d Gold Pieces" (money-amount self))) ;---------------------------------------------------------------- (defvar *you* (make-player :char #\@)) (defun com-loop () (send *current-view* :expose) (send *current-view* :clear-screen) (draw (moving-thing-within *you*)) (draw *you*) (do () (()) (case (read-char) ((#\hand-up) (move-up *you*)) ((#\hand-down) (move-down *you*)) ((#\hand-left) (move-left *you*)) ((#\hand-right) (move-right *you*)))))