(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.pprint] [clojure.set :as set] [advent.pathfind] [advent.tween :as tween] [advent.utils :as utils] [clojure.core.async :refer [put! ! >!! chan go thread take! alts!!]] #_[advent.screens.scene :as scene]) (: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.scenes.scene2d.utils Align] [com.badlogic.gdx.math Vector3 Vector2 Matrix4] [com.badlogic.gdx Screen] [play_clj.entities NinePatchEntity])) (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 (min (- 900 (label! talk :get-height)) (:y talk)) talk (assoc (cond (> label-right maximum-x) (assoc talk :x (- maximum-x label-width)) (< (:x talk) minimum-x) (assoc talk :x minimum-x) :else talk) :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] (utils/setup-viewport screen 1280 960) {}) :on-render (fn [{:keys [camera ^FitViewport viewport] :as screen} [entities]] (.apply viewport) (render! screen (vals entities)) entities) :on-talk (fn [{:keys [create-talk target-id color text x y scale scene-viewport id] :as screen} [entities]] (let [font (bitmap-font "ego/font.fnt" ) p (NinePatchEntity. (skin! (skin "ui/ui.json") :get-patch "ui-bg")) _ (nine-patch! p :set-padding 25 25 5 15) bg (drawable :nine-patch (:object p)) _ (bitmap-font! font :set-markup-enabled true) tr (bitmap-font! font :get-region) scale (/ scale 2) scale (or (min (max scale 0.2) 0.25) 0.25) tx (.getTexture tr) _ (texture! tx :set-filter Texture$TextureFilter/Linear Texture$TextureFilter/Linear) style (style :label font color) #_#__ (set! (.background style) bg) [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 700 (+ 50 (label! % :get-width))))) )) 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 [scene-viewport scene-camera viewport] :as screen} [ entities]] (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 [{:keys [id] } [entities]] (dissoc entities (or id :fg-actions))) :on-resize (fn [{:keys [viewport width height]} entities] (.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] (label! e :set-style (style :label font (get-color e mouse-pos))) e) (defscreen choice-screen :on-show (fn [screen entities] (utils/setup-viewport screen 1280 960) (let [font (bitmap-font "ego/font.fnt" ) tr (bitmap-font! font :get-region) scale 1 tx (.getTexture tr) p (NinePatchEntity. (skin! (skin "ui/ui.json") :get-patch "ui-bg")) _ (nine-patch! p :set-padding 25 25 5 15) _ (texture! tx :set-filter Texture$TextureFilter/Linear Texture$TextureFilter/Linear)] {:state {:object nil :callback nil :choices [] :last-pos [0 0] :font font :np (assoc p :x 5 :y 5 :width 1270)}})) :on-render (fn [{:keys [^FitViewport viewport] :as screen} [entities]] (.apply viewport) (when (seq (get-in entities [:state :choices])) (render! screen [(get-in entities [:state :np])]) (render! screen (vals entities))) entities) :on-present-choices (fn [{:keys [choices callback]} [entities]] (let [choice-count (count choices) font (get-in entities [:state :font])] (-> entities (into (for [[[text] i] (map vector choices (range)) :let [e (label text (style :label font (color 0.6 1.0 1.0 1.0)) :set-alignment Align/bottomLeft) e (assoc e :height choice-height :x 30 :y (+ 25 (* choice-height (- choice-count i 1))) :index i) e (style-label e font (get-in entities [:state :last-pos]))]] [i (doto e (label! :set-x (:x e)) (label! :set-y (:y e)) (label! :set-height (:height e)) (label! :set-font-scale 0.25))])) (assoc-in [:state :choices] choices) (assoc-in [:state :callback] callback) (assoc-in [:state :np :height] (* choice-height (inc choice-count)))))) :on-touch-up (fn [screen [entities]] (let [[x y] (utils/unproject screen)] (when (seq (get-in entities [:state :choices])) (when-let [choice (first (filter #(utils/intersects? % [x y]) (vals entities)))] ((get-in entities [:state :callback]) (:index choice)) (-> entities (assoc-in [:state :callback] nil) (assoc-in [:state :choices] []) (select-keys [:state])))))) :on-mouse-moved (fn [screen [entities]] (let [[x y] (utils/unproject screen) entities (assoc-in entities [:state :last-pos] [x y]) choice-count (dec (count entities))] (doseq [e (vals entities) :when (:object e)] (style-label e (get-in entities [:state :font]) [x y])) entities)) :on-resize (fn [{:keys [width height viewport]} entities] (.update viewport width height))) (defscreen toast-screen :on-show (fn [screen entities] (utils/setup-viewport screen 1280 960) {}) :on-render (fn [{:keys [camera ^FitViewport viewport] :as screen} [entities]] (.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 [{:keys [message] :as screen} [entities]] (let [font (bitmap-font "ego/font.fnt" ) p (nine-patch {:region (:object (utils/get-texture "talk-bg-2.png")) :left 9 :top 9 :right 9 :bottom 9}) _ (nine-patch! p :set-padding 25 25 5 15) bg (drawable :nine-patch (:object p)) _ (bitmap-font! font :set-markup-enabled true) tr (bitmap-font! font :get-region) tx (.getTexture tr) _ (texture! tx :set-filter 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)] (-> 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 #(dissoc % :dialogue)))))) :stop-talk (fn [{:keys [target-id] } [entities]] (dissoc entities :dialogue)) :on-resize (fn [{:keys [viewport width height]} entities] (.update viewport width height)))