戦闘モジュール2

(let ((tb (make-hash-table :size 7))
    (t-t (list '(0 0) '(0 1) '(0 2)))
    (lim 100)
    (cur 0)
    (pl (list 0 1 2))
    ms act
    (name 0)(tgh 1)(n 2)(x 3)(dur 4)(spd 5)(win 6)(lose 7))
  (make-random-state)
  (setf (gethash 0 tb) (list "John" 20 1 18 1  3 "I'm No.1!!" "Oops!!"))
  (setf (gethash 1 tb) (list "Tosh" 30 2  8 2  6 "I win!!" "Ouch!!"))
  (setf (gethash 2 tb) (list "Keel" 40 5  2 3 11 "I've done!!" "Oh,my..."))
  (while (and (setq act (pop t-t))
        (< cur lim))
  (setq cur (car act))
  (let ((acter (gethash (cadr act) tb))
      (tgl (remove-if (lambda (x) (>= 0 (elt (gethash x tb) tgh))) (remove (cadr act) pl))))
    (if (>= 0 (cadr acter))
      (progn (setq pl (delete (cadr act) pl))
      (push (format nil "~A \"~A\"" (elt acter name) (elt acter lose)) ms))
    (if (>= 0 (length tgl))
      (push (format nil "~A \"~A\"" (elt acter name) (elt acter win)) ms)
      (let ((target (gethash (elt tgl (random (length tgl))) tb))
        (dmg (apply '+ (map 'list #'(lambda (x) (1+ (random x)))
                  (make-sequence 'list (elt acter n) :initial-element (elt acter x))))))
      (push (format nil "~A's attack!! ~A " (car acter) (car target)) ms)
      (if (>= 0 (decf dmg (elt target dur)))
        (push (format nil "deffenced!!") ms)
        (progn (setf (elt target 1) (- (elt target tgh) dmg))
        (push (format nil "got ~A damage!!" dmg) ms)))
      (setq t-t (merge 'list `((,(+ cur (elt acter spd) (random 6)) ,(cadr act)))
               t-t '< :key 'car))
      (push (format nil "  (~A ~A / ~A ~A)"
              (elt acter name) (elt acter tgh)
              (elt target name) (elt target tgh)) ms)))))
  (push (format nil "~%") ms))
  (push (format nil (if (= 1 (length pl)) "~%~A won." "~%time over. drawn game.~*") (car (gethash (car pl) tb))) ms)
  (with-output-to-temp-buffer ("*hoge*" nil) (dolist (m (reverse ms)) (format t "~A" m))))

改良版。パラメータを付けてみた。なかなからしくなってきた。アンテナ対策に書いておくけど、xyzzyで動くLispだよ。

追記

defunして繰り返し動かしたら挙動がおかしかったので修正した。データをquoteで与えていたのが問題。