;------------------------------------------------
; SPACEWARS in AutoLISP   Version 2.0
; Bill Kramer April 1992 CADENCE
; Updated May 1995 for AutoCAD R13 Operations
; AUTOCAD TECH JOURNAL
; Updated Dec 95 by CAD Studio CB
;
; PUBLIC DOMAIN SOFTWARE
; 
; This program is meant to be further hacked for 
; the shear pleasure of it.
;
; No tech support, if it doesn't work on your
; system, well, sorry.  But it has been tested
; on the following platforms:
;
; MS-DOS R12 VGA w/MS-Mouse    Works ok
; MS-DOS R13 VGA w/MS-Mouse    Works ok
; Windows R13 VGA w/MS-Mouse   Did not work
; Windows R12 VGA w/MS-Mouse   Did not work
;------------------------------------------------
; These activities and settings take place while
; the program is loading.
;
(setq Turn_ANG1 (/ PI 20)
      Turn_ANG2 (/ PI 20)
      TURN_TIME 0.000005787 ; increase for 386's
      ;;
      ;;Ship List defines ship abilities
      ;;  Nam   String name of ship type
      ;;  MxV   Maximum Velocity
      ;;  TT    Torpedoes range
      ;;  TC    Torpedoes available
      ;;  TDP   Torpedo destructive power
      ;;  DFP   Defensive field power
      ;;  SIZ   Size of ship [radius]
      ;;  ACC   Accel factor [lower is faster]
      ;;  Turn  Angular turn per command
      ;;
SHIPS (list 
     ;Nam MxV TT  TC  TDP DFP  SIZ  ACC   Turn speed
(list "1" 3.0 35  25  0.6 1.0  1.0  4.0   (/ PI 20))
(list "2" 2.0 70  25  0.8 2.0  1.5  10.0  (/ PI 30))
(list "3" 1.5 100 100 1.1 5.0  2.5  25.0  (/ PI 60))
(list "4" 1.0 100 500 2.1 12.0 5.0  50.0  (/ PI 80))
))

