Files
gitea-docker/desktop/src-common/advent/screens/scene.clj

811 lines
45 KiB
Clojure

(ns advent.screens.scene
(:refer-clojure :exclude [load])
(:require [play-clj.core :refer :all]
[play-clj.ui :refer :all]
[play-clj.utils :refer :all]
[play-clj.math :refer :all]
[play-clj.entities :as entities]
[play-clj.g2d :refer :all]
[clojure.zip :as zip]
[clojure.pprint]
[clojure.java.io :as io]
[advent.pathfind]
[advent.actions :as actions]
[advent.zone :as zone]
[advent.utils :as utils]
[advent.tween :as tween]
[advent.screens.rooms :as rooms]
[advent.screens.rooms.common :as common]
[advent.screens.items :as items]
[advent.screens.rooms.dream :as rooms.dream]
[advent.screens.rooms.castle-gate :as rooms.castle-gate]
[advent.screens.rooms.outside-house :as rooms.outside-house]
[advent.screens.rooms.inside-house :as rooms.inside-house]
[advent.screens.rooms.inside-stash :as rooms.inside-stash]
[advent.screens.rooms.inside-castle :as rooms.inside-castle]
[advent.screens.rooms.inside-jail :as rooms.inside-jail]
[advent.screens.rooms.outside-jail :as rooms.outside-jail]
[advent.screens.rooms.inside-cafeteria :as rooms.inside-cafeteria]
[advent.screens.rooms.inside-antique :as rooms.inside-antique]
[advent.screens.rooms.behind-house :as rooms.behind-house]
[advent.screens.rooms.outside-castle :as rooms.outside-castle]
[advent.screens.rooms.space :as rooms.space]
[advent.screens.rooms.cat-tree :as rooms.cat-tree]
[advent.screens.dialogue :refer [talking-screen]]
[advent.screens.inventory :refer [inventory-screen]]
[clojure.core.async :refer [put! <! <!! >! chan go thread take! alts!!]])
(:import [com.badlogic.gdx.graphics Pixmap Pixmap$Filter Texture Texture$TextureFilter GL20 GL30]
[com.badlogic.gdx.graphics.g2d TextureRegion Animation Batch]
[com.badlogic.gdx.math Vector3 Matrix4]
[com.badlogic.gdx.utils.viewport FitViewport]
[com.badlogic.gdx.scenes.scene2d Actor Stage]
[java.lang Object]
[com.badlogic.gdx Gdx]
[com.badlogic.gdx.graphics Camera Color GL20 OrthographicCamera
PerspectiveCamera Pixmap Pixmap$Format PixmapIO Texture
VertexAttributes$Usage]
[com.badlogic.gdx.scenes.scene2d Actor Stage]))
(declare hud)
(def default-interaction
{:get-script (fn [cursor [x y]] (if (= :main cursor)
(actions/get-script entities
(actions/walk-to entities :ego [x y] :can-skip? true))
(actions/get-script entities
(actions/talk entities :ego "I don't know what to do with that."))))})
(defn click-inventory [screen entities]
(when (not (get-in entities [:actions :script-running?]))
(if (= (get-in entities [:cursor :current] ) :main)
(do
(screen! inventory-screen :show-screen :items (map (entities :all-items) (get-in entities [:state :inventory])))
(-> entities
(assoc-in [:state :active?] false)
(assoc-in [:cursor :override] nil)))
(assoc-in entities [:cursor :current] :main))))
(defn left-click [screen entities]
(let [[x y] (utils/unproject screen)]
(println "clicked " x y)
(let [interaction (first (filter #((:mouse-in? %) entities x y)
(get-in entities [:room :interactions])))
interacting-entity (first (sort-by (comp - :baseline) (filter #(and (:mouse-in? %)
(:get-script %)
((:mouse-in? %) entities x y))
(vals (dissoc (get-in entities [:room :entities]) :ego)))))
current-action (get-in entities [:actions :current])
;; TODO - hacky way of resetting queue
entities (if (and current-action (actions/can-skip? current-action screen entities))
(let [terminated-entities (actions/terminate current-action screen entities)]
(do (put! (actions/get-channel current-action) terminated-entities)
(-> terminated-entities
(assoc-in [:actions :current] nil)
(assoc-in [:actions :started?] false))))
entities)]
(if (get-in entities [:actions :script-running?])
entities
((or (when interacting-entity
((:get-script interacting-entity) (get-in entities [:cursor :current]) [x y]))
(when interaction
((:get-script interaction) (or (when (:cursor interaction) :main)
(get-in entities [:cursor :current]))
[x y]))
((:get-script default-interaction) (get-in entities [:cursor :current]) [x y])) entities))
entities)))
(defn drink-blergh [entities]
(actions/walk-straight-to entities :ego [205 45])
(sound! (sound "ego/potion.ogg") :play (utils/current-sound-volume))
(actions/play-animation entities :ego :grow :stop? false)
(actions/do-dialogue entities
:blergh "What this? A potion of strength?"
:blergh "You're still no match for me."
:blergh "Give it to me, or I'll make you regret it!")
(actions/present-choices entities {:choices ["Ok."
{:run (fn [_]
(actions/talk entities :ego "Ok." :anim :grow-talk :stop? false)
(actions/talk entities :ego "Here you go." :anim :grow-talk)
(actions/do-dialogue entities
:blergh "Yes! Now I can drink this whole thing and can become powerful enough to rule the world!"
:blergh "[#AAFFAAFF]*gulp*[]"
:blergh "What's this? What's happening?")
(actions/talk entities :ego "Uh oh." :anim :grow-talk :stop? false)
(actions/walk-straight-to entities :ego [100 45] :face :right)
(actions/play-animation entities :blergh :grow :stop? false)
(actions/do-dialogue entities :ego "'Not more than that do drink,\nOr you'll push your body to the brink.'"
:ego "Brilliant! I win!")
(actions/walk-straight-to entities :ego [800 75] :face :right)
(actions/update-state entities (fn [s] (assoc s :blergh-dead? true))))}
"No way!"
{:run (fn [_]
(actions/talk entities :ego "No way!" :anim :grow-talk)
(actions/talk entities :blergh "Then take this!")
(actions/play-animation entities :blergh :swing)
(actions/walk-straight-to entities :ego [100 45] :anim :squat :override-dir :right :speed 3.0)
(actions/do-dialogue entities :ego "Yeow!!"
:ego "Even with that potion, I'm not strong enough."))}]}))
(defn get-ego [screen start-pos start-scale]
(let [player-sheet (texture! (texture "player.png") :split 18 36)
talk-sheet (texture! (texture "ego/talk.png") :split 18 36)
stand-sheet (texture! (texture "ego/stand.png") :split 18 36)
squat-sheet (texture! (texture "ego/squat.png") :split 18 36)
reach-sheet (texture! (texture "ego/reach.png") :split 18 36)
grow-sheet (texture! (texture "ego/grow.png") :split 18 36)
cat-toy-sheet (texture! (texture "ego/cat-toy.png") :split 41 50)
fire-sheet (texture! (texture "ego/fire.png") :split 18 36)
walk-right (animation 0.075 (for [i (range 8)]
(texture (aget player-sheet 0 i))))
stand-anim (animation 0.1 (for [i (flatten [(repeat 6 [(repeat 10 0) (repeat 3 1) (repeat 20 0)]) 3 4 5 5 5 6 5 6 5 6 5 4 3 ])]
(texture (aget stand-sheet 0 i))))
reach-up (animation 0.1 (for [i [0 3 4 5]]
(texture (aget stand-sheet 0 i))))
reach-down (animation 0.1 (for [i [5 4 3 0]]
(texture (aget stand-sheet 0 i))))
talk-anim (animation 0.2 (for [i (range 8)]
(texture (aget talk-sheet 0 i))))
start-squat (animation 0.05 (for [i [0 1 2 3 4]]
(texture (aget squat-sheet 0 i))))
end-squat (animation 0.05 (for [i [4 3 2 1 0]]
(texture (aget squat-sheet 0 i))))
squat-anim (animation 0.05 (for [i [0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 2 1] ]
(texture (aget squat-sheet 0 i))))
reach-anim (animation 0.1 (for [i [0 1 2 3 3 3 3 3 3 2 1 0]]
(texture (aget reach-sheet 0 i))))
reach-start (animation 0.1 (for [i [0 1 2 3 ]]
(texture (aget reach-sheet 0 i))))
reach-stop (animation 0.1 (for [i [3 2 1 0]]
(texture (aget reach-sheet 0 i))))
cat-toy-anim (animation 0.1 (for [i [0 0 1 1 2 2 3 4 3 2 3 4 3 2 3 4 3 2 3 4 3 2 2 1 1 0 0]]
(texture (aget cat-toy-sheet 0 i))))
cat-toy-first-half (animation 0.1 (for [i [0 0 1 1 2 2 3]]
(texture (aget cat-toy-sheet 0 i))))
cat-toy-last-half (animation 0.1 (for [i [3 3 3 2 1 1 0 0]]
(texture (aget cat-toy-sheet 0 i))))
fire-1-anim (animation 0.1 (for [i [0 1 2 2 2 3 2 3 2 2 2 2 2 2 2 2 2 2 1 0]]
(texture (aget fire-sheet 0 i))))
fire-2-anim (animation 0.1 (for [i [0 1 2 2 2 3 2 3 2 2 2 2 2 2 2 4 4 4 5 6 7 4 4 4 2 2 2 2 2 2 2 2 1 0]]
(texture (aget fire-sheet 0 i))))
fire-3-anim (animation 0.1 (for [i [0 1 2 2 2 3 2 3 2 2 2 2 2 2 4 4 4 4 4 4 5 6 7 4 4 4 4 4 8 9 10 11 4 4 4 2 2 2 2 2 2 2 2 0]]
(texture (aget fire-sheet 0 i))))
grow (animation 0.1 (for [i [0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 3 0 0 0 0 3 0 0 0 3 3 0 0 0 2 2 0 0 2 0 0 2 0 2 0 2 0 2 0 2 0 2 3 2 3 2 3 2 3 2 4 3 4 3 4 3 4]]
(texture (aget grow-sheet 0 i))))
hold-up-to-window (utils/make-anim "ego/hold-up-to-window.png" [18 36] 0.1 [0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 1 0 0 0 0 0 0])
jump (utils/make-anim "ego/swing.png" [36 75] 0.2 (flatten [[1 2]]))
swing (utils/make-anim "ego/swing.png" [36 75] 0.145 (flatten [[3 4 5 6 7 ]]))
grow-talk (utils/make-anim "ego/grow-talk.png" [18 36] 0.2 (range 2))
get-sick (animation 0.3 (map (partial get [(aget talk-sheet 0 0 ) (texture "ego/get-sick.png")]) [0 1 1 1 1 1 1 1 1 1 1 1]) )
spear (utils/make-anim "ego/spear.png" [18 100] 0.2 [0 1 2 3 2 3 2 3 2 3 2 1 0])
crowbar (utils/make-anim "ego/crowbar.png" [36 36] 0.1 [0 0 0 1 1 2 2 2 2 2 3 2 3 2 3 2 3 2 3 3 3 1 1 0 0 0])
shoot (utils/make-anim "ego/shoot.png" [24 36] 0.075 [0 0 0 1 1 2 2 2 2 2 2 2 2 3 4 5 4])
pant (utils/make-anim "ego/pant.png" [31 36] 0.5 [0 1])
shock (utils/make-anim "ego/shock.png" [40 48] 0.075 (flatten (repeat 2 [(repeat 5 [0 1 2]) (repeat 5 [3 4 5]) (repeat 5 [6 7 8])])))
burnt (utils/make-anim "ego/burnt.png" [40 46] 0.12 [1 2 3 2 1 2 3 2 1 0 2 0 4 5 6 7 8 9 10 11 10 9 10 11])
passed-out (utils/make-anim "ego/burnt.png" [40 46] 0.12 [9 10 11 10])
scared (utils/make-anim "ego/scared.png" [18 36] 0.05 [0 1])
scared-talk (utils/make-anim "ego/scared.png" [18 36] 0.05 [0 1 0 1 0 1 0 1 2 3 2 3 2 3 2 3])
scared-walk (utils/make-anim "ego/scared-walk.png" [16 36] 0.05 (range 6))
sigh (utils/make-anim "ego/sigh.png" [18 36] 0.08 [0 0 0 0 1 1 1 2 3 4 5 6 7 8 8 8 8 8 8 8 8 8 0 0 0 0 ])
glad (utils/make-anim "ego/glad.png" [20 46] 0.04 (flatten [0 1 2 3 4 (repeat 8 [5 5 5]) (repeat 20 0)]))
milk (utils/make-anim "ego/squat.png" [18 36] 0.05 [0 1 2 2 3 3 3 3 3 3 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 3 3 3 3 3 3 3 3 3 3 3 2 1 0])
throw (utils/make-anim "ego/throw.png" [18 36] 0.04 (flatten [[(repeat 5 0) (repeat 10 1)] (repeat 3 [2 2 2 3 3 3 4 4 4 5 5 5]) (repeat 5 [2 2 3 3 4 4 5 5]) (repeat 10 [2 3 4 5]) [2 3 3] (repeat 15 6)]))
ego {:right {:walk walk-right
:stand stand-anim
:talk talk-anim
:squat squat-anim
:start-squat start-squat
:end-squat end-squat
:reach reach-anim
:cat-toy cat-toy-anim
:cat-toy-first-half cat-toy-first-half
:cat-toy-last-half cat-toy-last-half
:grow grow
:crowbar crowbar
:get-sick get-sick
:hold-up-to-window hold-up-to-window
:swing swing
:grow-talk grow-talk
:reach-up reach-up
:reach-down reach-down
:reach-start reach-start
:jump jump
:reach-stop reach-stop
:shoot shoot
[:fire 1] fire-1-anim
[:fire 2] fire-2-anim
[:fire 3] fire-3-anim
:spear spear
:pant pant
:shock shock
:burnt burnt
:passed-out passed-out
:scared scared
:scared-talk scared-talk
:scared-walk scared-walk
:sigh sigh
:glad glad
:milk milk
:throw throw}
:left {:walk (utils/flip walk-right)
:stand (utils/flip stand-anim)
:talk (utils/flip talk-anim)
:start-squat (utils/flip start-squat)
:end-squat (utils/flip end-squat)
:squat (utils/flip squat-anim)
:reach (utils/flip reach-anim)
:cat-toy (utils/flip cat-toy-anim)
:get-sick (utils/flip get-sick)
:cat-toy-first-half (utils/flip cat-toy-first-half)
:cat-toy-last-half (utils/flip cat-toy-last-half)
:grow (utils/flip grow)
:hold-up-to-window (utils/flip hold-up-to-window)
:grow-talk (utils/flip grow-talk)
:reach-up (utils/flip reach-up)
:reach-down (utils/flip reach-down)
:reach-start (utils/flip reach-start)
:reach-stop (utils/flip reach-stop)
:shoot (utils/flip shoot)
[:fire 1] (utils/flip fire-1-anim)
[:fire 2] (utils/flip fire-2-anim)
[:fire 3] (utils/flip fire-3-anim)
:spear (utils/flip spear)
:pant (utils/flip pant)
:sigh (utils/flip sigh)
:glad (utils/flip glad)
:milk (utils/flip milk)
:throw (utils/flip throw)}
:baseline (- 240 (last start-pos))
:facing :right
:origin-x 9
:origin-y 0
:scaled true
:milk-sound (sound "outsidehouse/milk.ogg")
:step-sound-1 (sound "ego/step-1.ogg")
:step-sound-2 (sound "ego/step-2.ogg")
:sigh-sound (sound "ego/sigh.ogg")
:blink (sound "blink.ogg")
:scale-x start-scale
:scale-y start-scale
:talk-color (color 0.6 1.0 1.0 1.0)
:mouse-in? (fn [entities x y]
(let [{entity-x :x entity-y :y region :object scale :scale-x} (get-in entities [:room :entities :ego])
half-width (/ (* (.getRegionWidth region) (or scale 1.0)) 2)
height (* (.getRegionHeight region) (or scale 1.0))]
#_(clojure.pprint/pprint [["point" x y]
["entity " (- entity-x half-width) entity-y (+ entity-x half-width) (+ entity-y height)]])
((zone/box (- entity-x half-width) entity-y (+ entity-x half-width) (+ entity-y height)) x y)))
:get-script (fn [cursor [x y]]
(condp = (:value cursor)
:flask-1-with-cream-of-mushroom (actions/get-script entities (actions/talk entities :ego "Blegh! Gross!"))
:flask-1-strength (actions/get-script entities
(cond (and (actions/has-item? entities :magic-slingshot)
(get-in @entities [:room :blergh]))
(drink-blergh entities)
(get-in @entities [:room :blergh])
(actions/talk entities :ego "There's no time!")
:else
(do
(actions/talk entities :ego "I'll just take a sip!")
(sound! (sound "ego/potion.ogg") :play (utils/current-sound-volume))
(actions/play-animation entities :ego :grow :stop? false))))
:recipe (actions/get-script entities (actions/do-dialogue entities
:ego "The recipe says:"
:ego "'For strength beyond measure,\nyou must mix, at your leisure:'"
:ego "'1. Cream of mushroom soup.'"
:ego "'2. Saliva of the creature whose strength you want to match.'"
:ego "'3. Mandrake root.'"
:ego "'A word of warning, before you go.\nA sip is all it takes to grow.'"
:ego "'Not more than that do drink,\nOr you'll push your body to the brink.'"
:ego "Hmm. I wonder what that last part means?"))
:note-1 (actions/get-script entities (common/read-note-1 entities))
:note-2 (actions/get-script entities (common/read-note-2 entities))
:camera (actions/get-script entities (actions/talk entities :ego "It's some sort of magical device that captures images."))
:alarm-clock (actions/get-script entities (actions/talk entities :ego "It's a magic device that tells the time."))
:walkie-talkies (actions/get-script entities (actions/do-dialogue entities :ego "If I talk in one of these devices, I can hear it in the other one!"))
:walkie-talkie (actions/get-script entities (common/listen-to-frankie entities))
nil))
:x (first start-pos) :y (last start-pos)
:id "ego"}
ego (assoc ego :anim-sound-frames {(get-in ego [:left :walk]) {2 [:step-sound-1 1.0]
6 [:step-sound-2 0.8]}
(get-in ego [:right :walk]) {2 [:step-sound-1 1.0]
6 [:step-sound-2 0.8]}
(get-in ego [:left :talk] ) {2 [:blink 0.15]}
(get-in ego [:right :talk] ) {2 [:blink 0.15]}
(get-in ego [:left :stand]) {11 [:blink 0.15]
44 [:blink 0.15]
77 [:blink 0.15]
110 [:blink 0.15]
143 [:blink 0.15]
176 [:blink 0.15]}
(get-in ego [:right :stand]) {11 [:blink 0.15]
44 [:blink 0.15]
77 [:blink 0.15]
110 [:blink 0.15]
143 [:blink 0.15]
176 [:blink 0.15]}
(get-in ego [:left :sigh]) {1 [:sigh-sound 0.4]}
(get-in ego [:right :sigh]) {1 [:sigh-sound 0.4]}
(get-in ego [:left :milk]) {8 [:milk-sound 1.0]}
(get-in ego [:right :milk]) {8 [:milk-sound 1.0]}
}
:anim-merges {(get-in ego [:right :shock]) {:origin-x 15}
:default {:origin-x 9}})]
(actions/start-animation screen
(merge (animation->texture screen (:stand (:right ego))) ego)
:stand)))
(defn update-from-script [screen {{:keys [current started? channel]} :actions :as entities}]
(if current
(let [entities (if started? entities (actions/begin current screen entities))
entities (actions/continue current screen entities)]
(if (actions/done? current screen entities)
(let [terminated (actions/terminate current screen entities)]
(put! (actions/get-channel current) terminated)
(recur screen (assoc terminated
:actions {:channel channel :current nil :started? false :script-running? (get-in entities [:actions :script-running?])})))
(assoc-in entities [:actions :started?] true)))
(let [[current _] (alts!! [channel] :default nil)]
(assoc entities :actions {:channel channel :current current :started? false :script-running? (get-in entities [:actions :script-running?])}))))
(defn update-from-hotspots [screen entities]
(if-let [hot-spots (get-in entities [:room :hotspots])]
(if-let [hotspot-hit (first (filter #((apply zone/box (:box %)) (get-in entities [:room :entities :ego :x]) (get-in entities [:room :entities :ego :y])) hot-spots))]
((:fn hotspot-hit) screen entities)
entities)
entities))
(defn update-cursor [screen {{:keys [current override last]} :cursor :as entities}]
(let [new-current (or override current)]
(when-not (= new-current
last)
(input! :set-cursor-image (utils/cursor "cursor.png" (or (:cursor new-current) new-current)) 0 0))
(assoc-in entities [:cursor :last] new-current)))
(defn get-animation-point [^Animation animation total-time]
(loop [time total-time]
(if (> (- time (animation! animation :get-animation-duration)) 0)
(recur (- time (animation! animation :get-animation-duration)))
time)))
(defn animate [entity screen]
(merge entity (animation->texture (update-in screen [:total-time] #(- % (:anim-start entity)))
(:anim entity))
{:current-frame-index (texture! (:anim entity) :get-key-frame-index (get-animation-point (:anim entity) (- (:total-time screen) (:anim-start entity))))
:previous-frame-index (texture! (:anim entity) :get-key-frame-index (get-animation-point (:anim entity) (- (:total-time screen) (:anim-start entity) (or (:delta-time screen) 0))))}
(or (get-in entity [:anim-merges (:anim entity)])
(get-in entity [:anim-merges :default]))))
(defn get-layers [entities]
(let [layers (get-in entities [:room :layers])]
(if (map? layers)
((get-in entities [:state :time]) layers)
layers)))
(defn get-state []
(if (.exists (io/file "save.edn"))
(utils/load)
{:object nil
:active? true
:last-room :dream
:time :day
:obtained-items #{}
:inventory []
:plaques-read #{}
:clues #{}
:mints-eaten 0
:seen-intro? false}))
(defn fade-in-first-time-if-necessary [screen entities]
(if (not (get-in entities [:started? :value]))
(do (music! (utils/get-current-music entities) :set-volume (utils/current-music-volume (get-in entities [:volume :value])))
(utils/play-sound (get-in entities [:musics (actions/get-music (get-in entities [:room :music]) (get-in entities [:state :time]))]))
(assoc entities
:tweens {:fade-in (tween/tween :fade-in screen [:fade :opacity] 1.0 0.0 1.0 :ease tween/ease-in-cubic
:finish #(if (not (get-in % [:state :seen-intro?]))
(do ((actions/get-script % (rooms.dream/do-intro %)) entities)
(assoc-in % [:actions :script-running?] true))
%))
:fade-in-music (tween/tween :fade-in-music screen [:volume :value] 0.0 1.0 1.0 :ease tween/ease-in-cubic)}
:started? {:value true
:object nil}))
entities))
(defn play-key-sounds [entities]
(doseq [[target {:keys [previous-frame-index current-frame-index anim-sound-frames anim x y] :as e}] (get-in entities [:room :entities])]
(when (and (not= previous-frame-index current-frame-index)
((set (keys anim-sound-frames)) anim))
(when-let [[snd vol-scale] (get-in anim-sound-frames [anim current-frame-index])]
(let [vol (if (= target :ego)
(* (/ (get-in entities [:room :entities :ego :scale-x]) 1.5) 0.75)
(max 0.0
(- 1.0 (/ (utils/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))))
pan (/ (- (:x e) 160 ) 160)
vol (* vol vol-scale)
vol (max vol 0.005)]
(sound! (or (snd e)
(snd (:sounds entities))) :play (utils/current-sound-volume vol) 1.0 pan))))))
(defn update-from-room [screen entities]
(if-let [update-fn (get-in entities [:room :update-fn])]
(update-fn screen entities)
entities))
(defn render-parallax [{:keys [^OrthographicCamera camera ^Stage renderer] :as screen} {:keys [parallax] :as e }]
(let [tmp (Vector3.)
tmp2 (Vector3.)
parallax-view (Matrix4.)
parallax-combined (Matrix4.)]
(.update camera)
(.set tmp (.position camera))
(set! (.x tmp) (* (.x tmp) parallax))
(set! (.y tmp) (* (.y tmp) parallax))
(.setToLookAt parallax-view tmp (-> tmp2
(.set tmp)
(.add (.direction camera)))
(.up camera))
(.set parallax-combined (.projection camera))
(Matrix4/mul (.val parallax-combined) (.val parallax-view))
(let [^Batch batch (.getBatch renderer)]
(.begin batch)
(.setProjectionMatrix batch parallax-combined)
(.setColor batch (color 1 1 1 (or (:opacity e) 1.0)))
(entities/draw! (assoc e :x (+ (/ (:x e) (.zoom camera))
(- (* 320 parallax 0.5)
(/ 160 (.zoom camera)) ))
:y (+ (/ (:y e) (.zoom camera))
(- (* 240 parallax 0.5)
(/ 120 (.zoom camera))))) screen batch)
(.setColor batch (color 1 1 1 1))
(.end batch))))
(defn shift-range-to-bounds [x1 x2 min max]
(println x1 x2 "->" (cond (and (< x1 min)
(> x2 max))
[min max]
(< x1 min)
[min (+ x2 (- min x1))]
(> x2 max)
[(- x1 (- x2 max)) max]
:else
[x1 x2]))
(cond (and (< x1 min)
(> x2 max))
[min max]
(< x1 min)
[min (+ x2 (- min x1))]
(> x2 max)
[(- x1 (- x2 max)) max]
:else
[x1 x2]))
(defscreen scene
:on-timer
(fn [screen [entities]]
((get-in entities [:room :timers (:id screen) 2]) screen entities))
:on-show
(fn [screen entities]
(let [screen (assoc screen :total-time 0)]
(let [[cam] (utils/setup-viewport screen 320 240)]
(set! (. cam zoom) 0.95)
(let [_ (input! :set-cursor-image (utils/cursor "cursor.png" :main) 0 0)
rooms {:inside-house (rooms.inside-house/make screen)
:inside-stash (rooms.inside-stash/make screen)
:outside-house (rooms.outside-house/make screen)
:behind-house (rooms.behind-house/make screen)
:cat-tree (rooms.cat-tree/make screen)
:inside-castle (rooms.inside-castle/make screen)
:space (rooms.space/make screen)
:inside-cafeteria (rooms.inside-cafeteria/make screen)
:inside-antique (rooms.inside-antique/make screen)
:inside-jail (rooms.inside-jail/make screen)
:dream (rooms.dream/make screen)
:castle-gate (rooms.castle-gate/make screen)
:outside-jail (rooms.outside-jail/make screen)
:outside-castle (rooms.outside-castle/make screen)}
entities {:rooms rooms
:step-particles (assoc (particle-effect "ego/step") :x 100 :y 100 :baseline 241)
:cam {:zoom 0.95
:paused? false
:object nil}
:musics {:object nil
:inside-antique (utils/make-music "inside-antique.ogg")
:town-1 (utils/make-music "town-music-1.ogg")
:town-2 (utils/make-music "town-music-2.ogg")
:love (utils/make-music "love.ogg")
:inside-fangald (utils/make-music "inside-fangald.ogg")
:fight (utils/make-music "megaboss.mp3")
:pull-sword (utils/make-music "pull-sword.ogg")
:night (utils/make-music "night.ogg")}
:state (get-state)
:sounds {:blink (sound "blink-other.ogg")
:object nil}
:fade (assoc (texture "black.png")
:scale-x 20
:scale-y 20
:baseline 9500
:opacity 0.0)
:white-fade (assoc (texture "white.png")
:scale-x 20
:scale-y 20
:baseline 9500
:opacity 0.0)
:actions {:object nil
:channel (chan)
:current nil
:script-running? false
:started? false}
:volume {:object nil
:value 0.0}
:music-override {:object nil
:value nil}
:cursor {:id "cursor"
:current :main
:last :main
:override nil
:last-pos [0 0]}
:all-items (assoc items/items :object nil)
:started? {:value false
:object nil}
:room (as-> (get rooms (:last-room (get-state))) room
(assoc-in room [:entities :ego] (get-ego screen (:start-pos room) ((:scale-fn room) (:start-pos room)))))}]
(doseq [[k [start time fn]] (get-in entities [:room :timers])]
(add-timer! screen k start time))
(if-let [apply-state (get-in entities [:room :apply-state])]
(apply-state entities)
entities)))))
:on-render
(fn [{:keys [camera] :as screen} [entities]]
(clear!)
(let [entities (fade-in-first-time-if-necessary screen entities)
entities (utils/apply-tweens screen entities (:tweens entities))
entities (update-cursor screen entities)
entities (update-from-script screen entities)
entities (update-from-room screen entities)
entities (update-from-hotspots screen entities)
entities (assoc-in entities [:room :entities :ego :last-frame] (get-in entities [:room :entities :ego :object]))
entities (update-in entities [:room :entities] (fn [entities]
(into entities
(for [[id entity] entities]
(if (:anim entity)
[id (animate entity screen)]
[id entity])))))
entities (update-in entities [:room :entities] (fn [entities]
(into entities
(for [[id entity] entities]
(if (:update-fn entity)
[id ((:update-fn entity) screen entities entity)]
[id entity])))))
entities (if (and (not (get-in entities [:cam :paused?]))
(nil? (get-in entities [:tweens :cam-x]))
(= 1 (rand-int 20)))
(if (= (rand-int 2) 1)
(actions/pan-to screen entities
(get-in entities [:room :entities :ego :x])
(get-in entities [:room :entities :ego :y])
(constantly (get-in entities [:room :entities :ego :scale-x]))
tween/ease-in-out-quadratic
5.0)
(actions/pan-to screen entities
(+ (get-in entities [:cam :x] 0)
(- 10 (rand-int 20)))
(+ (get-in entities [:cam :y] 0)
(- 10 (rand-int 20)))
(constantly (get-in entities [:room :entities :ego :scale-x]))
tween/ease-in-out-quadratic
5.0))
entities)
layers (get-layers entities)
all-entities (concat (vals entities) layers (vals (get-in entities [:room :entities])))]
(screen! talking-screen :on-update-camera :scene-viewport (:viewport screen) :scene-camera (:camera screen))
(when (not (get-in entities [:cam :paused?]))
(set! (. camera zoom) (:zoom (:cam entities)))
(set! (.. camera position x) (:x (:cam entities) 160.0))
(set! (.. camera position y) (:y (:cam entities) 120.0)))
(let [entities (utils/update-override screen entities)]
(when (= (get-in entities [:fade :opacity])
0.0)
(play-key-sounds entities))
(doseq [m (vals (get-in entities [:musics]))]
(when m
(music! m :set-volume (utils/current-music-volume (get-in entities [:volume :value])))))
(doseq [e (sort-by :baseline all-entities)]
(if (:parallax e)
(render-parallax screen e)
(render! screen [e])))
entities)))
:on-resize (fn [{:keys [viewport width height]} [entities]]
(.update viewport width height))
:on-hide (fn [screen [entities]]
(doseq [snd (->> (get-in entities [:musics])
vals
(filter identity))]
(utils/stop-sound snd)))
:on-mouse-moved
(fn [{:keys [input-x input-y viewport] :as screen} [entities]]
(if (utils/contains-point? (.getScreenX viewport) (.getScreenY viewport)
(.getScreenWidth viewport) (.getScreenHeight viewport)
input-x input-y)
(utils/update-override screen (assoc-in entities [:cursor :last-pos] [input-x input-y]))
(assoc-in entities [:cursor :override] nil)))
:on-touch-up (fn [{:keys [input-x input-y viewport] :as screen} [entities]]
(when (utils/contains-point? (.getScreenX viewport) (.getScreenY viewport)
(.getScreenWidth viewport) (.getScreenHeight viewport)
input-x input-y)
(if (= (button-code :right)
(:button screen))
(assoc-in entities [:cursor :current] :main)
(when (and (get-in entities [:state :active?])
(not (get-in entities [:state :hud-active?]))
(= 0.0 (get-in entities [:fade :opacity])))
(left-click screen entities)))))
:on-deactivate (fn [screen [entities]]
(assoc-in entities [:state :active?] false))
:on-reactivate (fn [screen [entities]]
(-> entities
(assoc-in [:state :active?] true)
(assoc-in [:cursor :override] nil)))
:on-chose-item (fn [{:keys [item]} [entities]]
(assoc-in entities [:cursor :current] item))
:on-show-inventory (fn [screen [entities]]
(click-inventory screen entities))
:on-menu (fn [screen [entities]]
(-> entities
(assoc-in [:cursor :override] nil)
(assoc-in [:tweens :fade-out-music]
(tween/tween :fade-out-music screen [:volume :value] 1.0 0.0 1.0))
(assoc-in [:tweens :fade-out]
(tween/tween :fade-out screen [:fade :opacity] 0.0 1.0 1.0
:finish #(do (.clear @(resolve 'advent.core/am))
(set-screen! @(resolve 'advent.core/advent) @(resolve 'advent.screens.title/title-screen))
%)))))
:on-start-script (fn [{:keys [script]} [entities]]
(script entities)
entities)
:hud-active? (fn [{:keys [hud-active?]} [entities]]
(assoc-in entities [:state :hud-active?] hud-active?)))
(defn grow-hud [screen entities target up?]
(let [grow-or-shrink (if up? :grow :shrink)
scale-from (if up? 1.0 1.1)
scale-to (if up? 1.1 1.0)
opacity-from (if up? 0.8 1.0)
opacity-to (if up? 1.0 0.8)]
(if (and (not (get-in entities [:tweens [target grow-or-shrink :x]]))
(not= scale-to (get-in entities [target :scale-y] 1.0)))
(-> entities
(assoc-in [:tweens [target grow-or-shrink :y]]
(tween/tween [target grow-or-shrink :y] screen [target :scale-y] scale-from scale-to 0.15 :ease tween/ease-in-out-quadratic))
(assoc-in [:tweens [target grow-or-shrink :x]]
(tween/tween [target grow-or-shrink :x] screen [target :scale-x] scale-from scale-to 0.15 :ease tween/ease-in-out-quadratic))
(assoc-in [:tweens [target grow-or-shrink :opacity]]
(tween/tween [target grow-or-shrink :opacity] screen [target :opacity] opacity-from opacity-to 0.15 :ease tween/ease-in-out-quadratic)))
entities)))
(defscreen hud
:on-show
(fn [screen entities]
(let [screen (assoc screen :total-time 0)]
(utils/setup-viewport screen 320 240)
{:close (assoc (texture "close.png")
:x 304 :y 224
:width 16 :height 16
:baseline 9000
:opacity 0.8)
:inventory (assoc (texture "inventory.png") :x 278 :y 0 :baseline 9000
:mouse-in? (zone/box 278 0 320 42)
:opacity 0.8)
:fps (assoc (label "" (color :white) ) :x 5 :baseline 0 :opacity 0.3)}))
:on-render
(fn [screen [entities]]
(let [entities (utils/apply-tweens screen entities (:tweens entities))]
#_(label! (:fps entities) :set-text (str (game :fps)))
(render! screen [#_(:fps entities) (:inventory entities) (:close entities)])
entities))
:on-resize
(fn [screen entities]
(.update (:viewport screen) (:width screen) (:height screen) true))
:on-mouse-moved
(fn [screen [entities]]
(let [[x y] (utils/unproject screen)
hovered-inventory? ((:mouse-in? (:inventory entities)) x y)
hovered-close? (utils/intersects? (:close entities) [x y])]
(screen! scene :hud-active? :hud-active? (or hovered-close? hovered-inventory?))
(cond hovered-inventory?
(grow-hud screen entities :inventory true)
hovered-close?
(grow-hud screen entities :close true)
:else
(let [entities (update-in entities [:tweens] dissoc :inventory-grow-x :inventory-grow-y)
entities (grow-hud screen entities :inventory false)
entities (grow-hud screen entities :close false)]
entities
))))
:on-touch-up
(fn [screen [entities]]
(if (= (button-code :left) (:button screen))
(let [[x y] (utils/unproject screen)]
(cond ((:mouse-in? (:inventory entities)) x y)
(screen! scene :on-show-inventory)
(utils/intersects? (:close entities) [x y])
(screen! scene :on-menu)
:else
nil)))))