915 lines
44 KiB
Clojure
915 lines
44 KiB
Clojure
(ns advent.actions
|
|
(:require [play-clj.core :refer :all]
|
|
[play-clj.ui :refer :all]
|
|
[play-clj.utils :refer :all]
|
|
[play-clj.g2d :refer :all]
|
|
[clojure.pprint]
|
|
[clojure.string :as s]
|
|
[clojure.zip :as zip]
|
|
[clojure.set :as set]
|
|
[advent.pathfind]
|
|
[advent.actions :as actions]
|
|
[advent.screens.dialogue :as dialogue]
|
|
[advent.utils :as utils]
|
|
[advent.tween :as tween]
|
|
[advent.tween :as tween]
|
|
[clojure.core.async :refer [put! <! <!! >! >!! chan go thread take! alts!!]])
|
|
(:import [com.badlogic.gdx.graphics Pixmap Pixmap$Filter Texture Texture$TextureFilter]
|
|
[com.badlogic.gdx.graphics.g2d TextureRegion Animation]
|
|
[com.badlogic.gdx Screen]))
|
|
|
|
(defprotocol IAction
|
|
(begin [this screen entities])
|
|
(done? [this screen entities])
|
|
(continue [this screen entities])
|
|
(terminate [this screen entities])
|
|
(skip-type [this screen entities])
|
|
(get-channel [this]))
|
|
|
|
(defn has-item? [entities item]
|
|
(if (map? entities)
|
|
((set (get-in entities [:state :inventory])) item)
|
|
((set (get-in @entities [:state :inventory])) item)))
|
|
|
|
(defn has-obtained? [entities item]
|
|
(if (map? entities)
|
|
((get-in entities [:state :obtained-items]) item)
|
|
((get-in @entities [:state :obtained-items]) item)))
|
|
|
|
(defn has-obtained-one-of? [entities items]
|
|
(some (partial has-obtained? entities) items))
|
|
|
|
(defn has-obtained-all-of? [entities items]
|
|
(every? (partial has-obtained? entities) items))
|
|
|
|
(defn has-one-of? [entities items]
|
|
(if (map? entities)
|
|
(seq (set/intersection (set (get-in entities [:state :inventory])) (set items)))
|
|
(seq (set/intersection (set (get-in @entities [:state :inventory])) (set items)))))
|
|
|
|
(defmacro run-action [entities & forms]
|
|
`(let [c# (chan)]
|
|
(do
|
|
(put! (get-in (deref ~entities) [:actions :channel])
|
|
(reify IAction
|
|
(get-channel [_] c#)
|
|
~@forms))
|
|
(let [result# (<!! c#)]
|
|
(if (= :end result#)
|
|
(do
|
|
(println "ending script")
|
|
(throw (ex-info "User quit script" {:type :end-script})))
|
|
(reset! ~entities result#))))))
|
|
|
|
(defn change-script-state [entities state]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:actions] assoc :script-running? state :last-skip-type (if state :end nil)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
true)
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none-but-arrow)))
|
|
|
|
(defmacro get-script [entities & forms]
|
|
`(fn [starting-entities#]
|
|
(put! (get-in starting-entities# [:actions :script-chan])
|
|
(fn [starting-entities#]
|
|
(let [~entities (atom starting-entities#)]
|
|
(thread (do
|
|
~@forms
|
|
(change-script-state ~entities false)
|
|
(utils/save @~entities))))))))
|
|
|
|
(defmacro get-unsaved-script [entities & forms]
|
|
`(fn [starting-entities#]
|
|
(put! (get-in starting-entities# [:actions :script-chan])
|
|
(fn [starting-entities#]
|
|
(let [~entities (atom starting-entities#)]
|
|
(thread (do
|
|
~@forms
|
|
(change-script-state ~entities false))))))))
|
|
|
|
(defn bound-to-camera [x length zoom]
|
|
(min (- length (* length 0.5 zoom ))
|
|
(max (* length 0.5 zoom )
|
|
x)))
|
|
|
|
(defn pan-to [screen entities x y scale-fn & [ease duration]]
|
|
(let [ease (or ease tween/ease-in-out-quadratic)
|
|
duration (or duration 3.0)
|
|
target-zoom (min 0.95 (max 0.75 (scale-fn [(max 0 (min 319 x)) (max 0 (min 240 y))])))
|
|
current-zoom (get-in entities [:cam :zoom] 1.0)
|
|
|
|
;; don't zoom if it's a subtle difference
|
|
target-zoom (if (< (Math/abs (- target-zoom current-zoom))
|
|
0.07)
|
|
current-zoom
|
|
target-zoom)
|
|
target-x (bound-to-camera x 320 target-zoom)
|
|
target-y (bound-to-camera y 240 target-zoom)]
|
|
(if (and (or (not= target-x (get-in entities [:cam :x]))
|
|
(not= target-y (get-in entities [:cam :y]))
|
|
(not= target-zoom (get-in entities [:cam :zoom])))
|
|
(not (get-in entities [:cam :paused?])))
|
|
(-> entities
|
|
(assoc-in [:tweens :cam-zoom]
|
|
(tween/tween :cam-zoom screen
|
|
[:cam :zoom]
|
|
(get-in entities [:cam :zoom] 1.0)
|
|
target-zoom
|
|
duration
|
|
:ease ease))
|
|
(assoc-in [:tweens :cam-x]
|
|
(tween/tween :cam-x screen
|
|
[:cam :x]
|
|
(get-in entities [:cam :x] 160.0)
|
|
target-x
|
|
duration
|
|
:ease ease))
|
|
(assoc-in [:tweens :cam-y]
|
|
(tween/tween :cam-y screen
|
|
[:cam :y]
|
|
(get-in entities [:cam :y] 120.0)
|
|
target-y
|
|
duration
|
|
:ease ease)))
|
|
entities)))
|
|
|
|
(defn jump-to [screen entities entity [x y] update-baseline?]
|
|
(let [scale-fn (-> entities :room :scale-fn)
|
|
entity (assoc entity :x x :y y)
|
|
entity (if update-baseline?
|
|
(assoc entity :baseline (- 240 y))
|
|
entity)]
|
|
(if (:scaled entity)
|
|
(assoc entity :scale-x (scale-fn [x y]) :scale-y (scale-fn [x y]))
|
|
entity)))
|
|
|
|
(defn find-animation [entity anim]
|
|
(if (instance? Animation anim)
|
|
anim
|
|
(or (get-in entity [(:facing entity) anim])
|
|
(get entity anim))))
|
|
|
|
(defn start-animation
|
|
([entity anim]
|
|
(start-animation {:total-time 0} entity anim))
|
|
([screen entity anim]
|
|
(let [new-anim (find-animation entity anim)]
|
|
(if (and anim (not= new-anim (:anim entity)))
|
|
(assoc entity
|
|
:anim new-anim
|
|
:anim-start (:total-time screen))
|
|
entity))))
|
|
|
|
(defn stop [screen entities target-id & {:keys [face]}]
|
|
(update-in entities [:room :entities target-id] (comp #(start-animation screen % (or (:stand-override %) :stand) ) (if face #(assoc % :facing face) identity))))
|
|
|
|
(defn do-stop [entities target-id & {:keys [face]}]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities target-id]
|
|
(comp #(start-animation screen % (or (:stand-override %) :stand)) (if face #(assoc % :facing face) identity))))
|
|
(continue [this screen entities] entities)
|
|
(done? [this screen entities] true)
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:skip)))
|
|
|
|
|
|
|
|
(defn walk-straight-to [entities target-id [final-x final-y] & {:keys [update-baseline? face speed anim override-dir stop?]}]
|
|
(let [{start-x :x start-y :y} (get-in @entities [:room :entities target-id])
|
|
final-x (int final-x)
|
|
final-y (int final-y)
|
|
update-baseline? (if (nil? update-baseline?) true update-baseline?)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(if (= :ego target-id)
|
|
(pan-to screen entities final-x final-y (get-in entities [:room :scale-fn]))
|
|
entities))
|
|
|
|
(continue [this screen entities]
|
|
(let [{from-x :x from-y :y :keys [left right scale-x] :as target-entity} (get-in entities [:room :entities target-id])]
|
|
(let [delta-x (- final-x from-x)
|
|
delta-y (- final-y from-y)
|
|
distance (utils/dist from-x from-y final-x final-y)
|
|
speed (* (or scale-x 1.0) (or speed 1.5))
|
|
speed (* speed
|
|
(/ (:delta-time screen)
|
|
(/ 1.0 60.0)))
|
|
moved-x (if (= 0.0 distance)
|
|
0
|
|
(* speed (/ delta-x distance)))
|
|
moved-y (if (= 0.0 distance)
|
|
0
|
|
(* speed (/ delta-y distance)))]
|
|
(if (< distance speed)
|
|
(-> entities
|
|
(assoc-in [:room :entities target-id :x] final-x)
|
|
(assoc-in [:room :entities target-id :y] final-y))
|
|
(update-in entities [:room :entities target-id]
|
|
#(start-animation screen
|
|
(assoc (jump-to screen entities % [(+ moved-x from-x) (+ moved-y from-y)] update-baseline?)
|
|
:facing (or override-dir (cond (< delta-x 0) :left
|
|
(> delta-x 0) :right
|
|
:else (:facing %))))
|
|
(or anim :walk)
|
|
))))))
|
|
|
|
(done? [this screen entities]
|
|
(let [{from-x :x from-y :y :keys [left right anim] :as target-entity} (get-in entities [:room :entities target-id])]
|
|
(< (utils/dist final-x final-y from-x from-y) 1)))
|
|
|
|
(terminate [this screen entities]
|
|
(if (or (nil? stop?) stop?)
|
|
(stop screen entities target-id :face face)
|
|
entities))
|
|
(skip-type [this screen entities]
|
|
:none))))
|
|
|
|
(defn play-animation [entities target-id anim & {:keys [stop? continue?]}]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities target-id] #(start-animation screen % anim) ))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(animation! (find-animation (get-in entities [:room :entities target-id ]) anim)
|
|
:is-animation-finished
|
|
(- (:total-time screen) (get-in entities [:room :entities target-id :anim-start]))))
|
|
|
|
(terminate [this screen entities]
|
|
(if continue?
|
|
entities
|
|
(if (or (nil? stop?) stop?)
|
|
(stop screen entities target-id)
|
|
(assoc-in entities [:room :entities target-id :anim] nil))))
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn update-entity [entities target-id f]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities target-id] f))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities] entities)
|
|
(skip-type [this screen entities] :none)))
|
|
|
|
(defn stop-walking [entities target-id & {:keys [face]}]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(stop screen entities target-id :face face))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities] entities)
|
|
(skip-type [this screen entities] :none)))
|
|
|
|
(defn walk-to [entities target-id [final-x final-y] & {:keys [skip-type face force-dir stop?] :or {stop? true}}]
|
|
(let [{start-x :x start-y :y} (get-in @entities [:room :entities target-id])
|
|
final-x (int final-x)
|
|
final-y (int final-y)
|
|
path (vec (take-nth 5 (advent.pathfind/visit-all
|
|
(:collision (:room @entities))
|
|
[(int start-x) (int start-y)]
|
|
[final-x final-y])))
|
|
path (if (seq path)
|
|
(conj path [final-x final-y])
|
|
[])
|
|
targets-left (atom path)]
|
|
(if (seq path)
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(if (= :ego target-id)
|
|
(pan-to screen entities final-x final-y (get-in entities [:room :scale-fn]))
|
|
entities))
|
|
|
|
(continue [this screen entities]
|
|
(when (= (rand-int 5) 2)
|
|
#_(particle-effect! (:step-particles entities) :start))
|
|
(let [{from-x :x from-y :y :keys [left right scale-x] :as target-entity} (get-in entities [:room :entities target-id])
|
|
[[target-x target-y] remainder] @targets-left]
|
|
(let [delta-x (- target-x from-x)
|
|
delta-y (- target-y from-y)
|
|
distance (utils/dist from-x from-y target-x target-y)
|
|
speed (* (or scale-x 1.0) 1.5)
|
|
speed (* speed
|
|
(/ (:delta-time screen)
|
|
(/ 1.0 60.0)))
|
|
moved-x (if (= 0.0 distance)
|
|
0
|
|
(* speed (/ delta-x distance)))
|
|
moved-y (if (= 0.0 distance)
|
|
0
|
|
(* speed (/ delta-y distance)))]
|
|
(if (< distance speed)
|
|
(do (swap! targets-left rest)
|
|
(-> entities
|
|
(assoc-in [:room :entities target-id :x] target-x)
|
|
(assoc-in [:room :entities target-id :y] target-y)
|
|
(assoc-in [:step-particles :x] target-x)
|
|
(assoc-in [:step-particles :y] target-y)))
|
|
(update-in entities [:room :entities target-id]
|
|
#(start-animation screen
|
|
(assoc (jump-to screen entities % [(+ moved-x from-x) (+ moved-y from-y)] true)
|
|
:facing (cond force-dir force-dir
|
|
(< delta-x 0) :left
|
|
(> delta-x 0) :right
|
|
:else (:facing %)))
|
|
:walk
|
|
))))))
|
|
|
|
(done? [this screen entities]
|
|
(let [{from-x :x from-y :y :keys [left right anim] :as target-entity} (get-in entities [:room :entities target-id])]
|
|
(< (utils/dist final-x final-y from-x from-y) 1)))
|
|
|
|
(terminate [this screen entities]
|
|
(if stop?
|
|
(stop screen entities target-id :face face)
|
|
entities))
|
|
(skip-type [this screen entities]
|
|
(or skip-type :none)))
|
|
(do-stop entities :ego :face face))))
|
|
|
|
(defn get-text-duration [text]
|
|
(max 1.5 (* (count (s/split text #"[ \-]")) 0.5)))
|
|
|
|
(defn talk [entities target-id text & {:keys [stop? animate? anim wait color] :or {wait true}}]
|
|
(let [initial-time (atom nil)
|
|
stop? (if (nil? stop?) true stop?)
|
|
animate? (if (nil? animate?) true animate?)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(let [_ (swap! initial-time #(or % (:total-time screen)))
|
|
target-y (get-in entities [:room :entities target-id :y])
|
|
target-x (get-in entities [:room :entities target-id :x])
|
|
width (or (get-in entities [:room :entities target-id :width])
|
|
(.getRegionWidth (get-in entities [:room :entities target-id :object])))
|
|
origin-x (get-in entities [:room :entities target-id :origin-x])
|
|
target-x (if (nil? origin-x) (+ target-x (/ width 2)) target-x )
|
|
height (or (get-in entities [:room :entities target-id :height])
|
|
(.getRegionHeight (get-in entities [:room :entities target-id :object])))
|
|
scaled (get-in entities [:room :entities target-id :scaled])
|
|
scale-fn (get-in entities [:room :scale-fn])
|
|
scale (get-in entities [:room :entities target-id :scale-y] 1)
|
|
height (* scale height)]
|
|
(screen! dialogue/talking-screen :on-talk :text text
|
|
:scene-viewport (:viewport screen)
|
|
:x target-x :y (+ target-y height)
|
|
:color (or color (get-in entities [:room :entities target-id :talk-color]))
|
|
|
|
:target-id target-id
|
|
:scale scale)
|
|
(if animate?
|
|
(update-in entities [:room :entities target-id ] #(start-animation screen % (or anim (:talk-override %) :talk)))
|
|
entities)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(if wait
|
|
(> (- (:total-time screen)
|
|
@initial-time)
|
|
(get-text-duration text))
|
|
true))
|
|
|
|
(terminate [this screen entities]
|
|
(if wait
|
|
(do
|
|
(screen! dialogue/talking-screen :stop-talk :target-id target-id)
|
|
(if stop?
|
|
(stop screen entities target-id)
|
|
entities))
|
|
entities))
|
|
(skip-type [this screen entities]
|
|
:skip))))
|
|
|
|
(defn something-else [zipper]
|
|
(-> zipper zip/up zip/up))
|
|
|
|
(defn previous-choices [zipper]
|
|
(-> zipper zip/up))
|
|
|
|
(defn nth-child [zipper i]
|
|
(loop [so-far 0
|
|
zipper (zip/down zipper)]
|
|
(if (= so-far i)
|
|
zipper
|
|
(recur (inc so-far) (zip/right zipper)))))
|
|
|
|
(defn make-zipper [tree]
|
|
(zip/zipper map?
|
|
#(apply concat (filter first (partition 2 (:choices %))))
|
|
(fn [n c]
|
|
(assoc n :choices (vec c)))
|
|
tree))
|
|
|
|
(defn present-choices [entities choices]
|
|
(loop [zipper (make-zipper choices)]
|
|
(let [selected-index (atom nil)
|
|
node (zip/node zipper)
|
|
|
|
dialogue-choices (filter first (partition 2 (:choices node)))]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(screen! dialogue/choice-screen :on-present-choices :choices dialogue-choices :callback #(reset! selected-index %))
|
|
(screen! @(resolve 'advent.screens.scene/scene) :on-deactivate)
|
|
(-> entities
|
|
(assoc-in [:cursor :override] nil)
|
|
(assoc-in [:cursor :current] :main)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(not (nil? @selected-index)))
|
|
|
|
(terminate [this screen entities]
|
|
(-> entities
|
|
(assoc-in [:state :active?] true)
|
|
(assoc-in [:cursor :override] nil)))
|
|
(skip-type [this screen entities]
|
|
:none))
|
|
|
|
(let [zipper (nth-child zipper (inc (* 2 @selected-index)))
|
|
node (zip/node zipper)]
|
|
(when-let [run (:run node)]
|
|
(run (-> dialogue-choices
|
|
(nth @selected-index)
|
|
first)))
|
|
(when-let [next-choices (or (when-let [choice-fn (:choice-fn node)]
|
|
(choice-fn))
|
|
(:choices node))]
|
|
(if (fn? next-choices)
|
|
|
|
(recur (next-choices zipper))
|
|
(recur (zip/edit zipper assoc :choices next-choices))))))))
|
|
|
|
(defn update-entities [entities f & {:keys [use-screen?] :or {use-screen? false}}]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(if use-screen?
|
|
(f screen entities)
|
|
(f entities)))
|
|
(continue [this screen entities] entities)
|
|
(done? [this screen entities] true)
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn pause-camera [entities]
|
|
(update-entities entities #(-> %
|
|
(assoc-in [:cam :paused? ] true)
|
|
(update-in [:tweens] dissoc :cam-x :cam-y))))
|
|
|
|
(defn resume-camera [entities]
|
|
(update-entities entities #(assoc-in % [:cam :paused? ] false)))
|
|
|
|
(defn begin-animation [entities target-id anim]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities target-id]
|
|
#(start-animation screen % anim)))
|
|
(continue [this screen entities] entities)
|
|
(done? [this screen entities] true)
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
|
|
|
|
(defn update-state [entities f]
|
|
(update-entities entities #(update-in % [:state] f)))
|
|
|
|
(defn remove-item [entities item]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(-> entities
|
|
(update-in [:state :inventory] #(remove (partial = item) %))
|
|
(assoc-in [:cursor :current] :main)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn play-sound
|
|
([entities sound-file vol & [wait?]]
|
|
(let [wait? (if (nil? wait?) true wait?)
|
|
s (if (string? sound-file)
|
|
(sound sound-file)
|
|
sound-file)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(utils/play-sound! screen entities s (constantly vol)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(if wait?
|
|
(not (seq (filter
|
|
#(= s (:sound %))
|
|
(get-in entities [:current-sounds :value]))))
|
|
true))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))))
|
|
|
|
(defn give [entities item]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(utils/play-sound! screen entities :pickup (constantly 0.3))
|
|
(-> entities
|
|
(update-in [:state :inventory] #(conj % item))
|
|
(update-in [:state :obtained-items] #(conj % item))
|
|
(assoc-in [:cursor :current] ((:all-items entities) item))))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn remove-entity [entities entity]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities] #(dissoc % entity)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities] entities)
|
|
|
|
(skip-type [this screen entities]
|
|
:none )))
|
|
|
|
(defn add-entity [entities id entity]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(update-in entities [:room :entities] #(assoc % id entity)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities] entities)
|
|
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn get-music [music time]
|
|
(if (keyword? music)
|
|
music
|
|
(time music)))
|
|
|
|
(defn transition-music [entities new-music & {:keys [duration between]}]
|
|
(let [current-volume (atom 1.0)
|
|
duration (or duration 2.0)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(assoc-in entities [:tweens :fade-out-music]
|
|
(tween/tween :fade-out-music screen [:volume :value] 1.0 0.0 duration)))
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(nil? (get-in entities [:tweens :fade-out-music])))
|
|
|
|
(terminate [this screen entities]
|
|
(doseq [m (-> entities :musics vals)
|
|
:when m]
|
|
(music! m :stop))
|
|
(let [entities (-> entities
|
|
((or between identity))
|
|
(assoc-in [:music-override :value] new-music)
|
|
(assoc-in [:volume :value] 1.0))]
|
|
(music! (utils/get-current-music entities) :set-volume (utils/current-music-volume))
|
|
(music! (utils/get-current-music entities) :play)
|
|
entities))
|
|
|
|
(skip-type [this screen entities]
|
|
:none))))
|
|
|
|
|
|
(defn transition-background [entities new-background [x y] & {:keys [transition-music? between time face]}]
|
|
(let [transition-music? (if (nil? transition-music?) true transition-music?)
|
|
old-music (get-music (get-in @entities [:room :music]) (get-in @entities [:state :time]))
|
|
new-music (get-music (get-in @entities [:rooms new-background :music]) (get-in @entities [:state :time]))
|
|
music-changed? (and transition-music? (not= old-music new-music))
|
|
time (/ (float (or time 1.0)) 2.0)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(doseq [[k] (get-in entities [:room :timers])]
|
|
(remove-timer! screen k))
|
|
(as-> entities e
|
|
(assoc-in e [:tweens :fade-out] (tween/tween :fade-out screen [:fade :opacity] 0.0 1.0 time))
|
|
(if music-changed?
|
|
(assoc-in e [:tweens :fade-out-music] (tween/tween :fade-out-music screen [:volume :value] 1.0 0.0 time))
|
|
e)
|
|
(assoc-in e [:cursor :current] :main)))
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(>= (get-in entities [:fade :opacity]) 1.0))
|
|
|
|
(terminate [this screen entities]
|
|
(let [entities (stop screen (if-let [next-time (get-in entities [:state :next-time])]
|
|
(-> entities
|
|
(assoc-in [:state :time] next-time)
|
|
(assoc-in [:state :next-time] nil))
|
|
entities)
|
|
:ego
|
|
:face face)]
|
|
(if-let [stop-fn (get-in entities [:room :stop-fn])]
|
|
(stop-fn screen entities)
|
|
entities)))
|
|
(skip-type [this screen entities]
|
|
:none))
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(utils/stop-all-sounds! entities)
|
|
(let [ego (get-in entities [:room :entities :ego])
|
|
old-music (get-music (get-in entities [:room :music]) (get-in entities [:state :time]))
|
|
entities (as-> entities e
|
|
(assoc-in e [:room] (get-in entities [:rooms new-background]))
|
|
(assoc-in e [:room :entities :ego] ego)
|
|
(assoc-in e [:current-sounds :value] [])
|
|
(if between (between screen e) e)
|
|
(assoc-in e [:state :last-room] new-background)
|
|
(assoc-in e [:tweens :fade-in] (tween/tween :fade-in screen [:fade :opacity] 1.0 0.0 time))
|
|
(if-not (get-in entities [:cam :paused?])
|
|
(-> e
|
|
(update-in [:tweens] dissoc :cam-zoom :cam-x :cam-y)
|
|
(assoc-in [:cam :x] 160)
|
|
(assoc-in [:cam :y] 120)
|
|
(assoc-in [:cam :zoom] 0.95))
|
|
e)
|
|
|
|
(if music-changed?
|
|
(assoc-in e [:tweens :fade-in-music] (tween/tween :fade-in-music screen [:volume :value] 0.0 1.0 time))
|
|
e))
|
|
new-music (get-music (get-in entities [:room :music]) (get-in entities [:state :time]))
|
|
apply-state (get-in entities [:room :apply-state])
|
|
entities (if apply-state
|
|
(apply-state screen entities)
|
|
entities)
|
|
entities (utils/update-override screen entities)]
|
|
(when (and (not= new-music old-music) transition-music?)
|
|
(doseq [[k v] (:musics entities)
|
|
:when (and v (not= new-music k))]
|
|
(music! v :stop))
|
|
(when (and new-music transition-music?)
|
|
(music! (get-in entities [:musics new-music]) :set-volume 0)
|
|
(music! (get-in entities [:musics new-music]) :play)))
|
|
(-> entities
|
|
(update-in [:room :entities :ego] #(jump-to screen entities % [x y] true)))))
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(<= (get-in entities [:fade :opacity]) 0.0))
|
|
|
|
(terminate [this screen entities]
|
|
(doseq [[k [start time fn]] (get-in entities [:room :timers])]
|
|
(add-timer! screen k start time))
|
|
entities)
|
|
|
|
(skip-type [this screen entities]
|
|
:none))))
|
|
|
|
(defn do-dialogue [entities & pairs]
|
|
(loop [pairs (partition 2 pairs)]
|
|
(let [[[target line]] pairs
|
|
next-speaker-is-different (not= target (ffirst (next pairs)))
|
|
result (talk entities target line :stop? next-speaker-is-different)]
|
|
|
|
(Thread/sleep 200)
|
|
(if (seq (rest pairs))
|
|
(recur (rest pairs))
|
|
result))))
|
|
|
|
(defn respond [entities line & more]
|
|
(apply do-dialogue entities :ego line more))
|
|
|
|
(defn glad [entities]
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
(let [current-y (get-in entities [:room :entities :ego :y])
|
|
to-y (+ current-y 15)]
|
|
(-> entities
|
|
(update-in [:room :entities :ego] #(actions/start-animation screen % :glad) )
|
|
(assoc-in [:tweens :jump] (tween/tween :jump screen [:room :entities :ego :y] current-y to-y 0.3 :ease tween/ease-out-cubic))
|
|
(assoc-in [:room :entities :glad-jump] (doto (assoc (particle-effect "particles/glad-jump")
|
|
:x (get-in entities [:room :entities :ego :x])
|
|
:y (get-in entities [:room :entities :ego :y])
|
|
:baseline (get-in entities [:room :entities :ego :baseline]))
|
|
(particle-effect! :reset) (particle-effect! :start)))
|
|
(assoc-in [:room :entities :cloud] (assoc (utils/get-texture "space/cloud.png")
|
|
:x (get-in entities [:room :entities :ego :x])
|
|
:y (get-in entities [:room :entities :ego :y])
|
|
:origin-x 7
|
|
:origin-y 7
|
|
:scale-x 0.5
|
|
:scale-y 0.5
|
|
:opacity 0.5
|
|
:baseline 240))
|
|
(assoc-in [:tweens :cloud-up] (tween/tween :cloud-up screen [:room :entities :cloud :y]
|
|
(get-in entities [:room :entities :ego :y])
|
|
(+ (get-in entities [:room :entities :ego :y]) 10)
|
|
1.0))
|
|
(assoc-in [:tweens :cloud-fade] (tween/tween :cloud-fade screen [:room :entities :cloud :opacity]
|
|
0.5
|
|
0.0
|
|
1.0))
|
|
(assoc-in [:tweens :cloud-grow] (tween/tween :cloud-grow screen [:room :entities :cloud :scale-y]
|
|
0.5
|
|
1.0
|
|
1.0))
|
|
(assoc-in [:tweens :cloud-grow-2] (tween/tween :cloud-grow-2 screen [:room :entities :cloud :scale-x]
|
|
0.5
|
|
1.0
|
|
1.0)))))
|
|
|
|
(continue [this screen entities]
|
|
(assoc-in entities [:room :entities :glad-jump :y] (+ (get-in entities [:room :entities :ego :y]) 5))
|
|
)
|
|
|
|
(done? [this screen entities]
|
|
(nil? (get-in entities [:tweens :jump])))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none))
|
|
(Thread/sleep 800)
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
(let [current-y (get-in entities [:room :entities :ego :y])
|
|
to-y (- current-y 15)]
|
|
(-> entities
|
|
(assoc-in [:tweens :jump] (tween/tween :jump screen [:room :entities :ego :y] current-y to-y 0.1 :ease tween/ease-in-cubic)))))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(and (nil? (get-in entities [:tweens :jump]))
|
|
(animation! (actions/find-animation (get-in entities [:room :entities :ego ]) :glad)
|
|
:is-animation-finished
|
|
(- (:total-time screen) (get-in entities [:room :entities :ego :anim-start])))))
|
|
|
|
(terminate [this screen entities]
|
|
(stop screen entities :ego))
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
|
|
|
|
|
|
|
|
(defn fade-in-georgia [entities]
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
(particle-effect! (get-in entities [:room :entities :georgia-cloud]) :reset)
|
|
(particle-effect! (get-in entities [:room :entities :georgia-cloud]) :start)
|
|
(-> entities
|
|
(assoc-in [:room :entities :georgia-face :x] (- (get-in entities [:room :entities :ego :x]) 30))
|
|
(assoc-in [:room :entities :georgia-face :y] (+ (get-in entities [:room :entities :ego :y]) 30))
|
|
|
|
(assoc-in [:room :entities :georgia-cloud :x] (- (get-in entities [:room :entities :ego :x]) 30))
|
|
(assoc-in [:room :entities :georgia-cloud :y] (+ (get-in entities [:room :entities :ego :y]) 30))
|
|
(assoc-in [:tweens :fade-georgia]
|
|
(tween/tween :fade-georgia screen [:room :entities :georgia-face :opacity] 0.0 1.0 1.0 :ease tween/ease-in-cubic))))
|
|
|
|
(continue [this screen entities]
|
|
(assoc-in entities [:room :entities :georgia-cloud :opacity] (get-in entities [:room :entities :georgia-face :opacity])))
|
|
|
|
(done? [this screen entities]
|
|
(nil? (get-in entities [:tweens :fade-georgia])))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn fade-out-georgia [entities]
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
(particle-effect! (get-in entities [:room :entities :georgia-cloud]) :allow-completion)
|
|
(-> entities
|
|
(assoc-in [:tweens :fade-georgia]
|
|
(tween/tween :fade-georgia screen [:room :entities :georgia-face :opacity] 1.0 0.0 1.0 :ease tween/ease-in-cubic))))
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(nil? (get-in entities [:tweens :fade-georgia])))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn georgia-say [entities msg]
|
|
(transition-music entities :love :duration 0.5)
|
|
(Thread/sleep 1000)
|
|
(fade-in-georgia entities)
|
|
(actions/talk entities :georgia-face msg)
|
|
(Thread/sleep 1000)
|
|
(fade-out-georgia entities)
|
|
(transition-music entities nil :duration 1.0))
|
|
|
|
(defn wait-for-animation [entities target anim]
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
entities)
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(animation! (actions/find-animation (get-in entities [:room :entities target]) anim)
|
|
:is-animation-finished
|
|
(- (:total-time screen) (get-in entities [:room :entities target :anim-start]))))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn in-love [entities]
|
|
(let [seen-love (get-in @entities [:state :has-seen-love?])]
|
|
(when (or (not seen-love)
|
|
(< (rand-int 10) 3))
|
|
|
|
(transition-music entities :love :duration 1.0)
|
|
(begin-animation entities :georgia-face :love)
|
|
(fade-in-georgia entities)
|
|
(update-state entities (fn [s] (assoc s :has-seen-love? true)))
|
|
(wait-for-animation entities :georgia-face :love)
|
|
(fade-out-georgia entities)
|
|
(do-stop entities :georgia-face)
|
|
(transition-music entities nil :duration 1.0))))
|
|
|
|
|
|
(defn do-pan [entities x y scale-fn & [ease duration]]
|
|
(actions/run-action entities
|
|
(begin [this screen entities]
|
|
(pan-to screen entities x y scale-fn ease duration))
|
|
|
|
(continue [this screen entities]
|
|
entities)
|
|
|
|
(done? [this screen entities]
|
|
(nil? (get-in entities [:tweens :cam-y])))
|
|
|
|
(terminate [this screen entities]
|
|
entities)
|
|
(skip-type [this screen entities]
|
|
:none)))
|
|
|
|
(defn camera-shake [entities length]
|
|
(dotimes [n length]
|
|
(actions/do-pan entities (get-in @entities [:cam :x])
|
|
(+ (get-in @entities [:cam :y])
|
|
3)
|
|
(constantly (get-in @entities [:cam :zoom]))
|
|
nil
|
|
(* 0.01 (inc n)))
|
|
(actions/do-pan entities (get-in @entities [:cam :x])
|
|
(- (get-in @entities [:cam :y])
|
|
3)
|
|
(constantly (get-in @entities [:cam :zoom]))
|
|
nil
|
|
(* 0.01 (inc n)))))
|