(setvar "CMDECHO" 0)
(setvar "BLIPMODE" 0)
;;
;;Now load the block SPACE which contains
;;definitions for the space ship blocks
;;used in the game.  Blocks S1 through
;;S4 are expected to be defined in
;;block SPACE.  A copy of SPACE.DWG is
;;included in the download ZIP file.
;;
(if (null (tblsearch "BLOCK" "SPACE"))
  (if (findfile "SPACE.DWG")
    (command "_INSERT" 
             "SPACE" 
             (list 0 0 0) 
             1 1 0
             "_ERASE" 
             (entlast) 
             ""
    )
    (alert "Could not find SPACE.DWG seed file!")
  )
)
;
;------------------------------------------------
; Main Program
;------------------------------------------------
(defun C:SW ()
   (SetUpVars) ;;Prepare global variables
   ;;
   (setq GAME_OVER nil  ;;'T when game is done
         GAME_ON 'T     ;;toggle flag
   )
   (prompt "\nBattle start")
   (setvar "COORDS" 0)
   (grtext -2 " SPACE WARS - Bill Kramer")
   ;;
   ;; Main Event Loop
   (while (null GAME_OVER)
         (grtext -1 ;;display ship settings
           (strcat 
             "T1= " (itoa S1_AMMO)
             " D1= " (rtos S1_DEF 2 2)
             " T2= " (itoa S2_AMMO)
             " D2= " (rtos S2_DEF 2 2)))
         ;;
         ;; Get the user keystroke
         (setq KEY (grread 'T))
         ;;
         ;; React to keystroke
         (if KEY (key_action KEY))
         ;;
         ;; Update objects
         (if (null GAME_OVER) (move_action))
   )
   ;;Game Over, clean up the mess...
   ;;
   (command "_REDRAW")
   ;;Get rid of running torpedoes
   (if (and T1_OBJ (entget (last T1_OBJ))) 
       (entdel (last T1_OBJ)))
   (if (and T2_OBJ (entget (last T2_OBJ))) 
       (entdel (last T2_OBJ)))
   (setq T1_OBJ nil T2_OBJ nil
         T1_LIFE -1 T2_LIFE -1)
   ;;
   ;;Get rid of existing ships
   (entdel (last S1_OBJ))
   (entdel (last S2_OBJ))
   ;;
   ;;Report Game Results
   (cond
     ((and (minusp S1_DEF) (minusp S2_DEF))
        (prompt "\nBoth ships destroyed.")
     )
     ((minusp S1_DEF)
        (prompt "\nShip 2 is victorious!")
     )
     ((minusp S2_DEF)
        (prompt "\nShip 1 is victorious!")
     )
   )
   (princ)
)
;
;------------------------------------------------
; Prepare global variables.
;
(defun SETUPVARS ( / P1 P2)
   (prompt "\n\nSPACE WARS!  Bill Kramer 1995")
   (prompt "  Version 2.0  AutoCAD Tech Journal")
   (setq USCALE (/ (getvar "VIEWSIZE") 100.0)
         T1_LIFE -1  ;;No torpedoes running
         T2_LIFE -1  ;;initially.
         T1_OBJ nil
         T2_OBJ nil
   )
   ;;
   ;; Get screen limits from operator
   ;;
   (if (or (null UMIN) (null UMAX))
     (setq
       UMIN 
        (getpoint 
          "\nLower left corner of battle area: ")
       UMAX 
        (getpoint 
          "\nUpper right corner of battle area: ")
     )
   )
   (textscr)
   ;;
   ;;How many users?  Game will auto
   ;;play ship 2 for single user.
   ;;
   (setq N_USERS 
           (getint 
             "\nEnter # of players <1> or 2: ")
   )
   (if (null N_USERS) (setq N_USERS 1))
   (if (or (> N_USERS 2) (< N_USERS 1)) 
      (setq N_USERS 1))
   ;;
   (prompt "\nSPACE WARS!\n\nKeyboard Usage:")
   (prompt "\n\nShip 1: (A) turn to the left")
   (prompt "\n        (S) Thruster burst")
   (prompt "\n        (D) turn to the right") 
   (prompt "\n        (F) fire torpedo")
   (if (= N_USERS 2) (progn
      (prompt "\n\nShip 2: (J) turn to the left")
      (prompt "\n        (K) Thruster burst")
      (prompt "\n        (L) turn to the right") 
      (prompt "\n        (;) fire torpedo")
   ))
   (prompt "\n\nBasic Ship Types:")
   (prompt "\n  1   Quick fighter")
   (prompt "\n  2   Slow fighter")
   (prompt "\n  3   Battle Station")
   (prompt "\n  4   Super Battle Station")
   (initget 0 "1 2 3 4")
   (setq TMP 
     (getkword 
       "\nPick ship 1 type [1..4] <1>: "))
   (if (null TMP) (setq TMP "1"))
   (setq S1_TYP TMP)
   ;;
   (initget 0 "1 2 3 4")
   (setq TMP 
     (getkword 
       "\nPick ship 2 type [1..4] <3>: "))
   (if (null TMP) (setq TMP "3"))
   (setq S2_TYP TMP)
   ;;
   (graphscr)
   (setq P1 (getpoint "\nShip 1 Location: ")
         P2 (getpoint P1 "\n  Orientation: ")
   )
   ;; Define Ship 1 object list containing
   ;; current point, velocity, facing, size
   (setq S1_OBJ 
     (list
       P1
       (/ 
         (* USCALE 
            (cadr (assoc S1_TYP SHIPS))) 
         4.0)
       (angle P1 P2)
       (* USCALE (nth 6 (assoc S1_TYP SHIPS)))
   ))
   ;;
   ;; Insert graphic object for ship
   (command "_INSERT" 
            (strcat "S" S1_TYP) 
            (car S1_OBJ)
            USCALE ""
            (angtos (caddr S1_OBJ)))
   ;; Save entity name on Object list
   (setq S1_OBJ (append S1_OBJ (list (entlast)))
         ;;
         ;;Define ship 1's globals from
         ;;ship list.
         ;;
         ;;Torpedo duration
         TORP1_LIFE (nth 2 (assoc S1_TYP SHIPS))
         ;;Torpedo damage
         TORP1_DMG (nth 4 (assoc S1_TYP SHIPS))
         ;;Defense rating
         S1_DEF (nth 5 (assoc S1_TYP SHIPS))
         ;;Max velocity
         S1_MAXV (* USCALE 
                    (nth 1 (assoc S1_TYP SHIPS)))
         ;;Avaialable ammo
         S1_AMMO (nth 3 (assoc S1_TYP SHIPS))
         ;;Accel factor
         S1_ACC (nth 7 (assoc S1_TYP SHIPS))
         ;;Helm response factor
         Turn_ANG1 (nth 8 (assoc S1_TYP SHIPS))
         ;;Ship type code
         S1_TYP (atoi S1_TYP)
   )
   ;;
   (setq P1 (getpoint "\nShip 2 Location: ")
         P2 (getpoint P1 "\n Orientation: ")
   )
   ;;
   ;;build Ship 2 object and globals as
   ;;in ship 1.
   ;;
   (setq S2_OBJ (list
                  P1
                  (/ (* USCALE 
                        (cadr 
                          (assoc S2_TYP SHIPS))) 
                      4.0)
                  (angle P1 P2)
                  (* USCALE 
                     (nth 6 (assoc S2_TYP SHIPS)))
   ))
   (command "_INSERT" 
            (strcat "S" S2_TYP) 
            (car S2_OBJ)
            USCALE ""
            (angtos (caddr S2_OBJ)))
   (setq S2_OBJ (append S2_OBJ (list (entlast)))
         TORP2_LIFE (nth 2 (assoc S2_TYP SHIPS))
         TORP2_DMG (nth 4 (assoc S2_TYP SHIPS))
         S2_DEF (nth 5 (assoc S2_TYP SHIPS))
         S2_MAXV (* USCALE 
                    (nth 1 (assoc S2_TYP SHIPS)))
         S2_AMMO (nth 3 (assoc S2_TYP SHIPS))
         S2_ACC (nth 7 (assoc S2_TYP SHIPS))
         Turn_ANG2 (nth 8 (assoc S2_TYP SHIPS))
         S2_TYP (atoi S2_TYP)
   )
   (getstring "\n\nPress Enter when ready")
   (graphscr)
)

;------------------------------------------------
; Do what the operator has requested.
;
(defun KEY_ACTION (KEY)
  ;;check to see if auto user input needed.
  (if (and (= N_USERS 1)
           (/= (car KEY) 2)
      )
    ;;Yes it is, do automatic move
    (setq KEY (AUTO_USER KEY))
  )
  ;;Respond to key board input only
  (if (= (car KEY) 2)
    (progn
      ;;convert ASCII code into string
      ;;Note: for speed improvement, do all
      ;;      the tests with integer codes.
      (setq KEY (strcase (chr (cadr KEY))))
      (cond
        ((= KEY "S")
           (Tell_It "\nShip 1: Thruster fire")
           (setq S1_OBJ 
             (Thrust S1_OBJ S1_MAXV S1_ACC)))
        ((= KEY "A")
           (Tell_It "\nShip 1: Turn left")
           (Turn S1_OBJ Turn_ANG1))
        ((= KEY "D")
           (Tell_It "\nShip 1: Turn right")
           (Turn S1_OBJ (* -1 Turn_ANG1)))
        ((= KEY "F")
           (Tell_It "\nShip 1: Fire request")
           (if (and (null T1_OBJ) (> S1_AMMO 0))
              (setq T1_OBJ (fire S1_OBJ 0 4)
                    S1_AMMO (1- S1_AMMO)
                    T1_LIFE TORP1_LIFE)
           ))
        ((= KEY "K")
           (Tell_It "\nShip 2: Thruster fire")
           (setq S2_OBJ 
             (Thrust S2_OBJ S2_MAXV S2_ACC)))
        ((= KEY "J")
           (Tell_It "\nShip 2: Turn left")
           (Turn S2_OBJ Turn_ANG2))
        ((= KEY "L")
           (Tell_It "\nShip 2: Turn right")
           (Turn S2_OBJ (* -1 Turn_ANG2)))
        ((= KEY ";")
           (Tell_It "\nShip 2: Fire request")
           (if (and (null T2_OBJ) (> S2_AMMO 0))
              (setq T2_OBJ 
                      (fire S2_OBJ 
                            (if (= 1 N_USERS) 
                               S2_TYP 
                               0) 
                            2)
                    S2_AMMO (1- S2_AMMO)
                    T2_LIFE TORP2_LIFE)
           ))
        ((= KEY "P")
           (Laser_Fire)
        )
      );;end COND
    )
  )
)
;------------------------------------------------
;
;  MOVE_ACTION  Updates objects on the screen
;
(defun MOVE_ACTION ()
   (setq VMAX (list (cadr S1_OBJ) (cadr S2_OBJ)))
   (if T1_OBJ 
     (setq VMAX (cons (cadr T1_OBJ) VMAX)))
   (if T2_OBJ 
     (setq VMAX (cons (cadr T2_OBJ) VMAX)))
   (setq VMAX (apply 'max VMAX)
         TT (/ VMAX USCALE)  
         RTC (getvar "DATE")
         CNT 0
   )
   (if (not (zerop TT))
     (while (< CNT (1+ (fix TT)))
        (setq S1_OBJ 
                (move_obj S1_OBJ 
                          (/ (cadr S1_OBJ) TT))
              S2_OBJ 
                (move_obj S2_OBJ 
                          (/ (cadr S2_OBJ) TT))
              GAME_ON (hit_miss S1_OBJ S2_OBJ))
        (if (null GAME_ON) 
           (progn
              (prompt "\nCollision!")
              (setq S1_DEF -1.0
                    S2_DEF -1.0
                    GAME_OVER 'T)
           )
        )
        (if (and T1_OBJ 
                 (> T1_LIFE 0) 
                 (null GAME_OVER))
          (progn
            (setq T1_OBJ 
                    (move_obj T1_OBJ 
                              (/ (cadr T1_OBJ) 
                                 TT))
                  T1_LIFE (1- T1_LIFE)
                  GAME_ON 
                    (hit_miss T1_OBJ S2_OBJ))
            (if (null GAME_ON)
              (progn
               (entdel (last T1_OBJ))
               (prompt "\nTopedo hit on Ship 2!")
               (setq S2_DEF (- S2_DEF TORP1_DMG)
                     T1_OBJ nil
                     Turn_ANG2 
                       (- Turn_ANG2 
                          (/ Turn_ANG2 4))
                     S2_ACC (- S2_ACC 
                               (/ S2_ACC 4))
                     T1_LIFE -1)
               (if (minusp S2_DEF) (progn
                  (prompt " DESTROYED!")
                  (setq GAME_OVER 'T)
                 )
                  (setq GAME_ON 'T)
               )
              )
            )
          )
        )
        (if (and T2_OBJ 
                 (> T2_LIFE 0) 
                 (null GAME_OVER))
          (progn
            (setq T2_OBJ 
                    (move_obj T2_OBJ 
                              (/ (cadr T2_OBJ) 
                                 TT))
                  T2_LIFE (1- T2_LIFE)
                  GAME_ON 
                    (hit_miss T2_OBJ S1_OBJ))
            (if (null GAME_ON)
              (progn
                (entdel (last T2_OBJ))
                (prompt "\nShip 1 hit!")
                (setq S1_DEF (- S1_DEF TORP2_DMG)
                      T2_OBJ nil
                      Turn_ANG1 
                         (- Turn_ANG1 
                            (/ Turn_ANG1 4))
                      S1_ACC (- S1_ACC 
                                (/ S1_ACC 4))
                      T1_LIFE -1)
                (if (minusp S1_DEF) (progn
                  (prompt " DESTROYED!")
                  (setq GAME_OVER 'T)
                 )
                  (setq GAME_ON 'T)
                )
              )
            )
          )
        )
        (if (and GAME_ON T1_OBJ T2_OBJ)
           (if (null (hit_miss T1_OBJ T2_OBJ))
              (setq T1_OBJ (entdel (last T1_OBJ))
                    T2_OBJ (entdel (last T2_OBJ))
                    T1_OBJ nil
                    T2_OBJ nil
                    T1_LIFE -1
                    T2_LIFE -1
              )
           )
        )
        (setq CNT (1+ CNT))
        (if (null GAME_ON) (setq CNT (1+ TT)))
        (if (null GAME_OVER) (progn 
           (setq KEY (grread 'T))
           (if KEY (key_action KEY))
        ))
     )
   )
   (while (< (- (getvar "DATE") RTC) TURN_TIME)) 
   (if (zerop S1_AMMO) 
     (Tell_It "\nShip 1 out of ammunition."))
   (if (zerop S2_AMMO) 
     (Tell_It "\nShip 2 out of ammunition."))
   (if (zerop T1_LIFE)
      (progn
        (entdel (last T1_OBJ))
        (torp_expl T1_OBJ)
        (Tell_It "\nTorpedo 1 detonation")
        (setq T1_OBJ nil T1_LIFE -1)
      )
   )
   (if (zerop T2_LIFE)
      (progn
        (entdel (last T2_OBJ))
        (torp_expl T2_OBJ)
        (Tell_It "\nTorpedo 2 detonation")
        (setq T2_OBJ nil T2_LIFE -1)
      )
   )
)
;------------------------------------------------
;
;  Update Thrust vectors for object
;
(defun Thrust (OBJ MAXV VINC)
  (setq V1 (polar (list 0 0) 
                  (caddr OBJ) 
                  (cadr OBJ))
        V2 (polar (list 0 0) 
                  (cdr 
                    (assoc 50 
                      (entget 
                        (last OBJ))))
                  (/ USCALE VINC))
        V1 (mapcar '+ V1 V2)
  )
  (if (> (distance (list 0 0) V1) MAXV)
     (setq V1 (polar (list 0 0) 
                     (angle (list 0 0) V1) 
                     MAXV)))
  (list (car OBJ) 
        (distance (list 0 0) V1)
        (angle (list 0 0) V1)
        (cadddr OBJ)
        (last OBJ)
  )
)
;------------------------------------------------
;
;  TURN an object
;
(defun TURN (OBJ ANG)
  (setq EL (entget (last OBJ))
        EL (subst (cons 50 
                        (+ (cdr (assoc 50 EL)) 
                           ANG))
                  (assoc 50 EL)
                  EL)
  )
  (entmod EL)
)

;------------------------------------------------
; Fire Control
;
(defun FIRE (OBJ TYP CLR)
  (entmake (list 
     (cons 0 "CIRCLE") 
     (cons 8 "0")
     (cons 62 CLR)
     (cons 10 (car OBJ))
     (cons 40 (/ USCALE 2))
  ))
  (setq EL (entget (entlast)))
  (list (cdr (assoc 10 EL))
        (* USCALE 5)
        (if (< TYP 3)
          ;;user control and smaller ships
          ;;support front fire only.
          (cdr (assoc 50 (entget (last OBJ))))
          ;;auto-ship classes 3 & 4 support
          ;;omni-directional firing.
          (angle (car S2_OBJ) (car S1_OBJ))
        )
        USCALE
        (entlast)
  )
)

;------------------------------------------------
;
;  hit_miss determination
;  return 'T if miss, nil if hit.
;
(defun HIT_MISS (M_OBJ T_OBJ)
  (setq DD (distance (car M_OBJ) (car T_OBJ)))
  (if (and (> DD 
              (+ (cadddr M_OBJ) 
                 (cadddr T_OBJ))) 
           GAME_ON
      )
     'T ;; No hit
     (explosion M_OBJ) ;;hit
  )
)

;------------------------------------------------
;
(defun EXPLOSION (OBJ / CNT)
  (setq CNT 0.5)
  (repeat 10
     (entmake (list 
       (cons 0 "CIRCLE") 
       (cons 8 "0") 
       (cons 62 1) 
       (cons 10 (car OBJ))
       (cons 40 (* CNT USCALE))
     ))
     (setq EN (entlast))
     (repeat 11
       (entdel EN))
     (setq CNT (+ CNT 0.5))
  )
  nil
)
;------------------------------------------------
(defun TORP_EXPL (OBJ / CNT)
  (setq CNT 0.5)
  (repeat 2
     (entmake (list 
       (cons 0 "CIRCLE") 
       (cons 8 "0") 
       (cons 62 1) 
       (cons 10 (car OBJ))
       (cons 40 (* CNT USCALE))
     ))
     (setq EN (entlast))
     (repeat 5
       (entdel EN))
     (setq CNT (+ CNT 0.5))
  )
  nil
)

;------------------------------------------------
;
(defun MOVE_OBJ (OBJ FAR / P1 EL)
   (setq P1 (polar (car OBJ) (caddr OBJ) FAR))

   (if (< (car P1) (car UMIN)) 
      (setq P1 (list (car UMAX) (cadr P1) 0.0)))
   (if (< (cadr P1) (cadr UMIN)) 
      (setq P1 (list (car P1) (cadr UMAX) 0.0)))
   (if (> (car P1) (car UMAX)) 
      (setq P1 (list (car UMIN) (cadr P1) 0.0)))
   (if (> (cadr P1) (cadr UMAX)) 
      (setq P1 (list (car P1) (cadr UMIN) 0.0)))
   (if (or (= (length P1) 2) 
           (/= (caddr P1) 0.000))
      (setq P1 (list (car P1) (cadr P1) 0.0)))
   (setq EL (entget (last OBJ))
         EL (subst (cons 10 P1) (assoc 10 EL) EL)
   )
   (entmod EL)
   (cons P1 (cdr OBJ))
)
;------------------------------------------------
; Laser Fire
;
(defun LASER_FIRE ()
   (grdraw (car S2_OBJ) (car S1_OBJ) 1)
   (prompt "\nShip 2: Laser Fire - power=")
   (setq AA (angle (car S2_OBJ) 
                   (car S1_OBJ))
         DD (/ 
               (distance 
                 (car S2_OBJ) 
                 (car S1_OBJ)) 
               USCALE)
         DD (/ S2_TYP (* DD DD))
         S1_DEF (- S1_DEF DD)
   )
   (princ DD)
   (if (< S1_DEF 0.0) (progn
      (prompt "\nShip 1 destroyed!")
      (setq GAME_OVER 'T
            GAME_ON nil
      )
   ))
   (grdraw (car S2_OBJ) (car S1_OBJ) 0)
)
;------------------------------------------------
(defun AUTO_USER (KEY / RAND AA)
   (setq RAND (rtos (getvar "CDATE") 2 8)
         RAND (atoi (substr RAND (strlen RAND)))
         AA (cdr 
              (assoc 50   ;;get facing direction
                (entget 
                  (last S2_OBJ)))) 
   )
   (cond
     ((and (> S2_TYP 2) (< RAND 1)) ;;long range lasers
           (list 2 (ascii "P"))
     )
     ((and (< RAND 4) 
           (null T2_OBJ)  
           (equal (angle (car S2_OBJ) 
                         (car S1_OBJ)) 
                  AA 
                  ;;fuzz factor varies based
                  ;;on ship type.
                  (cond ((= S2_TYP 4) (* PI 2.0))
                        ((= S2_TYP 3) PI)
                        ((= S2_TYP 2) (/ PI 2))
                        ((= S2_TYP 1) (/ PI 4))
                  )
           )
           (< (distance (car S1_OBJ) (car S2_OBJ)) 
              (* 0.75 USCALE TORP2_LIFE))
        )
           (list 2 (ascii ";"))
     )
     ((< RAND 6)  ;;rotate towards enemy
        (if (< (angle (car S2_OBJ) (car S1_OBJ))
               AA)
           (list 2 (ascii "L"))
           (list 2 (ascii "J"))
        )
     )
     ((< RAND 8)  ;;fire Thrusters
        (list 2 (ascii "K"))
     )
     (t KEY)  ;;otherwise do nothing
   )
)
;------------------------------------------------
; Set Game_Tacer to 'T to have prompts appear for
; each keystroke command entered into the system.
;
(defun Tell_It (P)
  (if GAME_TRACER (prompt P))
)
;------------------------------------------------
;
(prompt "\nTurn OFF UNDO system before playing!")
(prompt "\nEnter SW to start battle....")
(princ)

    Source: geocities.com/wpsmoke/acadalisptrng/starwars

               ( geocities.com/wpsmoke/acadalisptrng)                   ( geocities.com/wpsmoke)