blob: 9037d989bd67fdec769ac630c4f4cd7f49467d33 (
plain) (
tree)
|
|
(require "split-sequence") ; TODO: really used?
(defpackage #:ccap-muck
(:use #:common-lisp #:split-sequence)
(:export
#:main)
)
(in-package #:ccap-muck)
(defvar *terminate-program* nil)
(defvar +bold+ "#\esc[1m") ; TODO: (alexandria:define-constant ...)
(defvar +unbold+ "#\esc[0m")
(defconstant +q+ #\")
(defclass <avatar> () ((name :accessor name)
(playing :reader playing :initform nil)
(password :accessor password)))
(defvar *avatars* '())
(defvar *write-avatars* nil)
(defclass <connection> () ((g :reader g)
(socket :reader socket)
(parser :reader parser)
(avatar :reader avatar)
(curr-room :reader curr-room)))
(defvar *connections* '())
(defconstant +port-number+ 6565)
(defvar +vd-type+ #(n s e w u d)) ; TODO: alexandria again
(defclass <room> () ((name :reader name)
(desc :reader desc)
(exits :reader exits)))
(defvar *rooms* '())
(defvar *write-rooms* nil)
(defconstant +command-type+ #(say help quit look
rooms make-room make-door teleport
n s e w
u d password shutdown))
(defconstant +name-prompt+ "Please enter your character name:")
(defconstant +rdb+ "room.tam")
(defconstant +adb+ "avatar.tam")
(defun first-substr (s)
"Return the first substring of s (delimited by a space)."
(block result-first-substr
(do ((i 0 (+ i 1)))
((>= i (length s)) s)
(if (char= (elt s i) #\space)
(return-from result-first-substr (subseq s 0 i))))))
(defun rest-substr (s)
"Return the second part of s."
(block result-rest-substr
(let ((b nil))
(do ((i 0 (+ i 1)))
((>= i (length s)) "")
(if (char= (elt s i) #\space)
(setq b t)
(if b
(return-from result-rest-substr (subseq s i (length s)))))))))
(defun command (s)
(block result-command
(do ((i 0 (+ i 1)))
((>= i (length +command-type+)) 'say)
(let ((c (elt +command-type+ i)))
(if (string= s (symbol-name c))
(return-from result-command c))))))
(defun format-name (c)
(concatenate 'string +bold+ (name (avatar c)) +unbold+))
(defun say (c s)
(if (g c)
(format (socket c) "~A~%" s)))
(defun broadcast (s)
(do ((cs *connections* (cdr cs)))
((null cs))
(let ((c (car cs)))
(say c s))))
(defun say (r s)
(do ((cs *connections* (cdr cs)))
((null cs))
(let ((c (car cs)))
(if (eq (curr-room c) r)
(say c s)))))
(defun look (c)
(say c (concatenate 'string "Room: " (name (curr-room c))))
(do ((ds (desc (curr-room c)) (cdr ds)))
((null ds))
(let ((d (car ds)))
(say c (line d))))
(say c "")
(say c "Exits:")
(do ((i 0 (+ i 1)))
((>= i (length +vd-type+)))
(let ((e (elt (exits (curr-room c)) i)))
(if (not (null e))
(say c (concatenate 'string " " (symbol-name (elt +vd-type+ i)) " " (name e))))))
(say c "Avatars:")
())
;; TODO: Use the reader, for prototype at least?
;; Can switch to postmodern for production.
(defun read-room-database ()
(setq *rooms* '())
(with-open-file (file +rdb+ :direction :input)
(flet ((read-desc ()
(let ((ls '()))
(do ((l (read-line file) (read-line file)))
((string= l ".") ls)
(setq ls (cons l ls)))))
(skip-lines (n)
(do ((i 0 (+ i 1)))
((> i n))
(read-line file))))
(do ((name (read-line file nil nil))
(desc (read-desc)))
((or (null name) (null desc)))
(skip-lines (length +vd-type+))
(let ((r (make-instance (find-class '<room>))))
(setf (name r) name)
(setf (desc r) desc)
(setq *rooms* (cons r *rooms*))))
(file-position file 0)
())))
(defmethod print-object ((obj <room>) stream)
(flet ((write-desc (ds)
(mapcar (lambda (l)
(format stream "~A~%" l))
ds))
(write-exits (es)
(do ((i 0 (+ i 1)))
((> i (length +vd-type+)))
(if (null (elt es) i)
(format stream "nil~%")
(format stream "~A~%" (name (elt es i)))))))
(format stream "~A~%" (name r))
(write-desc (desc r))
(format stream ".~%")
(write-exits (exits r))))
(defun write-room-database ()
(with-open-file (file +rdb+ :direction output)
(mapcar (lambda (r) (print-object r file)) *rooms*))
(setq *write-rooms* nil))
(defun read-avatar-database ()
(setq *avatars* '())
(with-open-file (file +adb+ :direction :input)
(do ((name (read-line file nil nil))
(password (read-line file nil nil)))
((or (null name) (null password)))
(let ((a (make-instance (find-class '<avatar>))))
(setf (name a) name)
(setf (password a) password)
(setq *avatars* (cons a *avatars*)))))
(setq *write-avatars* nil))
(defmethod print-object ((obj <avatar>) stream)
(format stream "~A~%~A~%" (name a) (password a)))
(defun write-avatar-database ()
(with-open-file (file +adb+ :direction output)
(mapcar (lambda (a) (print-object a file)) *avatars*)))
(defun main ()
(read-avatar-database)
(read-room-database)
(while (not *terminate-program*)
(check-for-inputs)))
(provide "ccap-muck")
|