787 lines
30 KiB
Clojure
787 lines
30 KiB
Clojure
(ns advent.utils
|
|
|
|
(:require [play-clj.core :refer :all]
|
|
[play-clj.ui :refer :all]
|
|
[play-clj.utils :refer :all]
|
|
[play-clj.math :refer :all]
|
|
[play-clj.g2d :refer :all]
|
|
[play-clj.entities :refer [->TextureEntity]]
|
|
[clojure.java.io :as io]
|
|
[clojure.edn :as edn]
|
|
[clojure.tools.logging :as log]
|
|
[clojure.string :as str]
|
|
[advent.saves :as saves]
|
|
[advent.steam :as steam]
|
|
[clojure.core.async :refer [put! <! <!! >! chan go go-loop thread take! alts!! dropping-buffer]])
|
|
(:import [com.badlogic.gdx.graphics Pixmap Pixmap$Format Pixmap$Blending Pixmap$Filter Texture Texture$TextureFilter]
|
|
[com.badlogic.gdx.graphics.g2d TextureRegion Animation]
|
|
[com.badlogic.gdx.utils.viewport FitViewport]
|
|
[com.badlogic.gdx.utils ScreenUtils]
|
|
[com.badlogic.gdx.graphics PixmapIO$PNG]
|
|
[com.badlogic.gdx.scenes.scene2d Actor Stage]
|
|
[com.badlogic.gdx.math CatmullRomSpline]
|
|
[com.badlogic.gdx Application Audio Files Game Gdx Graphics Input
|
|
InputMultiplexer InputProcessor Net Preferences Screen]
|
|
[java.lang Object]))
|
|
|
|
(defn add-actor-to-stage [{:keys [^Stage renderer ui-listeners]} {:keys [^Actor object] :as entity}]
|
|
(.addActor renderer object)
|
|
(doseq [[_ listener] ui-listeners]
|
|
(.addListener ^Actor object listener))
|
|
entity)
|
|
|
|
|
|
(def ui-scale (Double/parseDouble (str (or (System/getProperty "ui_scale") 1.5))))
|
|
(def button-scale (+ 1 (* (- ui-scale 1.0) 2.0)))
|
|
(def mobile? (= 1.5 ui-scale))
|
|
(def max-zoom (if mobile? 0.5 0.75))
|
|
(def min-zoom 0.95)
|
|
(def button-font-scale (if mobile? 0.75 0.5))
|
|
(def title-label-scale (if mobile? 0.5 0.25))
|
|
|
|
(defn clear-stage [{:keys [^Stage renderer]}]
|
|
(.clear renderer))
|
|
|
|
(defn remove-actor-from-stage
|
|
([entities id]
|
|
(do
|
|
(remove-actor-from-stage (id entities))
|
|
(dissoc entities id)))
|
|
([{:keys [^Actor object]}]
|
|
(when object
|
|
(.remove object))))
|
|
|
|
(defn log-coords [screen entities]
|
|
(let [{:keys [x y]} (input->screen screen {:x (:input-x screen) :y (:input-y screen)})]
|
|
(log/info (:input-x screen) (:input-y screen) "->" x y)))
|
|
|
|
(def ^:const +all-cursors+ [:main :wool :mushrooms :carrot :right :down :left :up :flask :flask-with-contents :trophy :ladder :stick :cat-toy :balloon :frog-legs :teddy :portrait :recipe :glass-eye :motivational-tapes :used-earplugs :grass :slobber :flask-with-strength :medal :kiss :sword :hourglass :mandrake :ball-n-chain :key :rope :crowbar :note-1 :ash :sack-lunch :flies :spear :monocle :feather :spell-component :money :charcoal :broken-clock :slingshot :camera :walkie-talkies :alarm-clock :walkie-talkie :flask-water :flask-water-stuff :flask-water-stuff-2 :note-2 :magic-slingshot :active-main :shovel :broom :tune :hand :hand-depressed :talk :talk-depressed :look :look-depressed])
|
|
|
|
(def ^:const +cursor-hotspots+ {:look [8 8]
|
|
:look-depressed [8 8]
|
|
:wool [8 8]
|
|
:mushrooms [8 8]
|
|
:right [8 8]
|
|
:down [8 8]
|
|
:left [8 8]
|
|
:up [8 8]
|
|
:flask [8 8]
|
|
:flask-with-contents [8 8]
|
|
:trophy [8 8]
|
|
:ladder [8 8]
|
|
:stick [8 8]
|
|
:cat-toy [8 8]
|
|
:balloon [3 3]
|
|
:frog-legs [8 8]
|
|
:teddy [8 8]
|
|
:portrait [5 8]
|
|
:recipe [8 8]
|
|
:glass-eye [8 3]
|
|
:motivational-tapes [8 8]
|
|
:used-earplugs [8 8]
|
|
:grass [2 2]
|
|
:slobber [8 8]
|
|
:flask-with-strength [8 8]
|
|
:medal [8 8]
|
|
:kiss [8 8]
|
|
:sword [8 8]
|
|
:hourglass [0 0]
|
|
:mandrake [8 8]
|
|
:ball-n-chain [8 8]
|
|
:key [3 8]
|
|
:rope [8 8]
|
|
:crowbar [0 0]
|
|
:note-1 [8 8]
|
|
:ash [8 10]
|
|
:sack-lunch [8 8]
|
|
:flies [8 8]
|
|
:spear [0 0]
|
|
:monocle [8 8]
|
|
:feather [8 8]
|
|
:spell-component [8 8]
|
|
:money [8 8]
|
|
:charcoal [1 1]
|
|
:broken-clock [8 8]
|
|
:slingshot [8 8]
|
|
:camera [8 8]
|
|
:walkie-talkies [8 8]
|
|
:alarm-clock [8 8]
|
|
:walkie-talkie [8 8]
|
|
:flask-water [8 8]
|
|
:flask-water-stuff [8 8]
|
|
:flask-water-stuff-2 [8 8]
|
|
:note-2 [8 8]
|
|
:magic-slingshot [8 8]
|
|
:active-main [0 0]
|
|
:shovel [8 8]
|
|
:broom [0 0]
|
|
:tune [8 8]
|
|
:hand [3 0]
|
|
:hand-depressed [3 0]
|
|
:talk [8 8]
|
|
:talk-depressed [8 8]})
|
|
|
|
(def settings (atom {:music-volume 50.0
|
|
:sound-volume 75.0
|
|
:camera-man? (not mobile?)
|
|
:fullscreen true}))
|
|
|
|
(defonce selected-save (atom nil))
|
|
|
|
(defn current-music-volume
|
|
(^double [] (current-music-volume 1.0))
|
|
(^double [^double factor]
|
|
(-> (Math/pow (unchecked-multiply (:music-volume @settings) 0.01) 2)
|
|
(unchecked-multiply 0.25)
|
|
(unchecked-multiply (double factor)))))
|
|
|
|
(defn current-sound-volume
|
|
(^double [] (current-sound-volume 1.0))
|
|
(^double [^double factor]
|
|
(-> (Math/pow (unchecked-multiply (:sound-volume @settings) 0.01) 2)
|
|
(unchecked-multiply 0.5)
|
|
(unchecked-multiply (double factor)))))
|
|
|
|
(defn cursor [filename which]
|
|
(let [scale 4
|
|
base-cursor (pixmap filename)
|
|
target-width (* 16 scale)
|
|
target-height (* 16 scale)
|
|
resized (Pixmap. target-width target-height (.getFormat base-cursor))
|
|
index (.indexOf +all-cursors+ which)
|
|
[hot-x hot-y] (+cursor-hotspots+ which [0 0])
|
|
hot-x (int hot-x)
|
|
hot-y (int hot-y)]
|
|
(Pixmap/setFilter Pixmap$Filter/NearestNeighbour)
|
|
(pixmap! resized :draw-pixmap base-cursor (* index 18) 0 16 16
|
|
0 0 target-width target-height)
|
|
|
|
(graphics! :new-cursor resized (* hot-x scale) (* hot-y scale) )))
|
|
(defn atlas->texture
|
|
([atlas path]
|
|
(let [region-name (str/replace path #".png" "")]
|
|
(if-let [region (texture-atlas! atlas :find-region region-name)]
|
|
(texture region)
|
|
(log/error path "not found"))))
|
|
([atlas path index]
|
|
(let [region-name (str/replace path #".png" "")]
|
|
(if-let [region (texture-atlas! atlas :find-region region-name index)]
|
|
(texture region)
|
|
(log/error path index "not found")))))
|
|
|
|
(defn get-texture
|
|
([path]
|
|
(println "WARNING: using pack.atlas:" path)
|
|
(get-texture "packed/pack.atlas" path))
|
|
([atlas path]
|
|
(atlas->texture (texture-atlas atlas) path))
|
|
([atlas path index]
|
|
(atlas->texture (texture-atlas atlas) path index)))
|
|
|
|
|
|
(defn snapshot-list []
|
|
(->> (for [filename (steam/list-edn-files)]
|
|
(try
|
|
(edn/read-string (String. ^bytes (steam/get-bytes filename) "UTF-8"))
|
|
(catch Exception _ nil)))
|
|
(filter (every-pred identity :name :id))
|
|
(sort-by (fn [s]
|
|
(if (= "Autosave" (:name s))
|
|
(Long/MIN_VALUE)
|
|
(- (Long/parseLong (:id s))))))))
|
|
|
|
(defn snapshot-screenshots [atlas]
|
|
(doall (for [snapshot (snapshot-list)]
|
|
(assoc-in snapshot [:screenshot]
|
|
(try (let [bytes (steam/get-bytes (:screenshot snapshot))]
|
|
(texture (Pixmap. ^bytes bytes 0 (count bytes))))
|
|
(catch Exception e
|
|
(atlas->texture atlas (saves/default-screenshot (:state snapshot)))))))))
|
|
|
|
(defn save-chapter [entities chapter]
|
|
(let [prefs (.getPreferences (Gdx/app) "ticks-tales-saves")
|
|
chapters (if (.contains prefs "chapters")
|
|
(edn/read-string (.getString prefs "chapters"))
|
|
saves/chapters)
|
|
chapters (assoc chapters chapter {:state (assoc (entities :state)
|
|
:x (get-in entities [:room :entities :ego :x])
|
|
:y (get-in entities [:room :entities :ego :y]))})]
|
|
(.putString prefs "chapters" (pr-str chapters))
|
|
(.flush prefs)))
|
|
|
|
(defn get-chapters []
|
|
(let [prefs (.getPreferences (Gdx/app) "ticks-tales-saves")]
|
|
(if (.contains prefs "chapters")
|
|
(edn/read-string (.getString prefs "chapters"))
|
|
saves/chapters)))
|
|
|
|
(defn try-times [fn times]
|
|
(first (drop-while #{:fail}
|
|
(repeatedly times
|
|
#(try (fn)
|
|
(catch Exception e
|
|
(log/error "Could not save!" e)
|
|
:fail))))))
|
|
|
|
(defmacro iosify [mobile-version & [regular-version]]
|
|
(if (System/getProperty "is-desktop")
|
|
regular-version
|
|
mobile-version))
|
|
|
|
(def screenshot-chan (chan))
|
|
|
|
(defn publish-screenshot-fn []
|
|
(do
|
|
(log/info "Taking Desktop screenshot...")
|
|
(Pixmap/setFilter Pixmap$Filter/BiLinear)
|
|
(let [viewport (-> @ (resolve 'advent.screens.scene/scene) :screen deref :viewport)
|
|
[x y w h g-l g-r] [(.getScreenX ^FitViewport viewport) (.getScreenY ^FitViewport viewport) (.getScreenWidth ^FitViewport viewport) (.getScreenHeight ^FitViewport viewport)]
|
|
pm (ScreenUtils/getFrameBufferPixmap x y w h)
|
|
resized (Pixmap. 160 120 Pixmap$Format/RGB888)]
|
|
(.drawPixmap resized pm 0 0 (.getWidth pm) (.getHeight pm) 0 0 160 120)
|
|
(.dispose pm)
|
|
(fn [] resized))))
|
|
|
|
|
|
(defn save [entities id name & [blurb]]
|
|
(let [save-fn (fn []
|
|
(log/info "Saving " id name)
|
|
(let [save {:name name
|
|
:id id
|
|
:screenshot (steam/save-screenshot-file-name id)
|
|
:state (assoc (entities :state)
|
|
:x (get-in entities [:room :entities :ego :x])
|
|
:y (get-in entities [:room :entities :ego :y]))
|
|
:blurb (or blurb name)}]
|
|
|
|
(log/info "writing save file...")
|
|
(steam/write-bytes (steam/save-file-name id) (.getBytes (pr-str save) "UTF-8"))
|
|
(iosify
|
|
nil
|
|
(on-gl (let [gl-func (fn []
|
|
(log/info "Screenshot captured. Publishing for persistence")
|
|
(put! screenshot-chan [id (publish-screenshot-fn)]))]
|
|
(try-times gl-func 3)) ))))]
|
|
(try-times save-fn 3)))
|
|
|
|
(defn listen-for-screenshots []
|
|
(go-loop [[id ss-fn] (<! screenshot-chan)]
|
|
(let [screenshot (ss-fn)]
|
|
(log/info "Persisting Screenshot id" id)
|
|
(steam/save-screenshot screenshot (steam/save-screenshot-file-name id))
|
|
(.dispose screenshot)
|
|
(recur (<! screenshot-chan)))))
|
|
|
|
(defn remove-save [id]
|
|
(doseq [f [(steam/save-screenshot-file-name id)
|
|
(steam/save-file-name id)]]
|
|
(steam/delete-file f) ))
|
|
|
|
(defn save-settings! []
|
|
(doto (.getPreferences (Gdx/app) "ticks-tales-saves")
|
|
(.putString "settings" (pr-str @settings))
|
|
.flush))
|
|
|
|
(defn has-saved-settings? []
|
|
(-> (.getPreferences (Gdx/app) "ticks-tales-saves")
|
|
(.contains "settings")))
|
|
|
|
(defn load-settings! []
|
|
(reset! settings
|
|
(-> (.getPreferences (Gdx/app) "ticks-tales-saves")
|
|
(.getString "settings")
|
|
edn/read-string)))
|
|
|
|
(defn get-font [filename]
|
|
(let [font (-> (bitmap-font filename)
|
|
#_(doto (bitmap-font! :set-font-scale 0.5 0.5)))
|
|
tr (bitmap-font! font :get-region)
|
|
tx (.getTexture tr)]
|
|
(call! ^Texture tx :set-filter Texture$TextureFilter/Linear Texture$TextureFilter/Linear)
|
|
font))
|
|
|
|
(def +screen-width+ 320)
|
|
(def +screen-height+ 240)
|
|
|
|
(defn scaler-fn-with-baseline [baseline minimum-size & [maximum-size]]
|
|
(let [maximum-size (or maximum-size 1.0)]
|
|
(fn [[_ y]]
|
|
(if (< y baseline) maximum-size
|
|
(let [percent-complete (- 1.0 (/ (- y baseline) (- +screen-height+ baseline)))
|
|
range (+ (* percent-complete (- maximum-size minimum-size)) minimum-size)]
|
|
range)))))
|
|
|
|
(defn get-scale-value [image x y]
|
|
(let [base-y (Math/floor (- 240 y))
|
|
other-y (Math/ceil (- 240 y))
|
|
base-amount (- y (Math/floor y))
|
|
other-amount (- 1.0 base-amount)
|
|
base-v (-> image
|
|
(pixmap! :get-pixel x base-y)
|
|
color
|
|
(.r))
|
|
other-v (-> image
|
|
(pixmap! :get-pixel x other-y)
|
|
color
|
|
(.r))]
|
|
(+ (* base-v base-amount)
|
|
(* other-v other-amount))))
|
|
|
|
(defn scaler-fn-from-image [image minimum-size maximum-size]
|
|
(let [image (pixmap image)
|
|
maximum-size (or maximum-size 1.0)]
|
|
(fn [[x y]]
|
|
(let [percent-complete (get-scale-value image x y)]
|
|
(if (< y 0)
|
|
maximum-size
|
|
(+ (* percent-complete (- maximum-size minimum-size)) minimum-size))))))
|
|
|
|
(defn dist [x1 y1 x2 y2 & {:keys [y-sign x-sign]}]
|
|
(let [y-sign (or y-sign 1.0)
|
|
x-sign (or x-sign 1.0)
|
|
dx (* (- x1 x2) x-sign)
|
|
dy (* y-sign (- y1 y2))]
|
|
(Math/sqrt (+ (* dx dx) (* dy dy)))))
|
|
|
|
|
|
(defn flip [^Animation anim]
|
|
(animation (animation! anim :get-frame-duration)
|
|
(for [src-frame (animation! anim :get-key-frames)
|
|
:let [frame (texture (texture! src-frame :get-texture))]]
|
|
(do
|
|
(texture! frame :set-region ^TextureRegion src-frame)
|
|
(texture! frame :flip true false)
|
|
frame))))
|
|
|
|
(defn split-texture
|
|
([file [^int tile-width ^int tile-height] frames]
|
|
(let [sheet (get-texture file)
|
|
sheet-obj ^TextureRegion (:object sheet)
|
|
width ^int (int (.getRegionWidth sheet-obj))
|
|
x ^int (int (.getRegionX sheet-obj))
|
|
y ^int (int (.getRegionY sheet-obj))]
|
|
(for [frame frames
|
|
:let [new-tex ^TextureRegion (TextureRegion. sheet-obj)]]
|
|
(do
|
|
(.setRegion new-tex
|
|
^int (unchecked-add x (unchecked-multiply tile-width frame))
|
|
y
|
|
tile-width
|
|
tile-height)
|
|
(->TextureEntity new-tex)))))
|
|
|
|
([atlas file [^int tile-width ^int tile-height] frames]
|
|
(let [sheet (atlas->texture atlas file)
|
|
sheet-obj ^TextureRegion (:object sheet)
|
|
width ^int (int (.getRegionWidth sheet-obj))
|
|
x ^int (int (.getRegionX sheet-obj))
|
|
y ^int (int (.getRegionY sheet-obj))]
|
|
(for [frame frames
|
|
:let [new-tex ^TextureRegion (TextureRegion. sheet-obj)]]
|
|
(do
|
|
(.setRegion new-tex
|
|
^int (unchecked-add x (unchecked-multiply tile-width frame))
|
|
y
|
|
tile-width
|
|
tile-height)
|
|
(->TextureEntity new-tex))))))
|
|
|
|
(defn make-anim
|
|
([file [w h] speed frames]
|
|
(animation speed (split-texture file [w h] frames)))
|
|
([atlas file [w h] speed frames]
|
|
(animation speed (split-texture atlas file [w h] frames))))
|
|
|
|
|
|
(defn make-bird [screen global-atlas p]
|
|
(let [bird-sheet (texture! (atlas->texture global-atlas "bird") :split 1 2)
|
|
bird-stand (animation 0.15 (for [i [0 1]]
|
|
(aget bird-sheet 0 i)))]
|
|
(assoc (animation->texture screen bird-stand)
|
|
:x 0
|
|
:y 0
|
|
:baseline 21
|
|
:anim bird-stand
|
|
:anim-start 0
|
|
:path (catmull-rom-spline (map #(apply vector-2* %) p) true)
|
|
:update-fn (fn [screen entities entity]
|
|
(let [speed 0.05
|
|
pos-f (- (* (:total-time screen) speed) (int (* (:total-time screen) speed)))
|
|
v (vector-2 0 0)
|
|
a (catmull-rom-spline! ^CatmullRomSpline (:path entity) :value-at v pos-f)]
|
|
(assoc entity :x (vector-2! v :x) :y (vector-2! v :y)))))))
|
|
|
|
(defn path-point [speed screen entities entity]
|
|
(* (- (:total-time screen) (:path-start-time entity 0.0)) speed))
|
|
|
|
(defn update-path-location [speed screen entities entity]
|
|
(if (:path entity)
|
|
(let [entity (assoc entity :path-start-time (or (:path-start-time entity) (:total-time screen)))
|
|
pos-f (- (path-point speed screen entities entity) (int (* (- (:total-time screen) (:path-start-time entity 0.0)) speed)))
|
|
v (vector-2 0 0)
|
|
a (catmull-rom-spline! ^CatmullRomSpline (:path entity) :value-at v pos-f)]
|
|
(assoc entity :x (vector-2! v :x) :y (vector-2! v :y) ))
|
|
entity))
|
|
|
|
(defn find-override [entities [x y]]
|
|
(first (concat (filter #(and ((:mouse-in? %) entities x y)
|
|
|
|
(:override %))
|
|
(-> entities :room :interactions))
|
|
(filter #(and (:mouse-in? %)
|
|
((:mouse-in? %) entities x y)
|
|
(not= "ego" (:id %))
|
|
(:get-script %))
|
|
(vals (-> entities :room :entities)))
|
|
(filter #(and ((:mouse-in? %) entities x y)
|
|
(:get-script %))
|
|
(-> entities :room :interactions)))))
|
|
|
|
(defn hovering-ego [entities [x y]]
|
|
(when-let [mouse-in (-> entities :room :entities :ego :mouse-in?)]
|
|
(mouse-in entities x y)))
|
|
|
|
(defn remove-interaction [entities id]
|
|
(update-in entities [:room :interactions] (fn [i] (remove #(= id (:id %)) i))))
|
|
|
|
|
|
(defn play-music [snd]
|
|
(music! snd :play))
|
|
|
|
(defn stop-music [snd]
|
|
(music! snd :stop))
|
|
|
|
(defn make-music [r]
|
|
(log/info "making music from" r)
|
|
(try
|
|
(if mobile?
|
|
(doto (music (str r ".mp3")) (music! :set-looping true))
|
|
(doto (music r) (music! :set-looping true)))
|
|
|
|
(catch Exception x
|
|
(log/warn "music making error" x)
|
|
|
|
(doto (music (str r ".mp3")) (music! :set-looping true)))))
|
|
|
|
(defn load-sound [f]
|
|
(try
|
|
(iosify
|
|
(sound (str f ".mp3"))
|
|
(sound f))
|
|
(catch Exception e
|
|
(log/info e)
|
|
(sound (str f ".mp3")))))
|
|
|
|
|
|
|
|
(defn apply-tweens [screen entities tweens]
|
|
(reduce (fn [e f]
|
|
(f e (:total-time screen)))
|
|
entities
|
|
(vals tweens)))
|
|
|
|
(defn intersects? [e [x y]]
|
|
(when (:object e)
|
|
(let [object-width (* (:scale-x e 1.0) (or (:intersect-width e) (:width e) (when (actor? e ) (.getWidth ^Actor (:object e))) 0))
|
|
object-height (* (:scale-y e 1.0) (or (:intersect-height e) (:height e) (when (actor? e ) (.getHeight ^Actor (:object e))) 0))
|
|
origin-x (* (:scale-x e 1.0) (:origin-x e 0))
|
|
origin-y (* (:scale-y e 1.0) (:origin-y e 0))
|
|
object-x (- (or (:x e) (when (actor? e ) (.getX ^Actor (:object e))) 0) origin-x)
|
|
object-y (- (or (:y e) (when (actor? e ) (.getY ^Actor (:object e))) 0) origin-y)]
|
|
|
|
(and (:object e)
|
|
(< object-x x (+ object-x object-width))
|
|
(< object-y y (+ object-y object-height))))))
|
|
|
|
(defn get-current-music [entities]
|
|
(let [time (get-in entities [:state :time])
|
|
musics (:musics entities)
|
|
override-music (musics (get-in entities [:music-override :value]))
|
|
current-music (musics (get-in entities [:room :music]))
|
|
current-time-music (musics (get-in entities [:room :music time]))]
|
|
(or override-music current-music current-time-music)))
|
|
|
|
|
|
(defn setup-viewport [screen width height]
|
|
(let [cam (or (:cam screen) (orthographic))
|
|
viewport (FitViewport. width height cam)
|
|
stage (Stage. viewport)]
|
|
(update! screen :renderer stage :viewport viewport :camera cam)
|
|
(.apply viewport)
|
|
(assoc screen :renderer stage :viewport viewport :camera cam)))
|
|
|
|
(defn unproject
|
|
([screen options]
|
|
(unproject screen options [(:input-x options) (:input-y options)]) )
|
|
([screen options [x y]]
|
|
(let [pj (.unproject ^FitViewport (:viewport screen) (vector-2 x y))
|
|
x (.x pj)
|
|
y (.y pj)]
|
|
[x y])))
|
|
|
|
(defn project
|
|
([screen [x y]]
|
|
(let [pj (.project ^FitViewport (:viewport screen) (vector-2 x y))
|
|
x (.x pj)
|
|
y (.y pj)]
|
|
[x y])))
|
|
|
|
(defn contains-point? [x1 y1 width height x y]
|
|
(and (<= x1 x (+ x1 width))
|
|
(<= y1 y (+ y1 height))))
|
|
|
|
(defn is-unstoppable-script-running [screen entities]
|
|
(let [current-action (get-in entities [:fg-actions :current])
|
|
is-script-running (get-in entities [:fg-actions :script-running?])]
|
|
(and is-script-running
|
|
(not (#{:end :none-but-arrow} (or (get-in entities [:fg-actions :last-skip-type]) :end))))))
|
|
|
|
(defn update-override [{:keys [^FitViewport viewport] :as screen} entities options]
|
|
(let [raw-pos (-> entities :cursor :last-pos)
|
|
last-pos (unproject screen options raw-pos)
|
|
mouse-override (find-override entities last-pos)
|
|
out-of-bounds (not (contains-point? (.getScreenX viewport) (.getScreenY viewport)
|
|
(.getScreenWidth viewport) (.getScreenHeight viewport)
|
|
(first raw-pos) (last raw-pos)))
|
|
hovering-ego (hovering-ego entities last-pos)
|
|
current (-> entities :cursor :current)
|
|
entities (assoc-in entities [:label :text] "")
|
|
selected-inventory-item (@(resolve 'advent.screens.scene/get-selected-inventory-item))]
|
|
|
|
(cond
|
|
out-of-bounds
|
|
(update-in entities [:cursor] assoc :override nil :active false )
|
|
|
|
|
|
(not (-> entities :state :active?))
|
|
(-> entities
|
|
(assoc-in [:cursor :override] nil))
|
|
|
|
(is-unstoppable-script-running screen entities)
|
|
(-> entities
|
|
(assoc-in [:cursor :override] :hourglass))
|
|
|
|
(-> entities :state :hud-active?)
|
|
(-> entities
|
|
(assoc-in [:cursor :override] nil)
|
|
(assoc-in [:label :text] ""))
|
|
|
|
(and mouse-override (:only-script mouse-override))
|
|
(-> entities
|
|
(assoc-in [:cursor :override] (:cursor mouse-override))
|
|
(assoc-in [:label :text] (:label mouse-override)))
|
|
|
|
selected-inventory-item
|
|
(-> entities
|
|
(assoc-in [:cursor :override] selected-inventory-item)
|
|
(assoc-in [:label :text] (:label mouse-override)))
|
|
|
|
mouse-override
|
|
(-> entities
|
|
(assoc-in [:cursor :override] (:cursor mouse-override))
|
|
(assoc-in [:label :text] (:label mouse-override)))
|
|
|
|
:else
|
|
(assoc-in entities [:cursor :override] :main))))
|
|
|
|
(def default-night-merge {:r 0.13 :g 0.16 :b 0.61 :multiply-amount 0.5 :hue-amount 0.75})
|
|
(def default-night-merge-sprite {:r 0.13 :g 0.16 :b 0.61 :multiply-amount 0.1 :hue-amount 0.35})
|
|
|
|
(defn clamp-volume [vol]
|
|
(max vol 0.005))
|
|
|
|
(defn proximity-volume [entities [x y] & {:keys [scale]}]
|
|
(-> (max 0.0
|
|
(- 1.0 (/ (dist x y
|
|
(get-in entities [:room :entities :ego :x])
|
|
(get-in entities [:room :entities :ego :y])
|
|
:y-sign 2.0
|
|
:x-sign (/ 1.0 (get-in entities [:room :entities :ego :scale-x])))
|
|
175.0)))
|
|
(* (or scale 1.0))
|
|
(clamp-volume)))
|
|
|
|
(defn fast-forward-particle [p]
|
|
(particle-effect! p :reset)
|
|
(particle-effect! p :start)
|
|
|
|
(particle-effect! p :update 10.0)
|
|
(dotimes [_ 160]
|
|
(particle-effect! p :update 0.2)))
|
|
|
|
(defn os->key []
|
|
(let [os-name (System/getProperty "os.name")]
|
|
(cond
|
|
(or (.startsWith os-name "Linux") (.startsWith os-name "LINUX")) :linux
|
|
(.startsWith os-name "Mac") :mac
|
|
:else :windows)))
|
|
|
|
(defmulti make-windowed os->key)
|
|
(defmulti make-fullscreen os->key)
|
|
(defmulti is-fullscreen? os->key)
|
|
|
|
|
|
(defmethod make-windowed :linux []
|
|
(do
|
|
(log/info "Making windowed 800x600 decorated window")
|
|
(System/setProperty "org.lwjgl.opengl.Window.undecorated", "false")
|
|
(.setFullscreenMode Gdx/graphics (.getDisplayMode Gdx/graphics))))
|
|
|
|
(defmethod make-fullscreen :linux []
|
|
(let [width (-> Gdx/graphics .getDisplayMode .width)
|
|
height (-> Gdx/graphics .getDisplayMode .height)]
|
|
(log/info "Making fullscreen " width "x" height " as undecorated window")
|
|
(System/setProperty "org.lwjgl.opengl.Window.undecorated", "true")
|
|
(.setFullscreenMode Gdx/graphics (.getDisplayMode Gdx/graphics))))
|
|
|
|
(defmethod is-fullscreen? :linux []
|
|
(= "true" (System/getProperty "org.lwjgl.opengl.Window.undecorated")))
|
|
|
|
(defn make-fullscreen-normal []
|
|
(let [width (-> Gdx/graphics .getDisplayMode .width)
|
|
height (-> Gdx/graphics .getDisplayMode .height)]
|
|
(log/info "Making fullscreen " width "x" height " as true fullscreen")
|
|
(.setFullscreenMode Gdx/graphics
|
|
(.getDisplayMode Gdx/graphics))
|
|
(set! (.foregroundFPS (-> (class Gdx/graphics)
|
|
(.getDeclaredField (name "config"))
|
|
(doto (.setAccessible true))
|
|
(.get Gdx/graphics))) 60)))
|
|
|
|
(defn make-windowed-normal []
|
|
(do
|
|
(log/info "Making windowed 1280x960 decorated window")
|
|
(System/setProperty "org.lwjgl.opengl.Window.undecorated", "false")
|
|
(.setWindowedMode Gdx/graphics 1280 960)))
|
|
|
|
(defn is-fullscreen?-normal []
|
|
(.isFullscreen Gdx/graphics))
|
|
|
|
|
|
(defmethod make-windowed :mac [] (make-windowed-normal))
|
|
(defmethod make-fullscreen :mac [] (make-fullscreen-normal))
|
|
(defmethod is-fullscreen? :mac [] (is-fullscreen?-normal))
|
|
|
|
(defmethod make-windowed :windows [] (make-windowed-normal))
|
|
(defmethod make-fullscreen :windows [] (make-fullscreen-normal))
|
|
(defmethod is-fullscreen? :windows [] (is-fullscreen?-normal))
|
|
|
|
(defn set-fullscreen! [val]
|
|
(try
|
|
(if val
|
|
(on-gl (make-fullscreen))
|
|
(on-gl (make-windowed)))
|
|
(on-gl
|
|
(swap! settings assoc :fullscreen val)
|
|
(save-settings!))
|
|
nil
|
|
(catch Exception e
|
|
(log/error e))))
|
|
|
|
(defn toggle-fullscreen! []
|
|
(if (is-fullscreen?)
|
|
(set-fullscreen! false)
|
|
(set-fullscreen! true)))
|
|
|
|
(defn get-sound-pan [x]
|
|
(/ (- x 160 ) 160))
|
|
|
|
(defn sourced-volume-fn [target vol-scale [x y]]
|
|
(fn [entities]
|
|
(if (= target :ego)
|
|
(-> (* (/ (get-in entities [:room :entities :ego :scale-x]) 1.5) 0.9)
|
|
(* (or vol-scale 1.0))
|
|
(clamp-volume))
|
|
(proximity-volume entities [x y] :scale vol-scale))
|
|
))
|
|
|
|
(defn scale-vol-from-fade [entities vol]
|
|
(* vol
|
|
(- 1.0 (get-in entities [:fade :opacity]))))
|
|
|
|
(defn play-sound!
|
|
([screen entities snd volume-fn]
|
|
(play-sound! screen entities snd volume-fn 0.5))
|
|
|
|
([screen entities snd volume-fn pan]
|
|
(play-sound! screen entities snd volume-fn pan :once))
|
|
|
|
([screen entities snd volume-fn pan type]
|
|
(play-sound! screen entities snd volume-fn pan type 1.0))
|
|
|
|
([screen entities snd volume-fn pan type pitch]
|
|
(let [vol (volume-fn entities)
|
|
snd (if (keyword? snd)
|
|
(or (-> entities :room :sounds snd)
|
|
(-> entities :sounds snd))
|
|
snd)
|
|
|
|
sound-id (if (= :once type)
|
|
(sound! snd :play (scale-vol-from-fade entities (current-sound-volume vol)) (or pitch 1.0) pan )
|
|
(sound! snd :loop 0.0 (or pitch 1.0) pan )) ]
|
|
(update-in entities [:current-sounds :value]
|
|
conj {:id sound-id
|
|
:sound snd
|
|
:volume-fn volume-fn
|
|
:type type
|
|
:ends-at (if (= type :once)
|
|
(+ (:total-time screen) 1.0 #_(sound! snd :duration))
|
|
nil)}))
|
|
entities))
|
|
|
|
(defn stop-all-sounds! [entities]
|
|
(doseq [snd (get-in entities [:current-sounds :value] [])]
|
|
(sound! (:sound snd) :stop (:id snd))))
|
|
|
|
(defn translate-depressed [cursor depressed?]
|
|
(if depressed?
|
|
(get {:hand :hand-depressed
|
|
:talk :talk-depressed
|
|
:look :look-depressed} cursor cursor)
|
|
cursor))
|
|
|
|
(defn bound-to-camera [x length zoom]
|
|
(min (- length (* length 0.5 zoom ))
|
|
(max (* length 0.5 zoom )
|
|
x)))
|
|
|
|
(defn get-entity [entities id]
|
|
((:entities (:room entities)) id))
|
|
|
|
(defmacro eager-loop [xs n form]
|
|
`(let [xs# ~xs]
|
|
(if (instance? clojure.lang.Indexed xs#)
|
|
(loop [x# 0]
|
|
(if (< x# (count xs#))
|
|
(let [~n (nth xs# x#)]
|
|
~form
|
|
(recur (inc x#)))))
|
|
(do
|
|
|
|
(loop [[~n & r#] xs#]
|
|
(if (seq r#)
|
|
(do ~form
|
|
nil)
|
|
(do ~form
|
|
(recur r#))))))))
|
|
|
|
|
|
(defn acquire-atlas [{:keys [resources] :as screen :or {resources []}} file]
|
|
(let [atlas (texture-atlas file)]
|
|
(update! screen :resources
|
|
(conj resources file))
|
|
[(assoc screen :resources (conj resources file))
|
|
atlas]))
|
|
|
|
(defn release-resources [screen]
|
|
(doseq [resource (:resources screen)]
|
|
(asset-manager! *asset-manager* :unload resource))
|
|
(update! screen :resources [])
|
|
(app! :log "info"(str "Released resources " (.getDiagnostics *asset-manager*))))
|
|
|
|
(defn make-anim-seq
|
|
([file [w h] speed frames]
|
|
(animation speed (map #(get-texture (str file "-" (inc %) ".png")) frames)))
|
|
([atlas file [w h] speed frames]
|
|
(animation speed (map #(atlas->texture atlas file %) frames))))
|