(ns super-koalio.utils
  (:require [play-clj.core :refer :all]))

(def ^:const vertical-tiles 20)
(def ^:const pixels-per-tile 16)
(def ^:const duration 0.15)
(def ^:const damping 0.5)
(def ^:const max-velocity 14)
(def ^:const max-jump-velocity (* max-velocity 4))
(def ^:const deceleration 0.9)
(def ^:const gravity -2.5)

(defn decelerate
  [velocity]
  ;; not crazy about let using the same var name here
  ;; TODO cleanup and test
  (let [velocity (* velocity deceleration)]
    ;; I guess the idea of damping is to save processor cycles from
    ;; calculating infinitely smaller near-0 speeds.
    (if (< (Math/abs velocity) damping)
      0
      velocity)))

;; utility function for touch screen input; 
(defn touched? 
  [key]
  (and (game :touched?)
       (case key
         :down (< (game :y) (/ (game :height) 3))
         :up (> (game :y) (* (game :height) (/ 2 3)))
         :left (< (game :x) (/ (game :width) 3))
         :right (> (game :x) (* (game :width) (/ 2 3)))
         :center (and (< (/ (game :width) 3) (game :x) (* (game :width) (/ 2 3)))
                      (< (/ (game :height) 3) (game :y) (* (game :height) (/ 2 3))))
         false)))

(defn get-x-velocity
  [{:keys [me? x-velocity]}]
  ;; Accelerate if input being pressed, otherwise return existing
  ;; speed, which will be decelerated by e/move
  (if me?
    (cond
     (or (key-pressed? :dpad-left) (touched? :left))
     (* -1 max-velocity)
     (or (key-pressed? :dpad-right) (touched? :right))
     max-velocity
     :else
     x-velocity)
    x-velocity))

(defn get-y-velocity
  [{:keys [me? y-velocity can-jump?]}]
  (if me? ; ie the playeer
    (cond
     (and can-jump? (or (key-pressed? :dpad-up) (touched? :up))) ; on the ground & pressed jump
     max-jump-velocity
     :else
     y-velocity)
    y-velocity)) ;velocity is subtracted by gravity in e/move

(defn get-direction
  [{:keys [x-velocity direction]}]
  (cond
   (> x-velocity 0) :right
   (< x-velocity 0) :left
   :else ; if stationary, no need to turn around.
   direction))

(defn get-touching-tile
  [screen {:keys [x y width height]} & layer-names]
  ; tiled-map-layer Returns a TiledMapTileLayer from the tiled map in
  ; screen that matches layer-name.
  (let [layers (map #(tiled-map-layer screen %) layer-names)]
    ; Makes a pair of true or nil values (the result of (some))
    ; iterating over the range, saying whether it's a tile or not,
    ; stopping at the first one that is.  The range refers to the
    ; entity's x width and y height, so this means "am I overlapping a
    ; tile of the map, horizontally or vertically
    (->> (for [tile-x (range (int x) (+ x width))
               tile-y (range (int y) (+ y height))]
           (some #(when (tiled-map-cell % tile-x tile-y)
                    [tile-x tile-y])
                 layers))
         (drop-while nil?) ;drop any and all leading nils
         first)))          ;return whether you're left with true or
                           ;nil (this seems like a bit of a precious
                           ;way to test a vector with 2 values in it,
                           ;but why not?)