;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; General Game Definitions ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Classes ;;; All game objects are subclasses of this. (defclass () ;; symbol used by players to refer to the object (nickname :type ; a list of symbols :accessor nick :initarg :nick) ;; its printed name (name :type :accessor name :initarg :name) ;; a longer description - a list of strings (description :type :accessor description :initarg :description :initvalue "") ;; a list of commands that applies to the object (commands :type :accessor commlist :initarg :commands :initvalue '()) (visible? :type :initarg :visible :reader visible? :accessor visible :initvalue #t)) ;;; Objects that contain other objects. (defclass () (contents :type ; (of s) :accessor contents :initarg :contents :initvalue '())) ;;; Objects that can be in containers. (defclass () (location :type :accessor location :initarg :location)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Interface ;;; Use this to show an object with its nickname so players know how to ;;; refer to this object. (defgeneric (name+nick game-object)) ;;; This function gets a list of s and returns the one with ;;; the given nickname, or #f of none found. ;;; (define (nick-find nickname list) ...) ;;; Move an object to a different location. (defgeneric (transfer obj source target)) ;;; Returns a list of commands available to the player (defgeneric (commands plyr game-object)) ;;; Destroys an object -- essentially remove references so it can be ;;; garbage collected (defgeneric (destroy animate)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Globals ;;; This global is used as the location of destroyed objects - to ;;; check whether an animate is dead see if its location slot is eq? to ;;; this. There is no need for any information on this object. (define *null-place* (make :nick '(null) :name "null")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Implementation ;;; This specialize the way that objects are created - ;;; updating the holding container automatically. ;;; initialize is a built-in standard generic that is called on every ;;; object that is created, so you must call the next method to do what ;;; it was supposed to do, then add stuff. (defmethod (initialize (o ) initargs) (call-next-method) ; must call this ;; this prevents errors when there is no initial location value ;; (slot-bound can test if there is any value in the location slot) (when (slot-bound? o 'location) (set! (contents (location o)) (cons o (contents (location o)))))) ;;; Using this method will produce uniform output that players can use. (defmethod (name+nick (obj )) (add (name obj) " [" (as (first (nick obj))) "]")) ;;; Search for an object by its nickname, nickname can be anything, but ;;; only symbols will be found. (define (nick-find nickname list) (find-if (lambda (x) (memq nickname (nick x))) list)) ;;; Move an object to a different location. Using only this method to ;;; make sure that you don't get inconsistencies. (defmethod (transfer (obj ) (from ) (to )) (unless (eq? from to) (set! (contents from) (remq obj (contents from))) (set! (location obj) to) (set! (contents to) (cons obj (contents to))))) (defmethod (destroy (obj )) ;; remove the object from the starting container (set! (contents (location obj)) (remq obj (contents (location obj)))) ;; and indicate that this character is dead, should there be more ;; references to the object. *null-place* does not have any ;; references to this object. (set! (location obj) *null-place*))