(ns advent.screens.dialogue (:require [play-clj.core :refer :all] [play-clj.ui :refer :all] [play-clj.utils :refer :all] [play-clj.g2d :refer :all] [clojure.tools.logging :as log] [clojure.set :as set] [advent.pathfind] [advent.tween :as tween] [advent.utils :as utils] [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] [com.badlogic.gdx.utils.viewport FitViewport] [com.badlogic.gdx.utils Align] [com.badlogic.gdx.math Vector3 Vector2 Matrix4] [com.badlogic.gdx Screen] [com.badlogic.gdx.scenes.scene2d.utils NinePatchDrawable ] [play_clj.entities NinePatchEntity])) (println "loading " *ns*) (defn ensure-on-screen [talk] (let [margin-width (* 0.05 1280) minimum-x margin-width maximum-x (- 1280 margin-width) label-width (label! talk :get-width) label-right (+ (:x talk) label-width) y (max 30 (min (- 900 (label! talk :get-height)) (:y talk))) talk (cond-> talk (> label-right maximum-x) (assoc :x (- maximum-x label-width)) (< (:x talk) minimum-x) (assoc :x minimum-x) true (assoc :y y))] (doto talk (label! :set-x (:x talk)) (label! :set-y (:y talk))))) (defn scene-world->talk-world [scene-viewport [x y]] (let [[screen-x screen-y] (utils/project {:viewport scene-viewport} [x y]) x (Math/round (/ screen-x (/ (game :width) 1280.0 ))) y (Math/round (/ screen-y (/ (game :height) 960.0 )))] [x y])) (defscreen talking-screen :on-show (fn [screen entities options] (utils/setup-viewport screen 1280 960) {}) :on-render (fn [{:keys [camera ^FitViewport viewport] :as screen} entities options] (.apply viewport) (render! screen (vals entities)) entities) :on-talk (fn [screen entities {:keys [create-talk target-id color text x y scale scene-viewport id]}] (let [font (doto (bitmap-font "ego/font.fnt" ) (bitmap-font! :set-use-integer-positions false)) tr (bitmap-font! font :get-region) scale (* scale (/ utils/ui-scale 2)) scale (or (min (max scale (/ utils/ui-scale 5) 0.4) (/ utils/ui-scale 4)) (/ utils/ui-scale 4)) _ (.setFilter (.getTexture tr) Texture$TextureFilter/Linear Texture$TextureFilter/Linear) style (style :label font color) [source-x source-y] [x y] [x y] (scene-world->talk-world scene-viewport [source-x source-y]) talk (-> (label text style :set-font-scale scale :set-alignment Align/bottom) (assoc :source-x source-x :source-y source-y) (doto (label! :set-wrap true) (#(label! % :set-width (min (* (+ 1 (* 0.5 (- utils/ui-scale 1))) 700) (+ 50 (label! % :get-width)))))) (#(utils/add-actor-to-stage screen %))) x (- x (/ (label! talk :get-width) 2)) talk (assoc talk :x x :y y :id id) talk (ensure-on-screen talk)] (assoc entities id talk))) :on-update-camera (fn [{:keys [^FitViewport viewport] :as screen} entities {:keys [scene-viewport scene-camera]}] (reduce-kv (fn [entities id e] (if (:id e) (let [[x y] (scene-world->talk-world scene-viewport [(:source-x e) (:source-y e)])] (-> entities (assoc-in [id :x] (- x (/ (label! e :get-width) 2))) (assoc-in [id :y] y) (update-in [id] ensure-on-screen))) entities)) entities entities)) :stop-talk (fn [screen entities {:keys [id]}] (utils/remove-actor-from-stage entities (or id :fg-actions)) (dissoc entities (or id :fg-actions))) :on-resize (fn [{:keys [^FitViewport viewport]} entities {:keys [width height]}] (.update viewport width height))) (def choice-height 40) (defn get-color [e mouse-pos] (if (utils/intersects? e mouse-pos) (color :yellow) (color 0.6 1.0 1.0 1.0) )) (defn style-label [e font mouse-pos] (table! (:label e) :set-style (style :label font (get-color e mouse-pos))) e) (defn mouse-moved [screen entities options] (let [[x y] (utils/unproject screen options) entities (assoc-in entities [:state :last-pos] [x y]) choice-count (dec (count entities))] (when-let [table (get-in entities [:state :table])] (doseq [e (get-in entities [:state :labels])] (style-label e (get-in entities [:state :font]) [x y]))) entities)) (defscreen choice-screen :on-show (fn [screen entities options] (utils/setup-viewport screen 1280 960) (let [font (bitmap-font "ego/font.fnt" ) tr (bitmap-font! font :get-region) scale 1 p (NinePatchEntity. (skin! (skin "ui/ui.json") :get-patch "ui-bg")) _ (nine-patch! p :set-padding 25 25 5 15) _ (.setFilter (.getTexture tr) Texture$TextureFilter/Linear Texture$TextureFilter/Linear)] {:state {:object nil :callback nil :choices [] :last-pos [0 0] :font font :bg p }})) :on-pinch (fn [screen entities {:keys [initial-pointer-1 initial-pointer-2]}] (assoc-in entities [:state :pinching] true)) :on-render (fn [{:keys [^FitViewport viewport] :as screen} entities options] (.apply viewport) (let [entities (update-in entities [:state :bg] (fn [bg] (assoc bg :x 0 :y 0 :width 1280 :height (get-in entities [:state :table :height] 0)) ))] (when (seq (get-in entities [:state :choices])) (render! screen [(get-in entities [:state :bg])]) (render! screen [(get-in entities [:state :table])]) #_(render! screen (vals entities)))) entities) :on-present-choices (fn [screen entities {:keys [choices callback]}] (let [choice-count (count choices) font (get-in entities [:state :font]) label-width (- 1280 (* utils/ui-scale 100)) labels (vec (->> (for [[[text] i] (map vector choices (range))] (assoc (label text (style :label font (color 0.6 1.0 1.0 1.0)) :set-wrap true :set-alignment Align/bottomLeft :set-font-scale (* utils/ui-scale 0.25) :set-width label-width) :index i :width label-width)) (map (fn [l] (assoc (table [[l :width label-width :pad-bottom (* utils/ui-scale 12) :pad-top (* utils/ui-scale 12)]]) :label l :index (:index l))))))] (-> entities (assoc-in [:state :choices] choices) (assoc-in [:state :callback] callback) (assoc-in [:state :labels] labels) (assoc-in [:state :table] (doto (-> labels (vertical :align Align/bottomLeft :pad (* utils/ui-scale 20)) (#(utils/add-actor-to-stage screen %)) (assoc :x 0 :y 0 :width 1240) (#(assoc % :height (vertical! % :get-pref-height))) )))))) :on-touch-up (fn [screen entities options] (let [[x y] (utils/unproject screen options)] (if (and (seq (get-in entities [:state :choices])) (not (get-in entities [:state :pinching]))) (when-let [choice (first (filter #(utils/intersects? % [x y]) (get-in entities [:state :labels])))] (utils/clear-stage screen) ((get-in entities [:state :callback]) (:index choice)) (-> entities (assoc-in [:state :callback] nil) (assoc-in [:state :pinching] false) (assoc-in [:state :choices] []) (assoc-in [:state :labels] []) (assoc-in [:state :table] nil) (select-keys [:state]))) (assoc-in entities [:state :pinching] false)))) :on-mouse-moved mouse-moved :on-touch-dragged mouse-moved :on-touch-down mouse-moved :on-resize (fn [{:keys [^FitViewport viewport]} entities {:keys [width height]}] (.update viewport width height))) (defscreen toast-screen :on-show (fn [screen entities options] (utils/setup-viewport screen 1280 960) {}) :on-render (fn [{:keys [camera ^FitViewport viewport] :as screen} entities options] (.apply viewport) (let [entities (utils/apply-tweens screen entities (:tweens entities))] (when (:dialogue entities) (label! (:dialogue entities) :set-color (color 1.0 0.0 0.0 (:opacity (:dialogue entities))))) (render! screen (vals entities)) entities)) :on-toast (fn [screen entities {:keys [message]}] (let [font (bitmap-font "ego/font.fnt" ) tr (bitmap-font! font :get-region) _ (.setFilter (.getTexture tr) Texture$TextureFilter/Linear Texture$TextureFilter/Linear) style (style :label font (color :red)) [x y] [(/ 1280 2) (/ 960 2)] talk (label message style :set-alignment Align/center :set-font-scale 0.25) x (- x (/ (label! talk :get-width) 2)) talk (assoc talk :x x :y y :opacity 1.0) #_#_talk (ensure-on-screen talk)] (utils/add-actor-to-stage screen talk) (-> entities (assoc :dialogue talk) (assoc-in [:tweens :fade-out-toast] (tween/tween :fade-out-toast screen [:dialogue :opacity] 1.0 0.0 1.0 :finish #(do (utils/remove-actor-from-stage entities :dialogue) (dissoc % :dialogue))))))) :stop-talk (fn [_ entities {:keys [target-id]}] (utils/remove-actor-from-stage entities :dialogue) (dissoc entities :dialogue)) :on-resize (fn [{:keys [^FitViewport viewport]} entities {:keys [width height]}] (.update viewport width height))) (defscreen tooltip-screen :on-show (fn [screen entities options] (let [screen (utils/setup-viewport screen 1280 960)] (let [font (doto (bitmap-font "label-font.fnt" ) (bitmap-font! :set-use-integer-positions false)) tr (bitmap-font! font :get-region) _ (.setFilter (.getTexture tr) Texture$TextureFilter/Linear Texture$TextureFilter/Linear) style (doto (style :label font (color :white)) (#(-> % .font .getData (.setScale (/ utils/ui-scale 4)))))] {:label (as-> (label "" style) l (do (label! l :set-alignment (if utils/mobile? Align/bottomLeft Align/center)) (label! l :set-font-scale (* utils/ui-scale 0.25)) l) (assoc l :x 0 :y 0 :baseline 10000) (utils/add-actor-to-stage screen l)) :all-icons (texture! (texture (pixmap "cursor.png")) :split 18 16) :action-icon nil}))) :on-render (fn [{:keys [camera ^FitViewport viewport] :as screen} entities options] (.apply viewport) (let [entities (utils/apply-tweens screen entities (:tweens entities))] (render! screen [(:label entities) (or (:action-icon entities) (:item-icon entities) )]) entities)) :on-hover-start (fn [screen {:keys [all-icons] :as entities} {:keys [hover-text x y scene-viewport cursor ]}] (let [x (if utils/mobile? x (+ 8 x)) [scene-x scene-y] (scene-world->talk-world scene-viewport [x y]) depressed? (< 0.5 (- (or (:total-time screen) 0) (int (or (:total-time screen) 0)))) item-cursor (:cursor (first (:last cursor))) action-cursor (utils/translate-depressed (first (:last cursor)) depressed?)] (label! (get-in entities [:label]) :set-text hover-text) (cond-> entities true (assoc-in [:label :text] hover-text) utils/mobile? (update-in [:label] assoc :x (* 52 4 utils/ui-scale) :y 12) (and utils/mobile? (or item-cursor action-cursor) (= :main action-cursor)) (assoc :action-icon nil) item-cursor (assoc :action-icon nil) (and utils/mobile? action-cursor (not item-cursor) (not= :main action-cursor)) (assoc-in [:action-icon] (assoc ;; todo reflection here (texture (aget all-icons 0 (.indexOf utils/+all-cursors+ (or item-cursor action-cursor)))) :x (* utils/ui-scale 32 4) :y (* utils/ui-scale 4) :width (* 18 4 utils/ui-scale) :height (* 16 4 utils/ui-scale))) (not utils/mobile?) (update-in [:label] assoc :x scene-x :y scene-y) true (update-in [:label] ensure-on-screen)))) :on-select-item (fn [screen {:keys [all-icons] :as entities} {:keys [selected-item upright? in-or-out hide-or-show notify]}] (let [fade-tween (if (= :hide hide-or-show) (tween/tween :appear-item screen [:item-icon :opacity] 1.0 0.0 0.5 :ease tween/ease-linear :finish (fn [entities] (reset! notify true) (dissoc entities :item-icon))) (tween/tween :appear-item screen [:item-icon :opacity] 0.0 1.0 0.5 :ease tween/ease-linear :finish (fn [entities] (reset! notify true) entities))) move-tween (condp = in-or-out :far-out (tween/tween :appear-item-y screen [:item-icon :x] (* utils/ui-scale 4 40) (* utils/ui-scale 4 45) 0.5 :ease tween/ease-linear) :out (tween/tween :appear-item-y screen [:item-icon :x] (* utils/ui-scale 4 35) (* utils/ui-scale 4 40) 0.5 :ease tween/ease-linear) :in (tween/tween :appear-item-y screen [:item-icon :x] (* utils/ui-scale 4 40) (* utils/ui-scale 4 35) 0.5 :ease tween/ease-linear) :none (tween/tween :appear-item-y screen [:item-icon :x] (* utils/ui-scale 4 40) (* utils/ui-scale 4 40) 0.5 :ease tween/ease-linear))] (-> entities (assoc :item-icon (assoc (texture (aget all-icons 0 (.indexOf utils/+all-cursors+ (:cursor selected-item)))) :origin-x 8 :origin-y 0 :scale-x (* 4 utils/ui-scale) :scale-y (* 4 utils/ui-scale) :x (* utils/ui-scale 4 (condp = in-or-out :in 40 :out 35 :none 40 :far-out 40)) :y 0 :baseline 9000 :opacity (if (= :hide hide-or-show) 1.0 0.0) :item selected-item)) (assoc-in [:tweens :appear-item] fade-tween) (assoc-in [:tweens :appear-item-y] move-tween)))) #_#_:on-update-camera (fn [{:keys [^FitViewport viewport] :as screen} entities {:keys [scene-viewport scene-camera]}] (reduce-kv (fn [entities id e] (if (:id e) (let [[x y] (scene-world->talk-world scene-viewport [(:source-x e) (:source-y e)])] (-> entities (assoc-in [id :x] (- x (/ (label! e :get-width) 2))) (assoc-in [id :y] y) (update-in [id] ensure-on-screen))) entities)) entities entities)) #_#_:on-hover-end (fn [screen entities {:keys [id]}] (utils/remove-actor-from-stage entities (or id :fg-actions)) (dissoc entities (or id :fg-actions))) :on-resize (fn [{:keys [^FitViewport viewport]} entities {:keys [width height]}] (.update viewport width height)))