
(libload "libc/constants")
(libload "sdl/libsdl")

;; not really a lune lander. Just moving a ship around with the arrow keys
(de lander01 ()
  ;; initialize the SDL subsystem. DONT FORGET THIS!!!
  (sdl-initialize)
  (setq scr (new sdl-screen 640 480 "Lander")) ; open screen
  ;; create background sprite
  (setq bgd (new sdl-sprite scr 0))
  (==> bgd load-frame "moon.png" 0 0 0)
  (==> bgd move 0 0)
  ;; create lem sprite
  (setq ship (new sdl-sprite scr 1))     
  (==> ship load-frame "lem.png" 0 40 35)
  ;; set position of ship
  (setq x 200) (setq y 100)
  ;; create event object
  (setq event (new sdl-event))
  (setq xyk (int-matrix 3))
  (setq stop ())

  (while (not stop)
    (==> scr clear)			; fill image with black
    (==> bgd draw)			; draw moon ground
    (==> event get-arrows xyk)		; read keyboard
    (when (= (xyk 2) @@SDLK_q) (setq stop t)) ; stop when q is pressed
    (setq x (+ x (* 10 (xyk 0))))
    (setq y (+ y (* 10 (xyk 1))))
    (==> ship move x y)			; move ship sprite to position
    (==> ship draw)			; draw ship
    (==> scr flip)			; flip screens
    ))

;; a real lunar lander, but the ship does not rotate
(de lander02 ()
  ;; initialize the SDL subsystem. DONT FORGET THIS!!!
  (sdl-initialize)
  (let* ((scr (new sdl-screen 640 480 "Lander")) ; open screen
	 (bgd (new sdl-sprite scr 0))	; create background sprite
	 (ship (new sdl-sprite scr 1))	; create lem sprite
	 ;; set position, velocity, acceleration of ship
	 (x 200) (y 100) (vx 4) (vy 0) (ax 0) (ay 0)
	 ;; set mass, inverse mass, and deltat of ship
	 (mass 1) (mass-inv (/ 1 mass)) (deltat 0.01)
	 (side-thrust 200)		; set side engine thrust
	 (main-thrust 400)		; set main engine thrust
	 (grav 200)	       ; set gravity coefficient in pixels/s/s
	 (stop ())
	 (event (new sdl-event))
	 (xyk (int-matrix 3))
	 (ground 360))
    (==> bgd load-frame "moon.png" 0 0 0)
    (==> bgd move 0 0)
    (==> ship load-frame "lem.png" 0 40 35)
    (while (not stop)
      (==> scr clear)			; fill image with black
      (==> bgd draw)			; draw moon ground
      (==> event get-arrows xyk)	; read keyboard
      (when (= (xyk 2) @@SDLK_q) (setq stop t))	; stop when q is pressed
      (setq ax (* mass-inv side-thrust (xyk 0))) ; update acceleration 
      (setq ay (+ grav (* mass-inv main-thrust (xyk 1)))) ; update acceleration 
      (setq vx (+ vx (* ax deltat)))	; update velocity
      (setq vy (+ vy (* ay deltat)))	; update velocity
      (setq x  (+ x (* vx deltat)))	; update position
      (setq y  (+ y (* vy deltat)))	; update position
      (when (< x -40) (setq x (+ 640 (- x -40)))) ; wrap around left side
      (when (> x 680) (setq x (+ -40 (- x 640)))) ; wrap around right side
      (when (> y ground)		; bounce on ground
	(setq vy (* -0.5 vy)) 
	(setq vx (* 0.25 vx)) 
	(setq y ground))
      (==> ship move x y)		; move ship sprite to position
      (==> ship draw)			; draw ship
      (==> scr flip)			; flip screens
      (setq deltat :scr:deltat)	; update deltat to time between screen flips
      )))

;; lunar lander: has a shadow and a flame
(de lander03 ()
  ;; initialize the SDL subsystem. DONT FORGET THIS!!!
  (sdl-initialize)
  (let* ((scr (new sdl-screen 640 480 "Lander")) ; open screen
	 (bgd (new sdl-sprite scr 0))	; create background sprite
	 (ship (new sdl-sprite scr 1))	; create lem sprite
	 (flame (new sdl-sprite scr 1))	; create flame sprite
	 (shadow (new sdl-sprite scr 3)) ; create shadow sprite
	 ;; set position, velocity, acceleration of ship
	 (x 200) (y 100) (vx 4) (vy 0) (ax 0) (ay 0)
	 ;; set mass, inverse mass, and deltat of ship
	 (mass 1) (mass-inv (/ 1 mass)) (deltat 0.01)
	 (side-thrust 200)		; set side engine thrust
	 (main-thrust 400)		; set main engine thrust
	 (grav 200)	       ; set gravity coefficient in pixels/s/s
	 (stop ())
	 (event (new sdl-event))
	 (xyk (int-matrix 3))
	 (ground 360))
    (==> bgd load-frame "moon.png" 0 0 0)
    (==> bgd move 0 0)
    ;; put the handle at the center of the sprite (40,35)
    (==> ship load-frame "lem.png" 0 40 35)
    (==> flame load-frame "lem-flame.png" 0 40 35)
    (==> shadow load-frame "lem-shadow.png" 0 40 -6)
    (while (not stop)
      (==> scr clear)			; fill image with black
      (==> bgd draw)			; draw moon ground
      (==> event get-arrows xyk)	; read keyboard
      (when (= (xyk 2) @@SDLK_q) (setq stop t))	; stop when q is pressed
      (setq ax (* mass-inv side-thrust (xyk 0))) ; update acceleration 
      (setq ay (+ grav (* mass-inv main-thrust (xyk 1)))) ; update acceleration 
      (setq vx (+ vx (* ax deltat)))	; update velocity
      (setq vy (+ vy (* ay deltat)))	; update velocity
      (setq x  (+ x (* vx deltat)))	; update position
      (setq y  (+ y (* vy deltat)))	; update position
      (when (< x -40) (setq x (+ 640 (- x -40)))) ; wrap around left side
      (when (> x 680) (setq x (+ -40 (- x 640)))) ; wrap around right side
      (when (> y ground)		; bounce on ground
	(setq vy (* -0.5 vy)) 
	(setq vx (* 0.25 vx)) 
	(setq y ground))
      (==> shadow move x 360)		; move ship sprite to position
      (==> flame move x y)              ; move ship sprite to position
      (==> ship move x y)		; move ship sprite to position
      (==> shadow draw)
      (when (<> 0 (xyk 1)) (==> flame draw)) ; draw flame if engine is on
      (==> ship draw)
      (==> scr flip)			; flip screens
      (setq deltat :scr:deltat)	; update deltat to time between screen flips
      )))


