;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Inanimates ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Classes ;;; The class of all objects. (defclass () (start :type :accessor start-place :initvalue *null-place*) (size :type :initarg :size :accessor size :initvalue 0)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Interface ;;; A predicate for inanimates. ;;; (define (inanimate? x) ...) (defgeneric (drop inanimate animate place)) (defgeneric (take inanimate place animate)) (defgeneric (give inanimate animate animate)) (defgeneric (steal inanimate animate animate)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Implementation ;;; Record the starting place, in case we need it again. Do this ;;; using Swindle's initialize method. (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) ;; If the initial location is an animate, then change their ;; current capacity (cond ((and (animate? (location o)) (<= (size o) (maxload (location o)))) (set! (start-place o) (location o)) (set! (maxload (location o)) (- (maxload (location o)) (size o)))) ;; If the animate can't carry the object, then just destroy ;; it now ((and (animate? (location o)) (> (size o) (maxload (location o)))) (destroy o)) ;; Just put the object in some location (else (set! (start-place o) (location o)))))) ;;; This is defined since it is used in several places. (define (inanimate? x) (instance-of? x )) (defmethod (destroy (obj )) (when (animate? (location obj)) (set! (maxload (location obj)) (+ (maxload (location obj)) (size obj)))) (call-next-method)) (defmethod (transfer (o ) (from ) (to )) (unless (> (size o) (maxload to)) (call-next-method) (set! (maxload to) (- (maxload to) (size o)))) #t) (defmethod (transfer (o ) (from ) (to )) (unless (and (animate? to) (> (size o) (maxload to))) (call-next-method) (set! (maxload from) (+ (maxload from) (size o)))) #t) ;;; This makes transfer be the "take" command, the inanimate is the ;;; object, the place is the source and the player is the target. (defmethod (take (o ) (from ) (to )) (cond ((> (size o) 75) (tell to (echos "The" (name o) "is too big to carry."))) ((> (size o) (maxload to)) (tell to "You're carrying too much already.")) ((memq o (contents from)) (transfer o from to) (tell to (echos "You take" (name o))) (place-message from to #f (echos (name to) "took" (name o)))) (else (tell to (echos "You cannot take" (name o))))) ;; return this sice it is used as the result of command processing #t) ;;; And this uses transfer again to be a "drop" command, similar to the ;;; above but the types are reversed. (defmethod (drop (o ) (from ) (to )) (cond ((memq o (contents from)) (transfer o from to) (tell from (echos "You drop" (name o))) (place-message to from #f (echos (name from) "dropped" (name o)))) (else (tell from (echos "You don't have" (name o))))) #t) ;;; Yet another version - now transfer is a give operation between two ;;; players. (defmethod (give (o ) (from ) (to )) (cond ((> (size o) (maxload to)) (tell from (echos (name to) "says: Thank you, but I'm " "carrying too much already."))) ((memq o (contents from)) (transfer o from to) (tell from (echos "You give" (name o) "to" (name to))) (tell to (echos (name from) "gave you" (name o)))) (else (tell from (echos "You don't have" (name o))))) #t) (defmethod (steal (o ) (from ) (to )) (cond ((> (size o) (maxload to)) (tell to "You're already carrying too much to steal that.")) ((memq o (contents from)) (transfer o from to) (tell to (echos "You steal" (name o) "from" (name from)))) (else (tell to (echos (name from) "does not have" (name o))))) #t)