(ns advent.screens.rooms.inside-antique (:require [advent.screens.rooms :as rooms] [advent.actions :as actions] [advent.screens.items :as items] [advent.utils :as utils] [advent.tween :as tween] [advent.zone :as zone] [clojure.zip :as zip] [play-clj.core :refer :all] [play-clj.ui :refer :all] [play-clj.utils :refer :all] [play-clj.g2d :refer :all])) (def boy-names ["Steve" "Bob" "Bud" "Clement" "Terrence" "Flapjack" "Ticklemonster" "Peter" "Greg" "Dave" "Stu" "Calsbad" "Fatso" "Tanner" "Klug" "Griswold" "Leonardo" "Donatello" "Raphael" "Michelangelo" "Francis" "Ebeneezer" "Pierre" "Finn" "Slade" "Gilbert" "Graham" "Ralphie" "Arthur" "Barney" "Harry" "Gus" "Mortimer" "Walt"]) (defn do-antique-dialogue [entities] (if (< (get-in @entities [:room :entities :ego :x]) (get-in @entities [:room :entities :shopkeep :x])) (actions/do-stop entities :ego :face :right) (actions/do-stop entities :ego :face :left)) (actions/do-dialogue entities :shopkeep "Oh, hello there." :shopkeep "Can I help you?") (let [son-choices ["How long has he been gone?" {:run #(do (actions/respond entities % :shopkeep "5..." :shopkeep "... maybe 6 years." :ego "6 YEARS?!" :shopkeep "There must have been some delay." :shopkeep "He should be back any minute." :ego "... Are you sure he's coming back?" :shopkeep "Of course he is!") (actions/play-animation entities :shopkeep :sigh) (actions/do-dialogue entities :shopkeep "Until then, I just have this grandfather clock to keep me company.")) :choices actions/previous-choices} "So you're just waiting in the dark?" {:run #(do (actions/respond entities % :shopkeep "Somebody's got to guard all of this stuff." :shopkeep "Plus, my son will be back any minute now with those candles.") (actions/play-animation entities :shopkeep :sigh)) :choices actions/previous-choices} "Something else." {:choices actions/something-else}]] (actions/present-choices entities {:choices [(when-not (get-in @entities [:state :opened-blinds?]) "I can barely see anything!") {:run #(actions/respond entities % :shopkeep "Sorry about that, sonny." :shopkeep "My son will be back any minute with some candles.") :choices son-choices} (when (get-in @entities [:state :opened-blinds?]) "I let some light in. Will you open up shop?") {:run #(actions/respond entities % :shopkeep "It's still too dark in here." :shopkeep "Don't worry." :shopkeep "My son will be back any minute with those candles.") :choices son-choices} "What do you have for sale here?" {:run #(actions/respond entities % :shopkeep "We're not open for business right now." :shopkeep "Can't you see the lights are out?" :shopkeep "We'll be open again when my son comes back with some candles.") :choices [(when-not (get-in @entities [:state :opened-blinds?]) "Why don't you just open the curtains?") {:run #(actions/respond entities % :shopkeep "That window doesn't let much light in anyhow." :shopkeep "Plus, my son should be back any minute now.") :choices son-choices} "Is there anything here you will sell?" {:run #(actions/respond entities % :shopkeep "No, not until my son returns.") :choices son-choices} (if (get-in @entities [:state :opened-blinds?]) "Since I got some light in here, will you open up shop?" "If I get some light in here, will you open up shop?") {:run #(actions/respond entities % :shopkeep "No." :shopkeep "I need my son to help around the shop anyways." :shopkeep "And there's a lot to fix up before we're ready to open shop again.") :choices son-choices} "Something else." {:choices actions/something-else}]} (when (= 3 (get-in @entities [:state :mints-eaten])) "Do you still need those lava mints?") {:run #(actions/respond entities % :shopkeep "Of course!" :shopkeep "How am I going to keep all my customers happy?" :ego "But you don't have any customers." :shopkeep "No matter." :shopkeep "Tell Gandarf I need some more." :shopkeep "Pronto!") :choices actions/previous-choices} (when (not= 3 (get-in @entities [:state :mints-eaten])) "Are those lava mints on the desk?") {:run #(actions/respond entities % :shopkeep "They're the finest lava mints in all of Remington." :shopkeep "Hand-brewed and delivered by none other than Gandarf himself!" :shopkeep "They're free for customers." :shopkeep "We're not open for business, but I'll let you have one or two.") :choices actions/previous-choices} (when (and (get-in @entities [:state :wants-toy]) (not (get-in @entities [:state :allowed-to-keep-teddy?]))) "Listen, I really need that teddy bear you have.") {:run #(actions/respond entities % :shopkeep "Why?" :shopkeep "It's my son's favorite toy!" :shopkeep "Why should I give it to you?") :choices ["Because it's the choicest toy I've ever seen!" {:run #(actions/respond entities % :shopkeep "I'm sorry, it's not for sale.") :choices actions/something-else} "Your son said I could have it." {:run #(do (actions/respond entities % :shopkeep "REALLY? You've met him?" :ego "... erm. Yes!" :shopkeep "If you really did meet him, you'll have to prove it." :shopkeep "What is my son's name?")) :choice-fn (fn make-choices [] (let [names (shuffle boy-names)] (into (vec (interleave (take 3 (map #(str "Is it... " % "?") names)) (repeat {:run #(do (actions/respond entities % :shopkeep "No. That's not it.") (actions/play-animation entities :shopkeep :sigh) (actions/do-dialogue entities :ego "Oh. I must be thinking of another long lost son.")) :choices #(-> % zip/left (zip/edit (fn [_] (str "Is it... " (rand-nth names) "?"))) zip/up )}))) [(when ((get-in @entities [:state :clues]) :name) "Herb.") {:run #(do (actions/respond entities % :shopkeep "Yes, that's it!" :shopkeep "You must have really met my son!" :shopkeep "Of course you can keep the teddy bear.") (actions/update-state entities (fn [s] (assoc s :allowed-to-keep-teddy? true))))} "It must have slipped my mind." {:run #(do (actions/respond entities % :shopkeep "I was afraid you might say that.")) :choices #(-> % zip/up zip/up zip/up)}])))}]} "Nevermind." {:run (fn [m] (if (= 3 (get-in @entities [:state :mints-eaten])) (actions/respond entities m :shopkeep "Make sure to tell Gandarf to bring more lava mints.") (actions/respond entities m :shopkeep "Feel free to look around.")) ) }]}))) (defn return-portrait [ entities] (actions/walk-to entities :ego [143 58] :face :left) (actions/play-animation entities :ego :reach) (actions/add-entity entities :portrait (get-in @entities [:room :portrait])) (actions/remove-item entities :portrait)) (defn get-portrait [entities] (actions/walk-to entities :ego [140 58] :face :left) (actions/play-animation entities :ego :reach) (actions/remove-entity entities :portrait) (actions/give entities :portrait) (actions/talk entities :ego "It's a portrait. There's something on the back but it's too dim to read.")) (defn return-teddy [entities] (actions/walk-to entities :ego [242 49] :face :right) (actions/play-animation entities :ego :reach) (actions/add-entity entities :teddy (get-in @entities [:room :teddy])) (actions/remove-item entities :teddy)) (defn has-to-return-teddy? [entities] (and (actions/has-item? entities :teddy) (not (get-in @entities [:state :allowed-to-keep-teddy?])))) (defn choose-correct-blind-state [e] (if (get-in e [:state :opened-blinds?]) (-> e (assoc-in [:room :entities :closed-blinds :opacity] 0.0) (assoc-in [:room :entities :open-blinds :opacity] 1.0) (assoc-in [:room :entities :darken :opacity] 0.0) (assoc-in [:room :entities :glow :opacity] 0.25)) (-> e (assoc-in [:room :entities :closed-blinds :opacity] 1.0) (assoc-in [:room :entities :open-blinds :opacity] 0.0) (assoc-in [:room :entities :darken :opacity] 0.4) (assoc-in [:room :entities :glow :opacity] 0.0)))) (defn make [screen] (let [shopkeep-sheet (texture! (utils/get-texture "inside-antique/shopkeep-talk.png") :split 18 21) shopkeep-stand (animation 0.1 (for [i (flatten [(repeat 30 0) 1 (repeat 50 0) 1 0 1 0])] (aget shopkeep-sheet 0 i))) shopkeep-talk (animation 0.15 (for [i [0 2 0 2 0 3 1 0]] (aget shopkeep-sheet 0 i))) shopkeep-sigh (utils/make-anim "inside-antique/antique-sigh.png" [24 21] 0.12 (flatten [ (range 9) 0 0 ])) beard (utils/make-anim "inside-antique/beard.png" [28 54] 0.5 [0 1 0 2]) teddy (assoc (utils/get-texture "inside-antique/teddy.png") :x 255 :y 95 :baseline 160 :script (actions/get-script entities (actions/walk-to entities :ego [242 49] :face :right) (actions/play-animation entities :ego :reach) (actions/give entities :teddy) (actions/remove-entity entities :teddy) (when (not (get-in @entities [:state :allowed-to-keep-teddy?])) (actions/do-dialogue entities :ego "Aww, a cute teddy bear!" :shopkeep "Don't get any fast ideas." :shopkeep "That teddy bear does not leave my store." :shopkeep "My son would be stricken with grief to find it missing."))))] (rooms/make :music :inside-antique :name "Antique shop" :sounds {:fire-1 (utils/load-sound "inside-antique/fire-1.ogg") :fire-2 (utils/load-sound "inside-antique/fire-2.ogg") :fire-3 (utils/load-sound "inside-antique/fire-3.ogg") } :interactions {:right {:box [250 0 320 75] :cursor :right :script (actions/get-script entities (when (or (actions/has-item? entities :portrait) (has-to-return-teddy? entities)) (actions/walk-to entities :ego [235 15]) (actions/talk entities :shopkeep "Excuse me, sonny. Please return my belongings before you leave.") (when (actions/has-item? entities :portrait) (return-portrait entities)) (when (has-to-return-teddy? entities) (return-teddy entities))) (actions/walk-to entities :ego [235 15] :stop? false :skip-type :end) (actions/walk-straight-to entities :ego [320 -5]) (actions/transition-background entities :inside-castle [182 90]) (actions/walk-to entities :ego [187 75]))} :return-portrait-2 {:box [103 116 131 131] :script (actions/get-script entities (if (actions/has-item? entities :portrait) (actions/talk entities :ego "The shopkeep's portrait used to sit there.") (get-portrait entities) )) :scripts {:portrait (actions/get-script entities (return-portrait entities)) :teddy (actions/get-script entities (return-teddy entities))}} :return-portrait {:box [103 70 206 116] :script (actions/get-script entities (actions/talk entities :ego "It's the shopkeep's desk.")) :scripts {:portrait (actions/get-script entities (return-portrait entities)) :teddy (actions/get-script entities (return-teddy entities))}} :return-teddy {:box [227 90 301 105] :script (actions/get-script entities (actions/talk entities :ego "It's a shelf.")) :scripts {:teddy (actions/get-script entities (return-teddy entities)) :portrait (actions/get-script entities (return-portrait entities))}} :window {:box [195 121 256 190] :script (actions/get-script entities (actions/walk-to entities :ego [207 68] :face :right) (actions/play-animation entities :ego :reach) (actions/update-state entities (fn [s] (assoc s :opened-blinds? (not (:opened-blinds? s))))) (actions/update-entities entities (fn [screen e] (if (get-in e [:state :opened-blinds?]) (-> e (assoc-in [:room :entities :closed-blinds :opacity] 0.0) (assoc-in [:room :entities :open-blinds :opacity] 1.0) (assoc-in [:tweens :fade-darken-out] (tween/tween :fade-darken-out screen [:room :entities :darken :opacity] 0.4 0.0 0.75 :ease tween/ease-out-quadratic)) (assoc-in [:tweens :fade-glow-in] (tween/tween :fade-glow-in screen [:room :entities :glow :opacity] 0.0 0.3 0.75 :ease tween/ease-out-quadratic))) (-> e (assoc-in [:room :entities :closed-blinds :opacity] 1.0) (assoc-in [:room :entities :open-blinds :opacity] 0.0) (assoc-in [:tweens :fade-darken-in] (tween/tween :fade-darken-in screen [:room :entities :darken :opacity] 0.0 0.4 0.75 :ease tween/ease-out-quadratic)) (assoc-in [:tweens :fade-glow-out] (tween/tween :fade-glow-out screen [:room :entities :glow :opacity] 0.3 0.0 0.75 :ease tween/ease-out-quadratic))))) :use-screen? true)) :scripts {:portrait (actions/get-script entities (if (get-in @entities [:state :opened-blinds?]) (do (actions/walk-to entities :ego [142 49] :face :left) (actions/play-animation entities :ego :hold-up-to-window) (actions/talk entities :ego "The portrait says \"Herb\" on the back.") (actions/update-state entities (fn [state] (update-in state [:clues] #(conj % :name)) ))) (do (actions/walk-to entities :ego [142 49] :face :left) (actions/play-animation entities :ego :hold-up-to-window) (actions/talk entities :ego "It's just too dim."))))}} :grandfather-clock {:box [55 70 103 185] :script (actions/get-script entities (actions/do-dialogue entities :ego "Cool grandfather clock!" :shopkeep "It's quite the exquisite piece, isn't it?"))} :shelf {:box [0 60 52 199] :script (actions/get-script entities (actions/walk-to entities :ego [48 58]) (actions/talk entities :ego "All of these trinkets seem too bulky to fit in my pack."))} :flowers {:box [178 115 188 143] :script (actions/get-script entities (actions/talk entities :ego "I've never been a fan of flowers."))} :lian {:box [264 103 317 198] :script (actions/get-script entities (actions/walk-to entities :ego [220 35] :face :right) (actions/do-dialogue entities :ego "It's a tapestry of Rupert the Lion!" :ego "He's the town of Remington's mascot."))} } :layers [(assoc (utils/get-texture "inside-antique/background.png") :x 0 :y 0 :baseline 0) (assoc (utils/get-texture "inside-antique/desk.png") :x 0 :y 0 :baseline 113) (assoc (utils/get-texture "inside-antique/fg.png") :x 0 :y 0 :baseline 320 :parallax 1.5) ] :entities {:shopkeep (actions/start-animation screen (assoc (animation->texture screen shopkeep-stand) :x 148 :y 122 :baseline 112 :stand shopkeep-stand :scale-x 1.6 :scale-y 1.6 :talk-color (color 0.2 1.0 0.2 1.0) :talk shopkeep-talk :sigh shopkeep-sigh :sigh-sound (utils/load-sound "inside-antique/shopkeep-sigh.ogg") :anim-merges {shopkeep-sigh {:origin-x 9} :default {:origin-x 9}} :anim-sound-frames {shopkeep-stand {31 [:blink 0.5 1.5] 81 [:blink 0.5 1.5] 83 [:blink 0.5 1.5]} shopkeep-talk {6 [:blink 0.5 1.5]} shopkeep-sigh {1 [:sigh-sound 1.0]}} :script (actions/get-script entities (do-antique-dialogue entities)) :scripts #(condp = % :teddy (actions/get-script entities (if (get-in @entities [:state :allowed-to-keep-teddy?]) (actions/talk entities :shopkeep "Please give the teddy bear to Herb when you see him.") (actions/talk entities :shopkeep "That belonged to my long lost son."))) :portrait (actions/get-script entities (if (get-in @entities [:state :allowed-to-keep-teddy?]) (actions/talk entities :shopkeep "That's a portrait of my little Herb. " :shopkeep "Please put it back before you leave." ) (actions/do-dialogue entities :shopkeep "Put that back!" :shopkeep "It's been six years since I last saw my son." :shopkeep "I won't let you keep my only portrait of him."))) (actions/get-script entities (actions/talk entities :shopkeep "No thanks, sonny.")))) :stand) :glow (assoc (utils/get-texture "inside-antique/glow.png") :x 0 :y 0 :baseline 240 :additive? true :opacity 0.3) :closed-blinds (assoc (utils/get-texture "inside-antique/closed-blinds.png") :x 0 :y 0 :baseline 0 :opacity 1.0) :open-blinds (assoc (utils/get-texture "inside-antique/open-blinds.png") :x 0 :y 0 :baseline 0 :opacity 0.0) :darken (assoc (utils/get-texture "inside-antique/darken.png") :x 0 :y 0 :baseline 321 :opacity 0.4 ) :beard (assoc (animation->texture screen beard) :anim beard :anim-start 0 :x 69 :y 86 :baseline 120) :smoke-particle (doto (assoc (particle-effect "particles/smoke-particle") :x 162 :y 104 :baseline 240) (particle-effect! :set-position 162 103)) :fire-particle (doto (assoc (particle-effect "particles/fire-particle") :x 162 :y 104 :baseline 240) (particle-effect! :set-position 162 104)) :bowl (assoc (utils/get-texture "inside-antique/bowl.png") :images [(utils/get-texture "inside-antique/bowl-0.png") (utils/get-texture "inside-antique/bowl-1.png") (utils/get-texture "inside-antique/bowl-2.png") (utils/get-texture "inside-antique/bowl-3.png")] :x 165 :y 110 :baseline 125 :script (actions/get-script entities (if (= 3 (get-in @entities [:state :mints-eaten])) (do (actions/walk-to entities :ego [159 58] :face :right) #_(actions/update-state entities (fn [s] (assoc s :mints-eaten 0))) (actions/do-dialogue entities :ego "She's all out." :shopkeep "That's right, I'm all out." :shopkeep "Go tell Gandarf that I need some more brewed up." :shopkeep "Pronto!")) (do (actions/walk-to entities :ego [159 58] :face :right) (if (= 0 (get-in @entities [:state :mints-eaten])) (actions/talk entities :ego "I'll just try one of these mints.") (actions/talk entities :ego "I'll just try another one of these mints.")) (actions/play-animation entities :ego :reach) (actions/update-state entities (fn [s] (assoc s :mints-eaten (inc (s :mints-eaten))))) (actions/update-entities entities (fn [entities] (update-in entities [:room :entities :bowl] (fn [b] (merge b (get-in b [:images (- 3 (get-in entities [:state :mints-eaten] 0))]) ))))) (actions/play-sound entities (keyword (str "fire-" (get-in @entities [:state :mints-eaten]))) 0.8) (cond (= 2 (get-in @entities [:state :mints-eaten])) (do (particle-effect! (get-in @entities [:room :entities :smoke-particle]) :reset) (particle-effect! (get-in @entities [:room :entities :smoke-particle]) :start)) (= 3 (get-in @entities [:state :mints-eaten])) (do (particle-effect! (get-in @entities [:room :entities :fire-particle]) :reset) (particle-effect! (get-in @entities [:room :entities :fire-particle]) :start))) (actions/play-animation entities :ego [:fire (get-in @entities [:state :mints-eaten])]) (actions/talk entities :ego "WOWZA! Those are hot.") (when (= 3 (get-in @entities [:state :mints-eaten])) (actions/do-dialogue entities :shopkeep "Oh drat! You ate the last mint." :shopkeep "It seems like I'm always running out." :shopkeep "Now be a good lad and tell Gandarf that I need some more brewed up." :shopkeep "Pronto!")))))) :teddy teddy} :portrait (rooms/make-entity :portrait (assoc (utils/get-texture "inside-antique/portrait.png") :x 112 :y 114 :baseline 120 :script (actions/get-script entities (get-portrait entities)))) :teddy (rooms/make-entity :teddy teddy) :collision "inside-antique/collision.png" :apply-state (fn [_ entities] (let [mints-eaten (get-in entities [:state :mints-eaten] 0)] (as-> entities entities (if (or (actions/has-item? entities :teddy) (actions/has-obtained? entities :balloon)) (update-in entities [:room :entities] #(dissoc % :teddy)) entities) (update-in entities [:room :entities :bowl] (fn [b] (merge b (get-in b [:images (- 3 mints-eaten)])))) (if (actions/has-item? entities :portrait ) entities (assoc-in entities [:room :entities :portrait] (get-in entities [:room :portrait]))) (choose-correct-blind-state entities) ))) :scale-fn (utils/scaler-fn-with-baseline 110 0.10 1.75) :start-pos [222 3])))