200 lines
8.6 KiB
Clojure
200 lines
8.6 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]
|
|
[advent.pathfind]
|
|
[advent.actions :as actions]
|
|
[advent.screens.dialogue :as dialogue]
|
|
[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]))
|
|
|
|
(defprotocol IAction
|
|
(begin [this screen entities])
|
|
(done? [this screen entities])
|
|
(continue [this screen entities])
|
|
(terminate [this screen entities])
|
|
(get-channel [this]))
|
|
|
|
(defmacro get-script [entities & forms]
|
|
`(fn [starting-entities#]
|
|
(let [~entities (atom starting-entities#)]
|
|
(thread ~@forms))))
|
|
|
|
|
|
(defn jump-to [screen entities entity [x y]]
|
|
(let [scale-fn (-> entities :background :scale-fn)
|
|
entity (assoc entity :x x
|
|
:y y
|
|
:baseline (- 240 y))]
|
|
(if (:scaled entity)
|
|
(assoc entity :scale-x (scale-fn y) :scale-y (scale-fn y))
|
|
entity)))
|
|
|
|
(defn start-animation [screen entity anim]
|
|
(let [new-anim (if (keyword? anim)
|
|
(or (get-in entity [(:facing entity) anim])
|
|
(anim 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]
|
|
(update-in entities [:background :entities target-id] #(start-animation screen % :stand)))
|
|
|
|
|
|
(defn dist [x1 y1 x2 y2]
|
|
(let [dx (- x1 x2)
|
|
dy (- y1 y2)]
|
|
(Math/sqrt (+ (* dx dx) (* dy dy)))))
|
|
|
|
(defmacro run-action [entities & forms]
|
|
`(let [c# (chan)]
|
|
(do
|
|
(put! (get-in (deref ~entities) [:actions :channel])
|
|
(reify IAction
|
|
(get-channel [_] c#)
|
|
~@forms))
|
|
(reset! ~entities (<!! c#)))))
|
|
|
|
(defn walk-to [entities target-id [final-x final-y]]
|
|
(let [{start-x :x start-y :y} (get-in @entities [:background :entities target-id])
|
|
final-x (int final-x)
|
|
final-y (int final-y)
|
|
path (vec (take-nth 5 (advent.pathfind/visit-all
|
|
(:collision (:background @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]
|
|
entities)
|
|
|
|
(continue [this screen entities]
|
|
(let [{from-x :x from-y :y :keys [left right] :as target-entity} (get-in entities [:background :entities target-id])
|
|
[[target-x target-y] remainder] @targets-left]
|
|
(let [delta-x (- target-x from-x)
|
|
delta-y (- target-y from-y)
|
|
distance (dist from-x from-y target-x target-y)
|
|
moved-x (if (= 0.0 distance)
|
|
0
|
|
(* 1.5 (/ delta-x distance)))
|
|
moved-y (if (= 0.0 distance)
|
|
0
|
|
(* 1.5 (/ delta-y distance)))]
|
|
(if (< distance 1)
|
|
(do (swap! targets-left rest)
|
|
entities)
|
|
(update-in entities [:background :entities target-id]
|
|
#(start-animation screen
|
|
(assoc (jump-to screen entities % [(+ moved-x from-x) (+ moved-y from-y)])
|
|
:facing (cond (< 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 [:background :entities target-id])]
|
|
(< (dist final-x final-y from-x from-y) 1)))
|
|
|
|
(terminate [this screen entities]
|
|
(stop screen entities target-id)))
|
|
@entities)))
|
|
|
|
(defn get-text-duration [text]
|
|
(* (count (s/split text #" ")) 0.5))
|
|
|
|
(defn talk [entities target-id text & {:keys [stop?]}]
|
|
(let [initial-time (atom nil)
|
|
stop? (if (nil? stop?) true stop?)]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(let [_ (swap! initial-time #(or % (:total-time screen)))
|
|
target-y (get-in entities [:background :entities target-id :y])
|
|
scale-fn (get-in entities [:background :scale-fn])
|
|
scale (scale-fn target-y)
|
|
height (* scale 36)]
|
|
(run! dialogue/talking-screen :on-talk :text text
|
|
:x (get-in entities [:background :entities target-id :x]) :y (+ (get-in entities [:background :entities target-id :y]) height)
|
|
:target-id target-id
|
|
:scale scale)
|
|
(update-in entities [:background :entities target-id ] #(start-animation screen % :talk))))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities]
|
|
(> (- (:total-time screen)
|
|
@initial-time)
|
|
(get-text-duration text)))
|
|
|
|
(terminate [this screen entities]
|
|
(run! dialogue/talking-screen :stop-talk :target-id target-id)
|
|
(if stop?
|
|
(stop screen entities target-id)
|
|
entities)))))
|
|
|
|
(defn give [entities target-id item]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(sound! (sound "pickup.mp3") :play)
|
|
|
|
(-> entities
|
|
(update-in [:background :entities target-id :inventory] #(conj % item))
|
|
(assoc-in [:cursor :current] item)))
|
|
|
|
(continue [this screen entities] entities)
|
|
|
|
(done? [this screen entities] true)
|
|
|
|
(terminate [this screen entities]
|
|
entities)))
|
|
|
|
(defn transition-background [entities new-background [x y]]
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
|
|
(-> entities
|
|
(assoc-in [:transition]
|
|
(assoc (texture "black.png")
|
|
:scale-x 20
|
|
:scale-y 20
|
|
:baseline 9500
|
|
:opacity 0.1))))
|
|
|
|
(continue [this screen entities]
|
|
(update-in entities [:transition :opacity] + 0.075))
|
|
|
|
(done? [this screen entities]
|
|
(>= (get-in entities [:transition :opacity]) 1.0))
|
|
|
|
(terminate [this screen entities]
|
|
entities))
|
|
(run-action entities
|
|
(begin [this screen entities]
|
|
(let [ego (get-in entities [:background :entities :ego])]
|
|
(-> entities
|
|
(assoc-in [:background] (get-in entities [:backgrounds new-background]))
|
|
(assoc-in [:background :entities :ego] ego)
|
|
(assoc-in [:background :entities :ego :x] x)
|
|
(assoc-in [:background :entities :ego :y] y))))
|
|
|
|
(continue [this screen entities]
|
|
(update-in entities [:transition :opacity] - 0.075))
|
|
|
|
(done? [this screen entities]
|
|
(<= (get-in entities [:transition :opacity]) 0.0))
|
|
|
|
(terminate [this screen entities]
|
|
(dissoc entities :transition))))
|