diff --git a/desktop/src-common/advent/action_test2.clj b/desktop/src-common/advent/action_test2.clj index 51c99b18..4fc7514b 100644 --- a/desktop/src-common/advent/action_test2.clj +++ b/desktop/src-common/advent/action_test2.clj @@ -8,11 +8,6 @@ (terminate [this state])) -(defmacro do-actions [name & forms] - `(vector ~@(for [form forms] - `(fn [~name] - ~form)))) - (defn talk [action-channel who text] (let [c (chan)] @@ -86,8 +81,7 @@ (defn test-run [] (let [state {:x 0 :y 0 :time 0 :items #{} :current-action nil} action-channel (chan) - script (run-script state action-channel) - ] + script (run-script state action-channel)] (script action-channel) (loop [state state current-action nil diff --git a/desktop/src-common/advent/actions.clj b/desktop/src-common/advent/actions.clj index c0fc2358..6da482d0 100644 --- a/desktop/src-common/advent/actions.clj +++ b/desktop/src-common/advent/actions.clj @@ -7,10 +7,21 @@ [clojure.string :as s] [advent.pathfind] [advent.actions :as actions] - [advent.screens.dialogue :as dialogue]) + [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])) + +(defmacro get-script [& forms] + `(fn [action-channel#] (thread ~@forms (put! action-channel# :end)))) + + (defn jump-to [screen entities entity [x y]] (let [scale-fn (-> entities :background :scale-fn) entity (assoc entity :x x @@ -34,58 +45,81 @@ (assoc (jump-to screen entities target-entity [(+ moved-x from-x) (+ moved-y from-y)]) :anim (if (< moved-x 0) left right)))))))) -(defn stop [target-id] - (fn [screen entities] - (let [target (target-id entities)] - (run! dialogue/talking-screen :stop-talk :target-id target-id) - (assoc-in entities [target-id] (merge target - {:anim nil - :actions (rest (:actions target))} - (when (:anim target) - (texture (animation! (:anim target) :get-key-frame 0.25)))))))) +(defn stop [screen entities target-id] + (update-in entities [target-id] #(merge % + {:anim nil} + (when (:anim %) + (texture (animation! (:anim %) :get-key-frame 0.25)))))) -(defn from-path [screen entities target-id [x y]] - (let [entity (target-id entities) - path (vec (take-nth 5 (advent.pathfind/visit-all - (:collision (:background entities)) - [(int (:x entity)) (int (:y entity))] - [(int x) (int y)]))) - actions (when (seq path) - (concat - [(stop target-id)] - (map #(walk-to % target-id) (conj path [x y])) - [(stop target-id)]))] - actions)) + +(defn walk-to [entities target-id [x y]] + (let [c (chan) + entity (entities target-id) + path (take-nth 5 (advent.pathfind/visit-all + (:collision (:background entities)) + [(int (:x entity)) (int (:y entity))] + [(int x) (int y)]))] + (doseq [[target-x target-y] path] + (put! (get-in entities [:actions :channel]) + (reify + IAction + (begin [this screen entities] + (let [{from-x :x from-y :y :keys [left right anim]} (entities target-id)] + (let [delta-x (- target-x from-x)] + (assoc-in entities [target-id :anim] (if (< delta-x 0) left right))))) + + (continue [this screen entities] + (let [{from-x :x from-y :y :keys [left right anim] :as target-entity} (entities target-id)] + (let [delta-x (- target-x from-x) + delta-y (- target-y from-y) + mag (Math/sqrt (+ (* delta-x delta-x) (* delta-y delta-y))) + moved-x (* 1.5 (/ delta-x mag)) + moved-y (* 1.5 (/ delta-y mag))] + (assoc entities target-id + (jump-to screen entities target-entity [(+ moved-x from-x) (+ moved-y from-y)]))))) + + (done? [this screen entities] + (let [{from-x :x from-y :y :keys [left right anim] :as target-entity} (entities target-id)] + (let [delta-x (- target-x from-x) + delta-y (- target-y from-y) + mag (Math/sqrt (+ (* delta-x delta-x) (* delta-y delta-y)))] + (< mag 1)))) + + (terminate [this screen entities] + (put! c entities) + (stop screen entities target-id))))) + ( (- (:total-time screen) - @initial-time) - (get-text-duration text))] - (if done? - (do - (run! dialogue/talking-screen :stop-talk :target-id target-id) - (update-in entities [target-id :actions] rest)) - (do - (when begin? - (run! dialogue/talking-screen :on-talk :text text - :x (get-in entities [target-id :x]) :y (+ (get-in entities [target-id :y]) height) - :target-id target-id - :scale scale)) - (assoc-in entities [target-id :anim] (get-in entities [target-id :talk])))))))) +(defn talk [entities target-id text] + (let [c (chan) + initial-time (atom nil)] + (put! (get-in entities [:actions :channel]) + (reify + IAction + (begin [this screen entities] + (let [_ (swap! initial-time #(or % (:total-time screen))) + target-y (get-in 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 [target-id :x]) :y (+ (get-in entities [target-id :y]) height) + :target-id target-id + :scale scale) + (assoc-in entities [target-id :anim] (get-in entities [target-id :talk])))) + + (continue [this screen entities] entities) + + (done? [this screen entities] + (> (- (:total-time screen) + @initial-time) + (get-text-duration text))) + + (terminate [this screen entities] + (put! c entities) + (run! dialogue/talking-screen :stop-talk :target-id target-id) + (stop screen entities target-id)))) + (! chan go thread take! alts!!]]) (:import [com.badlogic.gdx.graphics Pixmap Pixmap$Filter Texture Texture$TextureFilter] [com.badlogic.gdx.graphics.g2d TextureRegion] [java.lang Object])) @@ -30,16 +31,18 @@ IInteractable (interact [_ screen entities cursor [x y] ] (case cursor - :walk (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego [x y])) - :look (assoc-in entities [:ego :actions] [(actions/stop :ego) - (actions/talk :ego "Looks pretty uninteresting to me.") - (actions/stop :ego)]) - :touch (assoc-in entities [:ego :actions] [(actions/stop :ego) - (actions/talk :ego "Can't do anything with it.") - (actions/stop :ego)]) - :talk (assoc-in entities [:ego :actions] [(actions/stop :ego) - (actions/talk :ego "It's not much of a conversationalist.") - (actions/stop :ego)]))))) + :walk (actions/get-script + (actions/walk-to entities :ego [x y])) + :look (actions/get-script + (actions/talk entities + :ego + "Looks pretty uninteresting to me.")) + :touch (actions/get-script + (actions/talk entities :ego + "Can't do anything with it.")) + :talk (actions/get-script + (actions/talk entities :ego + "It's not much of a conversationalist.")))))) (def +next-cursor+ (into {} (map vector [:walk :touch :look :talk] (drop 1 (cycle [:walk :touch :look :talk]))))) @@ -70,12 +73,17 @@ (get-in entities [:background :interactions]))) current-cursor (get-in entities [:cursor :current]) cursor-override (get-in entities [:cursor :override]) - interacted (or (when cursor-override - (interact cursor-override screen entities current-cursor [x y])) - (when interaction - (interact interaction screen entities current-cursor [x y])) - (interact default-interaction screen entities current-cursor [x y]))] - interacted)) + script (or (when cursor-override + (interact cursor-override screen entities current-cursor [x y])) + (when interaction + (interact interaction screen entities current-cursor [x y])) + (interact default-interaction screen entities current-cursor [x y])) + entities (if-let [current-action (get-in entities [:actions :current])] + (actions/terminate current-action screen entities) + entities)] + + (script (get-in entities [:actions :channel])) + entities)) (defn get-ego [screen] (let [player-sheet (texture! (texture "player.png") :split 18 36) @@ -91,15 +99,22 @@ :origin-x 9 :origin-y 0 :scaled true - :actions [] :x 150 :y 95 :id "ego"}] (merge (texture (animation! (:right ego) :get-key-frame 0.25)) ego))) -(defn update-ego [screen entities ego] - (if-let [action (first (:actions ego))] - (action screen entities) - entities)) +(defn update-from-script [screen {{:keys [current started? channel]} :actions :as entities}] + (if (= :end current) + (assoc entities :actions {:channel channel :current nil :started? false}) + (if current + (let [entities (if started? entities (actions/begin current screen entities)) + entities (actions/continue current screen entities)] + (if (actions/done? current screen entities) + (assoc (actions/terminate current screen entities) + :actions {:channel channel :current nil :started? false}) + (assoc-in entities [:actions :started?] true))) + (let [[current _] (alts!! [channel] :default nil)] + (assoc entities :actions {:channel channel :current current :started? false}))))) (defn scaler-fn-with-baseline [baseline minimum-size & [maximum-size]] (let [maximum-size (or maximum-size 1.0)] @@ -126,6 +141,10 @@ ;;_ (sound! music :loop) ] { + :actions {:object nil + :channel (chan) + :current nil + :started? false} :cursor {:id "cursor" :current :walk } :sheep (assoc (animation->texture screen sheep) :x 38 :y 160 :baseline 160 :anim sheep) :background (assoc {} @@ -136,8 +155,9 @@ (mouse-in? [_ location] (apply (zone/box 300 131 320 224) location)) IInteractable - (interact [_ screen entities _ location] - (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego [319 160]))) + (interact [_ _ entities _ _] + (actions/get-script + (actions/walk-to entities :ego [319 160]))) ICursorOverridable (cursor-override [_] :right)) (reify @@ -145,8 +165,9 @@ (mouse-in? [_ location] (apply (zone/box 60 180 224 240) location)) IInteractable - (interact [_ screen entities _ location] - (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego [137 204]))) + (interact [_ _ entities _ _] + (actions/get-script + (actions/walk-to entities :ego [137 204]))) ICursorOverridable (cursor-override [_] :up)) (reify @@ -154,8 +175,9 @@ (mouse-in? [_ location] (apply (zone/box 0 40 20 140) location)) IInteractable - (interact [_ screen entities _ location] - (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego [0 80]))) + (interact [_ _ entities _ _] + (actions/get-script + (actions/walk-to entities :ego [0 80]))) ICursorOverridable (cursor-override [_] :left))] :interactions [(reify @@ -163,18 +185,16 @@ (mouse-in? [_ location] (apply (zone/box 258 100 281 160) location)) IInteractable - (interact [_ screen entities cursor _] + (interact [_ _ entities cursor _] (case cursor :look - (assoc-in entities [:ego :actions] - [(actions/stop :ego) - (actions/talk :ego (str "The last time I went through that door, Fangald turned me into a frog.")) - (actions/stop :ego)]) + (actions/get-script + (actions/talk entities :ego (str "The last time I went through that door, Fangald turned me into a frog."))) + :touch - (assoc-in entities [:ego :actions] (concat - (actions/from-path screen entities :ego [262 88]) - [(actions/talk :ego (str "Anyone home?")) - (actions/stop :ego)])) + (actions/get-script + (actions/walk-to entities :ego [262 88]) + (actions/talk entities :ego (str "Anyone home?"))) nil))) (reify IMouseIn @@ -184,14 +204,12 @@ (interact [_ screen entities cursor _] (case cursor :look - (assoc-in entities [:ego :actions] [(actions/stop :ego) - (actions/talk :ego (str "It's the coolest sword I've ever seen!")) - (actions/stop :ego)]) + (actions/get-script + (actions/talk entities :ego (str "It's the coolest sword I've ever seen!"))) :touch - (assoc-in entities [:ego :actions] (concat - (actions/from-path screen entities :ego [290 66]) - [(actions/talk :ego (str "Maybe I can pull it out.")) - (actions/stop :ego)])) + (actions/get-script + (actions/walk-to entities :ego [290 66]) + (actions/talk entities :ego "Maybe I can pull it out.")) nil)))] :scale-fn (scaler-fn-with-baseline 110 0.10 1.00) :layers [(assoc background :x 0 :y 0 :baseline 0) @@ -205,7 +223,8 @@ :on-render (fn [screen [entities]] (clear!) - (let [entities (update-ego screen entities (:ego entities)) + (let [entities (update-from-script screen entities) + _ (label! (:fps entities) :set-text (str (game :fps))) entities (if (get-in entities [:sheep :anim])