(setq pi/180 (/ 3.1415927 180))

;; lunar lander: the ship rotates, has a shadow and a flame
(de lander04 ()
  ;; initialize the SDL subsystem. DONT FORGET THIS!!!
  (sdl-initialize)
  (let* ((scr (new sdl-screen 640 480 "Lander")) ; open screen
	 (bgd (new sdl-sprite scr 0))	; create background sprite
	 (ship (new sdl-sprite scr 1))	; create lem sprite
	 (flame (new sdl-sprite scr 1))	; create flame sprite
	 (shadow (new sdl-sprite scr 3)) ; create shadow sprite
	 ;; set position, velocity, acceleration of ship
	 (x 200) (y 100) (vx 4) (vy 0) (ax 0) (ay 0)
	 ;; angle of ship
	 (theta 0)
	 ;; set mass, inverse mass, and deltat of ship
	 (mass 1) (mass-inv (/ 1 mass)) (deltat 0.01)
	 (main-thrust 400)		; set main engine thrust
	 (grav 200)	       ; set gravity coefficient in pixels/s/s
	 (stop ())
	 (event (new sdl-event))
	 (xyk (int-matrix 3))
	 (ground 360))
    (==> bgd load-frame "moon.png" 0 0 0)
    (==> bgd move 0 0)
    ;; put the handle at the center of the sprite (40,35)
    (==> ship load-frame "lem.png" 0 40 35)
    (==> flame load-frame "lem-flame.png" 0 40 35)
    (==> shadow load-frame "lem-shadow.png" 0 40 -6)
    ;; fill up frames with rotated lems
    (let ((i 1))
      ;; make an image every 10 degrees from 10 to 350
      (for (angle 10 350 10)
	   ;; take frame 0, rotate by angle, scale by 1, 
	   ;; and copy into frame i
	   (==> ship rotscale-frame 0 i angle 1)
	   ;; same for flame
	   (==> flame rotscale-frame 0 i angle 1)
	   (incr i)))
    (while (not stop)
      (==> scr clear)			; fill image with black
      (==> bgd draw)			; draw moon ground
      (==> event get-arrows xyk)	; read keyboard
      (when (= (xyk 2) @@SDLK_q) (setq stop t))	; stop when q is pressed
      (when (= (xyk 2) @@SDLK_f) (==> scr toggle-fullscreen))
      ;; update the angle from the left-right arrow keys
      (setq theta (+ theta (xyk 0)))
      ;; bring the angle back to the 0-360 interval
      (while (>= theta 36) (setq theta (- theta 36)))
      (while (< theta 0) (setq theta (+ theta 36)))
      ;; set frame of ship and flame to one matching the angle
      (==> ship set-frame (int theta))
      (==> flame set-frame (int theta))
      ;; compute x acceleration
      (setq ax (* mass-inv main-thrust (xyk 1) (sin (* pi/180 -10 theta)))) 
      ;; compute y acceleration
      (setq ay (+ grav (* mass-inv main-thrust 
			  (xyk 1) (cos (* pi/180 10 theta)))))
      (setq vx (+ vx (* ax deltat)))	; update velocity
      (setq vy (+ vy (* ay deltat)))	; update velocity
      (setq x  (+ x (* vx deltat)))	; update position
      (setq y  (+ y (* vy deltat)))	; update position
      (when (< x -40) (setq x (+ 640 (- x -40)))) ; wrap around left side
      (when (> x 680) (setq x (+ -40 (- x 640)))) ; wrap around right side
      (when (> y ground)		; bounce on ground
	(setq vy (* -0.5 vy)) 
	(setq vx (* 0.25 vx)) 
	(setq theta 0)
	(setq y ground))
      (==> shadow move x 360)		; move shadow sprite to position
      (==> flame move x y)              ; move flame sprite to position
      (==> ship move x y)		; move ship sprite to position
      ;; now draw sprites in the right order, bottom sprite first
      (==> shadow draw)			; draw shadow
      (when (<> 0 (xyk 1)) (==> flame draw)) ; draw flame if engine is on
      (==> ship draw)			; draw ship
      (==> scr flip)			; flip screens
      (setq deltat :scr:deltat)	; update deltat to time between screen flips
      )))
