diff --git a/src/clj/game/core/commands.clj b/src/clj/game/core/commands.clj index 0c5c30bea7..1611881c7f 100644 --- a/src/clj/game/core/commands.clj +++ b/src/clj/game/core/commands.clj @@ -34,7 +34,7 @@ [game.core.winning :refer [clear-win]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer [dissoc-in enumerate-str quantify safe-split - same-card? same-side? server-card string->num]] + same-card? same-side? server-card string->num side-str]] [jinteki.utils :refer [str->int]])) (defn- constrain-value @@ -58,7 +58,7 @@ (defn command-save-replay [state _] (swap! state assoc-in [:options :save-replay] true)) -(defn command-bug-report [state side] +(defn command-bug-report [state _side] (swap! state update :bug-reported (fnil inc -1)) (let [title "[EDITME] Please give a short description of your bug here" body (str "Link to bug replay: https://jinteki.net/bug-report/" (:gameid @state) @@ -375,18 +375,20 @@ "/adv-counter" #(command-adv-counter %1 %2 value) "/bp" #(swap! %1 assoc-in [%2 :bad-publicity :base] (constrain-value value -1000 1000)) "/bug" command-bug-report - "/card-info" #(resolve-ability %1 %2 + "/card-info" (fn [state side] + (resolve-ability state side {:effect (effect (system-msg (str "shows card-info of " (card-str state target) ": " (get-card state target)))) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/card-info command"}) nil) - "/charge" #(resolve-ability %1 %2 - {:prompt "Choose an installed card" - :async true - :effect (req (charge-card %1 %2 eid target)) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/charge command"}) nil) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/card-info command"}) nil)) + "/charge" (fn [state side] + (resolve-ability state side + {:prompt "Choose an installed card" + :async true + :effect (req (charge-card state side eid target)) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/charge command"}) nil)) "/clear-win" clear-win "/click" #(swap! %1 assoc-in [%2 :click] (constrain-value value 0 1000)) "/close-prompt" command-close-prompt @@ -394,19 +396,21 @@ "/credit" #(swap! %1 assoc-in [%2 :credit] (constrain-value value 0 1000)) "/deck" #(toast %1 %2 "/deck number takes the format #n") "/derez" command-derez - "/disable-card" #(resolve-ability %1 %2 + "/disable-card" (fn [state side] + (resolve-ability state side {:prompt "Choose a card to disable" :effect (req (disable-card state side target)) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/disable-card command"}) nil) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/disable-card command"}) nil)) "/discard" #(toast %1 %2 "/discard number takes the format #n") "/discard-random" #(move %1 %2 (rand-nth (get-in @%1 [%2 :hand])) :discard) "/draw" #(draw %1 %2 (make-eid %1) (constrain-value value 0 1000)) - "/enable-card" #(resolve-ability %1 %2 + "/enable-card" (fn [state side] + (resolve-ability state side {:prompt "Choose a card to enable" :effect (req (enable-card state side target)) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/enable-card command"}) nil) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/enable-card command"}) nil)) "/end-run" (fn [state side] (when (and (= side :corp) (:run @state)) @@ -432,97 +436,114 @@ "/memory" (fn [state side] (when (= side :runner) (swap! state assoc-in [:runner :memory :used] (constrain-value value -1000 1000)))) - "/move-bottom" #(resolve-ability %1 %2 + "/move-bottom" (fn [state side] + (resolve-ability state side {:prompt "Choose a card in hand to put on the bottom of your deck" :effect (effect (move target :deck)) - :choices {:card (fn [t] (and (same-side? (:side t) %2) + :choices {:card (fn [t] (and (same-side? (:side t) side) (in-hand? t)))}} - (make-card {:title "/move-bottom command"}) nil) - "/move-deck" #(resolve-ability %1 %2 + (make-card {:title "/move-bottom command"}) nil)) + "/move-deck" (fn [state side] + (resolve-ability state side {:prompt "Choose a card to move to the top of your deck" - :effect (req (let [c (deactivate %1 %2 target)] - (move %1 %2 c :deck {:front true}))) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/move-deck command"}) nil) - "/move-hand" #(resolve-ability %1 %2 - {:prompt "Choose a card to move to your hand" - :effect (req (let [c (deactivate %1 %2 target)] - (move %1 %2 c :hand))) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/move-hand command"}) nil) + :effect (req (let [c (deactivate state side target)] + (move state side c :deck {:front true}))) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/move-deck command"}) nil)) + "/move-hand" (fn [state side] + (resolve-ability state side + {:prompt "Choose a card to move to your hand" + :effect (req (let [c (deactivate state side target)] + (move state side c :hand))) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/move-hand command"}) nil)) "/peek" #(command-peek %1 %2 value) - "/psi" #(when (= %2 :corp) (psi-game %1 %2 - (make-card {:title "/psi command" :side %2}) - {:equal {:msg "resolve equal bets effect"} - :not-equal {:msg "resolve unequal bets effect"}})) + "/psi" (fn [state side] + (when (= side :corp) + (psi-game state side + (make-card {:title "/psi command"}) + {:equal {:msg "resolve equal bets effect"} + :not-equal {:msg "resolve unequal bets effect"}}))) "/reload-id" command-reload-id "/replace-id" #(command-replace-id %1 %2 args) - :async true - "/rez" #(when (= %2 :corp) - (resolve-ability %1 %2 - {:choices {:card (fn [t] (same-side? (:side t) %2))} + "/rez" (fn [state side] + (when (= side :corp) + (resolve-ability state side + {:choices {:card (fn [t] (same-side? (:side t) side))} :async true :effect (effect (rez eid target {:ignore-cost :all-costs :force true}))} - (make-card {:title "/rez command"}) nil)) + (make-card {:title "/rez command"}) nil))) "/rez-all" #(when (= %2 :corp) (command-rezall %1 %2)) - "/rez-free" #(when (= %2 :corp) - (resolve-ability %1 %2 - {:choices {:card (fn [t] (same-side? (:side t) %2))} + "/rez-free" (fn [state side] + (when (= side :corp) + (resolve-ability state side + {:choices {:card (fn [t] (same-side? (:side t) side))} :async true :effect (effect (disable-card target) (rez eid target {:ignore-cost :all-costs :force true}) (enable-card (get-card state target)))} - (make-card {:title "/rez command"}) nil)) - "/rfg" #(resolve-ability %1 %2 - {:prompt "Choose a card" - :effect (req (let [c (deactivate %1 %2 target)] - (move %1 %2 c :rfg))) - :choices {:card (fn [t] (same-side? (:side t) %2))}} - (make-card {:title "/rfg command"}) nil) + (make-card {:title "/rez command"}) nil))) + "/rfg" (fn [state side] + (resolve-ability state side + {:prompt "Choose a card" + :effect (req (let [c (deactivate state side target)] + (move state side c :rfg))) + :choices {:card (fn [t] (same-side? (:side t) side))}} + (make-card {:title "/rfg command"}) nil)) "/roll" #(command-roll %1 %2 value) "/sabotage" #(when (= %2 :runner) (resolve-ability %1 %2 (sabotage-ability (constrain-value value 0 1000)) nil nil)) "/save-replay" command-save-replay "/set-mark" #(command-set-mark %1 %2 args) - "/show-hand" #(resolve-ability %1 %2 - {:effect (effect (system-msg (str + "/show-hand" #(resolve-ability %1 %2 + {:effect (effect (system-msg (str (if (= :corp %2) "shows cards from HQ: " "shows cards from the grip: ") (enumerate-str (sort (map :title (:hand (if (= side :corp) corp runner))))))))} nil nil) "/summon" #(command-summon %1 %2 args) - "/swap-ice" #(when (= %2 :corp) + "/swap-ice" (fn [state side] + (when (= side :corp) (resolve-ability - %1 %2 + state side {:prompt "Choose two installed ice to swap" - :choices {:max 2 - :all true - :card (fn [c] (and (installed? c) + :choices {:max 2 + :all true + :card (fn [c] (and (installed? c) (ice? c)))} - :effect (effect (swap-ice (first targets) (second targets)))} - (make-card {:title "/swap-ice command"}) nil)) - "/swap-installed" #(when (= %2 :corp) + :effect (effect (swap-ice (first targets) (second targets)))} + (make-card {:title "/swap-ice command"}) nil))) + "/swap-installed" (fn [state side] + (when (= side :corp) (resolve-ability - %1 %2 + state side {:prompt "Choose two installed non-ice to swap" - :choices {:max 2 - :all true - :card (fn [c] (and (installed? c) + :choices {:max 2 + :all true + :card (fn [c] (and (installed? c) (corp? c) (not (ice? c))))} - :effect (effect (swap-installed (first targets) (second targets)))} - (make-card {:title "/swap-installed command"}) nil)) - "/tag" #(swap! %1 assoc-in [%2 :tag :base] (constrain-value value 0 1000)) - "/take-core" #(when (= %2 :runner) (damage %1 %2 (make-eid %1) :brain (constrain-value value 0 1000) - {:card (make-card {:title "/damage command" :side %2})})) - "/take-meat" #(when (= %2 :runner) (damage %1 %2 (make-eid %1) :meat (constrain-value value 0 1000) - {:card (make-card {:title "/damage command" :side %2})})) - "/take-net" #(when (= %2 :runner) (damage %1 %2 (make-eid %1) :net (constrain-value value 0 1000) - {:card (make-card {:title "/damage command" :side %2})})) - "/trace" #(when (= %2 :corp) (init-trace %1 %2 - (make-card {:title "/trace command" :side %2}) - {:base (constrain-value value -1000 1000) - :msg "resolve successful trace effect"})) + :effect (effect (swap-installed (first targets) (second targets)))} + (make-card {:title "/swap-installed command"}) nil))) + "/tag" #(swap! %1 assoc-in [%2 :tag :base] (constrain-value value 0 1000)) + "/take-core" (fn [state side] + (when (= side :runner) + (damage state side (make-eid state) :brain (constrain-value value 0 1000) + {:card (make-card {:title "/damage command" :side (side-str side)})}))) + "/take-meat" (fn [state side] + (when (= side :runner) + (damage state side (make-eid state) :meat (constrain-value value 0 1000) + {:card (make-card {:title "/damage command" :side (side-str side)})}))) + "/take-net" (fn [state side] + (when (= side :runner) + (damage state side (make-eid state) :net (constrain-value value 0 1000) + {:card (make-card {:title "/damage command" :side (side-str side)})}))) + "/trace" (fn [state side] + (when (= side :corp) + (init-trace state side + (make-card {:title "/trace command"}) + {:base (constrain-value value -1000 1000) + :msg "resolve successful trace effect"}))) "/trash" command-trash "/undo-click" #(command-undo-click %1 %2) "/undo-turn" #(command-undo-turn %1 %2) diff --git a/src/clj/game/core/servers.clj b/src/clj/game/core/servers.cljc similarity index 100% rename from src/clj/game/core/servers.clj rename to src/clj/game/core/servers.cljc diff --git a/src/clj/game/core/toasts.clj b/src/clj/game/core/toasts.clj index ca6a9bb437..2d508cd913 100644 --- a/src/clj/game/core/toasts.clj +++ b/src/clj/game/core/toasts.clj @@ -13,14 +13,17 @@ ([state side message msg-type] (toast state side message msg-type nil)) ([state side message msg-type options] ;; Allows passing just the toast msg-type as the options parameter - (when message - ;; normal toast - add to list - (swap! state update-in [side :toast] #(conj % {:msg message :type msg-type :options options :id (random-uuid)}))))) + (when message + (let [new-toast {:id (random-uuid) + :msg message + :type msg-type + :options options}] + ;; normal toast - add to list + (swap! state update-in [side :toast] conj new-toast))))) (defn ack-toast - ([state side {:keys [id]}] - (when-let [id (when (string? id) (parse-uuid id))] - (swap! state update-in [side :toast] (fn [toasts] (remove #(= (:id %) id) toasts)))))) + [state side {:keys [id]}] + (swap! state update-in [side :toast] (fn [toasts] (remove #(= (:id %) id) toasts)))) (defn show-error-toast [state side] diff --git a/src/clj/game/utils.clj b/src/clj/game/utils.cljc similarity index 91% rename from src/clj/game/utils.clj rename to src/clj/game/utils.cljc index 061e70d7d1..c158528e0a 100644 --- a/src/clj/game/utils.clj +++ b/src/clj/game/utils.cljc @@ -1,11 +1,10 @@ (ns game.utils (:require - [jinteki.cards :refer [all-cards]] [clojure.string :as str] - [clj-uuid :as uuid])) + [jinteki.cards :refer [all-cards]])) (defn make-cid [] - (uuid/to-string (uuid/v4))) + (str (random-uuid))) (defn server-card ([title] (server-card title true)) @@ -15,7 +14,8 @@ (and title card) card (or (= title "Corp Basic Action Card") (= title "Runner Basic Action Card")) {} :else (when strict? - (throw (Exception. (str "Tried to select server-card for " title)))))))) + (throw #?(:clj (Exception. (str "Tried to select server-card for " title)) + :cljs (js/Error. (str "Tried to select server-card for " title))))))))) (defn server-cards [] @@ -46,10 +46,8 @@ (step coll #{}))) (defn string->num [s] - (try - (let [num (bigdec s)] - (if (and (> num Integer/MIN_VALUE) (< num Integer/MAX_VALUE)) (int num) num)) - (catch Exception _ nil))) + (when s + (parse-long s))) (def safe-split (fnil str/split "")) diff --git a/src/clj/web/game.clj b/src/clj/web/game.clj index 922804cd01..ab1dd96c49 100644 --- a/src/clj/web/game.clj +++ b/src/clj/web/game.clj @@ -1,8 +1,8 @@ (ns web.game (:require - [cheshire.core :as json] [cljc.java-time.instant :as inst] [clojure.stacktrace :as stacktrace] + [clojure.walk :refer [postwalk]] [cond-plus.core :refer [cond+]] [game.core :as core] [game.core.diffs :as diffs] @@ -14,17 +14,26 @@ [web.stats :as stats] [web.ws :as ws])) +(defn serialize-edn [obj] + (cond (record? obj) (into {} obj) + (instance? org.bson.types.ObjectId obj) (str obj) + (instance? java.time.Instant obj) (str obj) + (instance? clojure.lang.LazySeq obj) (into [] obj) + (fn? obj) (str obj) + :else + obj)) + (defn game-diff-json "Converts the appropriate diff to json" [gameid side {:keys [runner-diff corp-diff spect-diff]}] - (json/generate-string {:gameid gameid - :diff (cond - (= side "Corp") - corp-diff - (= side "Runner") - runner-diff - :else - spect-diff)})) + (postwalk + serialize-edn + {:gameid gameid + :diff (cond + (= side "Corp") corp-diff + (= side "Runner") runner-diff + :else spect-diff)})) + (defn send-state-diffs "Sends diffs generated by public-diffs to all connected clients." @@ -45,7 +54,8 @@ (send-state-diffs lobby diffs)))) (defn select-state [side {:keys [runner-state corp-state spect-state]}] - (json/generate-string + (postwalk + serialize-edn (case side "Corp" corp-state "Runner" runner-state diff --git a/src/cljc/game/core/card.cljc b/src/cljc/game/core/card.cljc index 28d099199b..094251b54e 100644 --- a/src/cljc/game/core/card.cljc +++ b/src/cljc/game/core/card.cljc @@ -87,41 +87,34 @@ (defn in-server? "Checks if the specified card is installed in -- and not PROTECTING -- a server" [card] - (= (last (get-zone card)) #?(:clj :content - :cljs "content"))) + (= (last (get-zone card)) :content)) (defn in-hand? "Checks if the specified card is in the hand." [card] - (= (get-zone card) #?(:clj [:hand] - :cljs ["hand"]))) + (= (get-zone card) [:hand])) (defn in-discard? "Checks if the specified card is in the discard pile." [card] - (= (get-zone card) #?(:clj [:discard] - :cljs ["discard"]))) + (= (get-zone card) [:discard])) (defn in-deck? "Checks if the specified card is in the draw deck." [card] - (= (get-zone card) #?(:clj [:deck] - :cljs ["deck"]))) + (= (get-zone card) [:deck])) (defn in-archives-root? [card] - (= (get-zone card) #?(:clj [:servers :archives :content] - :cljs ["servers" "archives" "content"]))) + (= (get-zone card) [:servers :archives :content])) (defn in-hq-root? [card] - (= (get-zone card) #?(:clj [:servers :hq :content] - :cljs ["servers" "hq" "content"]))) + (= (get-zone card) [:servers :hq :content])) (defn in-rd-root? [card] - (= (get-zone card) #?(:clj [:servers :rd :content] - :cljs ["servers" "rd" "content"]))) + (= (get-zone card) [:servers :rd :content])) (defn in-root? [card] @@ -131,18 +124,15 @@ (defn protecting-archives? [card] - (= (get-zone card) #?(:clj [:servers :archives :ices] - :cljs ["servers" "archives" "ices"]))) + (= (get-zone card) [:servers :archives :ices])) (defn protecting-hq? [card] - (= (get-zone card) #?(:clj [:servers :hq :ices] - :cljs ["servers" "hq" "ices"]))) + (= (get-zone card) [:servers :hq :ices])) (defn protecting-rd? [card] - (= (get-zone card) #?(:clj [:servers :rd :ices] - :cljs ["servers" "rd" "ices"]))) + (= (get-zone card) [:servers :rd :ices])) (defn protecting-a-central? [card] @@ -153,14 +143,12 @@ (defn in-play-area? "Checks if the specified card is in the play area." [card] - (= (get-zone card) #?(:clj [:play-area] - :cljs ["play-area"]))) + (= (get-zone card) [:play-area])) (defn in-set-aside? "Checks if the specific card is in a set-aside area." [card] - (= (get-zone card) #?(:clj [:set-aside] - :cljs ["set-aside"]))) + (= (get-zone card) [:set-aside])) (defn set-aside-visible? "Checks if the specific card is in set aside and visible to this side" @@ -173,20 +161,17 @@ (defn in-current? "Checks if the specified card is in the 'current' zone." [card] - (= (get-zone card) #?(:clj [:current] - :cljs ["current"]))) + (= (get-zone card) [:current])) (defn in-scored? "Checks if the specified card is in _a_ score area (don't know which one)." [card] - (= (get-zone card) #?(:clj [:scored] - :cljs ["scored"]))) + (= (get-zone card) [:scored])) (defn in-rfg? "Checks if the specified card is in the 'remove from game' zone" [card] - (= (get-zone card) #?(:clj [:rfg] - :cljs ["rfg"]))) + (= (get-zone card) [:rfg])) (defn- card-is? "Checks the property of the card to see if it is equal to the given value, @@ -315,15 +300,13 @@ (defn installed? [card] (or (:installed card) - (= (first (get-zone card)) #?(:clj :servers - :cljs "servers")))) + (= (first (get-zone card)) :servers))) (defn facedown? "Checks if the specified card is facedown." [card] (or (when-not (condition-counter? card) - (= (get-zone card) #?(:clj [:rig :facedown] - :cljs ["rig" "facedown"]))) + (= (get-zone card) [:rig :facedown])) (:facedown card))) (defn active? @@ -362,17 +345,14 @@ (defn can-be-advanced? "Returns true if the card can be advanced" ([card] - (or (card-is? card :advanceable #?(:clj :always - :cljs "always")) + (or (card-is? card :advanceable :always) ;; e.g. Tyrant, Woodcutter - (and (card-is? card :advanceable #?(:clj :while-rezzed - :cljs "while-rezzed")) + (and (card-is? card :advanceable :while-rezzed) (rezzed? card)) ;; e.g. Haas Arcology AI - (and (card-is? card :advanceable #?(:clj :while-unrezzed - :cljs "while-unrezzed")) + (and (card-is? card :advanceable :while-unrezzed) (not (rezzed? card))) - (and (is-type? card "Agenda") + (and (agenda? card) (installed? card)))) ([state card] (and (can-be-advanced? card) diff --git a/src/cljs/nr/gameboard/actions.cljs b/src/cljs/nr/gameboard/actions.cljs index 9ecee9c518..d0103c1234 100644 --- a/src/cljs/nr/gameboard/actions.cljs +++ b/src/cljs/nr/gameboard/actions.cljs @@ -4,8 +4,7 @@ [nr.angel-arena.lobby :as angel-arena] [nr.appstate :refer [app-state current-gameid]] [nr.gameboard.replay :refer [init-replay]] - [nr.gameboard.state :refer [check-lock? game-state get-side last-state - parse-state]] + [nr.gameboard.state :refer [check-lock? game-state get-side last-state]] [nr.translations :refer [tr]] [nr.utils :refer [toastr-options]] [nr.ws :as ws] @@ -42,7 +41,7 @@ (-> "#gamelobby" js/$ .fadeIn)) (defn handle-diff! [{:keys [gameid diff]}] - (when (= gameid (str (current-gameid app-state))) + (when (= gameid (current-gameid app-state)) (reset! game-state (differ/patch @last-state diff)) (check-lock?) (reset! last-state @game-state))) @@ -62,9 +61,9 @@ (defmethod ws/event-msg-handler :game/start [{data :?data}] (reset! angel-arena/queueing false) - (launch-game! (parse-state data))) -(defmethod ws/event-msg-handler :game/resync [{data :?data}] (reset-game! (parse-state data))) -(defmethod ws/event-msg-handler :game/diff [{data :?data}] (handle-diff! (parse-state data))) + (launch-game! data)) +(defmethod ws/event-msg-handler :game/resync [{data :?data}] (reset-game! data)) +(defmethod ws/event-msg-handler :game/diff [{data :?data}] (handle-diff! data)) (defmethod ws/event-msg-handler :game/timeout [{data :?data}] (handle-timeout data)) (defmethod ws/event-msg-handler :game/error [_] (handle-error)) @@ -84,13 +83,6 @@ (when (not (:replay @game-state)) (ws/ws-send! [:game/mute-spectators {:gameid (current-gameid app-state)}]))) -(defn stack-cards [] - (swap! app-state update-in [:options :stacked-cards] not)) - -; (defn flip-runner-board [] -; (let [layout (if (= "irl" (get-in @app-state [:options :runner-board-order])) "jnet" "irl")] -; (swap! app-state assoc-in [:options :runner-board-order] layout))) - (defn concede [] (when (not (:replay @game-state)) (ws/ws-send! [:game/concede {:gameid (current-gameid app-state)}]))) @@ -108,7 +100,8 @@ (build-report-url error) "');\">Report on GitHub"))) -(defn ack-toast ([id] (send-command "toast" {:id id}))) +(defn ack-toast [id] + (send-command "toast" {:id id})) (defn toast "Display a toast warning with the specified message. diff --git a/src/cljs/nr/gameboard/board.cljs b/src/cljs/nr/gameboard/board.cljs index 614179fcf4..e71e294ea1 100644 --- a/src/cljs/nr/gameboard/board.cljs +++ b/src/cljs/nr/gameboard/board.cljs @@ -6,10 +6,17 @@ [cljc.java-time.temporal.chrono-unit :as chrono] [cljs.core.async :refer [sort-key]] [jinteki.cards :refer [all-cards]] [jinteki.utils :refer [add-cost-to-label is-tagged? select-non-nil-keys str->int] :as utils] @@ -18,8 +25,14 @@ [nr.end-of-game-stats :refer [build-game-stats]] [nr.gameboard.actions :refer [send-command]] [nr.gameboard.card-preview :refer [card-highlight-mouse-out - card-highlight-mouse-over card-preview-mouse-out - card-preview-mouse-over put-game-card-in-channel zoom-channel]] + card-highlight-mouse-over + card-highlight-mouse-over + card-preview-mouse-out + card-preview-mouse-out + card-preview-mouse-over + card-preview-mouse-over + put-game-card-in-channel zoom-channel + zoom-channel]] [nr.gameboard.player-stats :refer [stat-controls stats-view]] [nr.gameboard.replay :refer [replay-panel]] [nr.gameboard.right-pane :refer [content-pane]] @@ -70,34 +83,26 @@ (swap! card-menu dissoc :source :keep-menu-open)) (defn action-list - [{:keys [type zone rezzed advanceable - advancementcost current-advancement-requirement] :as card}] + [{:keys [zone advancementcost current-advancement-requirement] + :as card}] (cond->> [] ;; advance - (or (and (= type "Agenda") - (#{"servers" "onhost"} (first zone))) - (= advanceable "always") - (and rezzed - (= advanceable "while-rezzed")) - (and (not rezzed) - (= advanceable "while-unrezzed"))) + (can-be-advanced? card) (cons "advance") ;; score - (and (= type "Agenda") - (#{"servers" "onhost"} (first zone)) + (and (agenda? card) + (#{:servers :onhost} (first zone)) (>= (get-counters card :advancement) (or current-advancement-requirement advancementcost))) (cons "score") ;; trash - (#{"ICE" "Program"} type) + (or (ice? card) (program? card)) (cons "trash") ;; rez - (and (#{"Asset" "ICE" "Upgrade"} type) - (not rezzed)) + (or (asset? card) (ice? card) (upgrade? card) (not (rezzed? card))) (cons "rez") ;; derez - (and (#{"Asset" "ICE" "Upgrade"} type) - rezzed) + (or (asset? card) (ice? card) (upgrade? card) (rezzed? card)) (cons "derez"))) (def click-card-keys @@ -164,34 +169,34 @@ (:poison card) (:highlight-in-discard card)))) -(defn handle-card-click [{:keys [type zone] :as card}] +(defn handle-card-click [{:keys [zone] :as card}] (let [side (:side @game-state)] (when (not-spectator?) (cond ;; Selecting card - (= (get-in @game-state [side :prompt-state :prompt-type]) "select") + (= :select (get-in @game-state [side :prompt-state :prompt-type])) (send-command "select" {:card (card-for-click card)}) ;; Card is an identity of player's side - (and (= (:type card) "Identity") + (and (identity? card) (= side (keyword (lower-case (:side card))))) (handle-abilities side card) ;; Runner clicking on a runner card (and (= side :runner) - (= "Runner" (:side card)) + (runner? card) (not (any-prompt-open? side)) - (= "hand" (first zone)) + (in-hand? card) (playable? card)) (send-command "play" {:card (card-for-click card)}) ;; Corp clicking on a corp card (and (= side :corp) - (= "Corp" (:side card)) + (corp? card) (not (any-prompt-open? side)) - (= "hand" (first zone)) + (in-hand? card) (playable? card)) - (if (= "Operation" type) + (if (operation? card) (send-command "play" {:card (card-for-click card)}) (if (= (:cid card) (:source @card-menu)) (do (send-command "generate-install-list" nil) @@ -201,7 +206,7 @@ :else (case (first zone) - ("current" "onhost" "play-area" "scored" "servers" "rig") + (:current :onhost :play-area :scored :servers :rig) (handle-abilities side card) ; else nil))))) @@ -219,7 +224,7 @@ (defn handle-drop [e server] (-> e .-target js/$ (.removeClass "dragover")) (let [card (-> e .-dataTransfer (.getData "card") ((.-parse js/JSON)) (js->clj :keywordize-keys true))] - (when (not= "Identity" (:type card)) + (when-not (identity? card) (send-command "move" {:card card :server server})))) ;; touch support @@ -270,27 +275,19 @@ [server moved-enough] (get-server-from-touch touch)] (release-touch card) (when (and server moved-enough (not= server (:start-server @touchmove))) - (let [cardinfo (-> @touchmove :card ((.-parse js/JSON)) (js->clj :keywordize-keys true))] + (let [cardinfo (:card @touchmove)] (send-command "move" {:card cardinfo :server server}))))) (defn remote->num [server] - (-> server str (clojure.string/split #":remote") last str->int)) + (-> server str (s/split #":remote") last str->int)) (defn remote->name [server] (let [num (remote->num server)] (str (tr [:game.server "Server"]) " " num))) -(defn zone->sort-key [zone] - (case (if (keyword? zone) zone (last zone)) - :archives -3 - :rd -2 - :hq -1 - (str->int - (last (clojure.string/split (str zone) #":remote"))))) - (defn get-remotes [servers] (->> servers - (filter #(not (#{:hq :rd :archives} (first %)))) + (remove #(#{:hq :rd :archives} (first %))) (sort-by #(zone->sort-key (first %))))) (defn facedown-card @@ -654,7 +651,7 @@ (= (:side host) "Runner")))))) (defn card-view - [{:keys [zone code type abilities counter + [{:keys [code abilities counter subtypes strength current-strength selected hosted side facedown card-target icon new ghost runner-abilities subroutines subtype-target corp-abilities] @@ -691,7 +688,7 @@ :on-key-up #(when (and (= " " (.-key %)) (not disable-click)) (handle-card-click card))} - (if (or (not code) flipped facedown) + (if (and side (or (not code) flipped facedown)) (let [facedown-but-known (or (not (or (not code) flipped facedown)) (spectator-view-hidden?) (= (:side @game-state) (keyword (lower-case side)))) @@ -699,7 +696,9 @@ [facedown-card side ["bg"] alt-str]) (when-let [url (image-url card)] [:div - [:img.card.bg {:src url :alt title :onError #(-> % .-target js/$ .hide)}]])) + [:img.card.bg {:src url + :alt title + :onError #(-> % .-target js/$ .hide)}]])) [:span.cardname title] [:div.counters (when counter @@ -723,23 +722,23 @@ (let [server-card (get @all-cards title)] [:div.darkbg.additional-subtypes (join " - " (remove (into #{} (:subtypes server-card)) subtypes))]))] - (cond - (and (= zone ["hand"]) - (#{"Agenda" "Asset" "ICE" "Upgrade"} type)) + ;; install list + (and (in-hand? card) + (corp-installable-type? card)) [server-menu card] - + ;; subroutines and runner abilities (and (= :runner (:side @game-state)) (pos? (+ (count runner-abilities) (count subroutines)))) [runner-abs card runner-abilities subroutines title] - + ;; corp abilities (and (= :corp (:side @game-state)) (pos? (count corp-abilities))) [corp-abs card corp-abilities] - + ;; regular card abilities (= (:side @game-state) (keyword (lower-case side))) [card-abilities card abilities subroutines]) - + ;; hosted cards (when (pos? (count hosted)) [:div.hosted (if (and (not (ice? card)) @@ -995,7 +994,6 @@ [card-view c]))])]))))) (defn play-area-view [user name cards] - (fn [user name cards] (let [size (count @cards)] (when (pos? size) [:div.panel.blue-shade.rfg {:class (when (> size 2) "squeeze")} @@ -1008,7 +1006,7 @@ [card-view card] [facedown-card (:side card)])]) @cards)) - [label @cards {:opts {:name name}}]])))) + [label @cards {:opts {:name name}}]]))) (defn scored-view [scored agenda-point me?] (let [size (count @scored) @@ -1025,15 +1023,13 @@ (ctrl :agenda-point [:div (tr [:game.agenda-count] @agenda-point)])]])) (defn run-arrow [run] - [:div.run-arrow [:div {:class (cond - (= "movement" (:phase run)) - "movement" - (= "approach-ice" (:phase run)) - "approach" - (= "encounter-ice" (:phase run)) - "encounter" - :else - "")}]]) + (let [phase (:phase run) + class (cond + (= :movement phase) "movement" + (= :approach-ice phase) "approach" + (= :encounter-ice phase) "encounter" + :else "")] + [:div.run-arrow [:div {:class class}]])) (defn server-view [{:keys [server central-view run]} opts] (let [content (:content server) @@ -1075,25 +1071,21 @@ (and (< 1 (count content)) (not is-first))) "shift"))} [card-view card flipped]])))) - [label content (update-in opts [:opts] assoc :classes "server-label" :hide-cursor true)]]])) + [label content (update opts :opts assoc :classes "server-label" :hide-cursor true)]]])) -(defn stacked-label [cursor similar-servers opts] +(defn stacked-label [similar-servers opts] (let [similar-server-names (->> similar-servers (map first) (map remote->name)) full-server-names (cons (get-in opts [:opts :name]) similar-server-names) numbers (map #(second (split % " ")) full-server-names)] - [label full-server-names (update-in opts [:opts] assoc + [label full-server-names (update opts :opts assoc :classes "server-label" :name (str "Servers " (join ", " numbers)) :hide-cursor true)])) -(defn stacked-view [{:keys [key server similar-servers central-view run]} opts] - (let [content (apply conj - (:content server) - ; this unfolds all servers and picks the first item in it - ; since this creates a sequence, we need to apply it to conj - (map #(-> % second :content first) similar-servers)) +(defn stacked-view [{:keys [server similar-servers run]} opts] + (let [content (concat (:content server) (map #(-> % second :content first) similar-servers)) ices (:ices server) run-pos (:position run) current-ice (when (and run (pos? run-pos) (<= run-pos (count ices))) @@ -1113,10 +1105,9 @@ :class (str (when (and (< 1 (count content)) (not is-first)) "shift"))} [card-view card flipped]]))) - [stacked-label content similar-servers opts]]]])) + [stacked-label similar-servers opts]]]])) -(defn compare-servers-for-stacking [s1] - (fn [s2] +(defn compare-servers-for-stacking [s1 s2] (let [ss1 (second s1) ss2 (second s2)] (and (= (-> ss1 :content first :normalizedtitle) @@ -1131,11 +1122,10 @@ (-> ss1 :content first :rezzed) (-> ss2 :content first :rezzed) (-> ss1 :content first :hosted empty?) - (-> ss2 :content first :hosted empty?))))) + (-> ss2 :content first :hosted empty?)))) (defn board-view-corp [player-side identity deck deck-count hand hand-count discard servers run] - (let [rs (:server @run) - server-type (first rs) + (let [run-target (target-server @run) side-class (if (= player-side :runner) "opponent" "me") hand-count-number (if (nil? @hand-count) (count @hand) @hand-count)] [:div.outer-corp-board {:class [side-class @@ -1143,8 +1133,9 @@ [:div.corp-board {:class side-class} (doall (for [server (reverse (get-remotes @servers)) - :let [num (remote->num (first server)) - similar-servers (filter #((compare-servers-for-stacking server) %) (get-remotes @servers)) + :let [[server-name content] server + num (remote->num server-name) + similar-servers (filter #(compare-servers-for-stacking server %) (get-remotes @servers)) all-servers (conj similar-servers server)] :when (or (empty? similar-servers) ; it is a normal server-view (not (get-in @app-state [:options :stacked-cards] false)) ; we're not in stacked mode @@ -1153,28 +1144,28 @@ (if (or (empty? similar-servers) (not (get-in @app-state [:options :stacked-cards] false))) [server-view {:key num - :server (second server) - :run (when (= server-type (str "remote" num)) @run)} - {:opts {:name (remote->name (first server))}}] + :server content + :run (when (= server-name run-target) @run)} + {:opts {:name (remote->name server-name)}}] [stacked-view {:key num - :server (second server) + :server content :similar-servers similar-servers :run (when - (some #(= server-type (str "remote" %)) (map #(remote->num (first %)) all-servers)) - (= server-type (str "remote" num)) @run)} - {:opts {:name (remote->name (first server))}}]))) + (some #(= run-target (str "remote" %)) (map #(remote->num (first %)) all-servers)) + @run)} + {:opts {:name (remote->name server-name)}}]))) [server-view {:key "hq" :server (:hq @servers) :central-view [identity-view :corp identity hand-count-number] - :run (when (= server-type "hq") @run)}] + :run (when (= :hq run-target) @run)}] [server-view {:key "rd" :server (:rd @servers) :central-view [deck-view :corp player-side identity deck deck-count] - :run (when (= server-type "rd") @run)}] + :run (when (= :rd run-target) @run)}] [server-view {:key "archives" :server (:archives @servers) :central-view [discard-view-corp player-side discard] - :run (when (= server-type "archives") @run)}]]])) + :run (when (= :archives run-target) @run)}]]])) (defn- ghost-card "recursively ghosts a card and all hosted cards" @@ -1280,8 +1271,6 @@ (pos? (count @my-hand))) (let [squeeze (< 5 (count @my-hand))] [:div.win.centered.blue-shade.start-game - [:div - [:div [:div.box [:div.start-game.ident.column {:class (case @my-keep "mulligan" "mulligan-me" "keep" "keep-me" "")} @@ -1333,18 +1322,18 @@ (tr [:game.close "Close"]) (tr [:game.start "Start Game"])) true #(swap! app-state assoc :start-shown true)] (list ^{:key "keepbtn"} [cond-button (tr [:game.keep "Keep"]) - (= "mulligan" (:prompt-type @prompt-state)) + (= :mulligan (:prompt-type @prompt-state)) #(send-command "choice" {:choice {:uuid (->> (:choices @prompt-state) (filter (fn [c] (= "Keep" (:value c)))) first :uuid)}})] ^{:key "mullbtn"} [cond-button (tr [:game.mulligan "Mulligan"]) - (= "mulligan" (:prompt-type @prompt-state)) + (= :mulligan (:prompt-type @prompt-state)) #(do (send-command "choice" {:choice {:uuid (->> (:choices @prompt-state) (filter (fn [c] (= "Mulligan" (:value c)))) first :uuid)}}) - (reset! mulliganed true))]))]]] + (reset! mulliganed true))]))] [:br] [:button.win-right {:on-click #(swap! app-state assoc :start-shown true) :type "button"} "✘"]]))))) @@ -1353,14 +1342,14 @@ :server first keyword)] - (get-in @game-state (concat [:corp :servers] [server] [:ices])))) + (get-in @game-state [:corp :servers server :ices]))) (defn get-current-ice [] (let [run-ice (get-run-ices) pos (get-in @game-state [:run :position]) phase (get-in @game-state [:run :phase]) encounter-ice (-> @game-state :encounters :ice) - get-ice-from-pos? (or (= "movement" phase) + get-ice-from-pos? (or (= :movement phase) (get-in @game-state [:run :approached-ice-in-position?]))] (or encounter-ice (when (and get-ice-from-pos? @@ -1370,25 +1359,25 @@ (nth run-ice (dec pos)))))) (def phase->title - {"initiation" (tr [:game.initiation "Initiation"]) - "approach-ice" (tr [:game.approach-ice "Approach ice"]) - "encounter-ice" (tr [:game.encounter-ice "Encounter ice"]) - "movement" (tr [:game.movement "Movement"]) - "success" (tr [:game.success "Success"])}) + {:initiation (tr [:game.initiation "Initiation"]) + :approach-ice (tr [:game.approach-ice "Approach ice"]) + :encounter-ice (tr [:game.encounter-ice "Encounter ice"]) + :movement (tr [:game.movement "Movement"]) + :success (tr [:game.success "Success"])}) (defn phase->next-phase-title ([run] (phase->next-phase-title (:phase @run) (:position @run))) ([phase position] (case phase - "initiation" (tr [:game.approach-ice "Approach ice"]) - "approach-ice" (if (rezzed? (get-current-ice)) + :initiation (tr [:game.approach-ice "Approach ice"]) + :approach-ice (if (rezzed? (get-current-ice)) (tr [:game.encounter-ice "Encounter ice"]) (tr [:game.movement "Movement"])) - "encounter-ice" (tr [:game.movement "Movement"]) - "movement" (if (zero? position) + :encounter-ice (tr [:game.movement "Movement"]) + :movement (if (zero? position) (tr [:game.success "Success"]) (tr [:game.approach-ice "Approach ice"])) - "success" (tr [:game.run-ends "Run ends"]) + :success (tr [:game.run-ends "Run ends"]) ;; Error (tr [:game.no-current-run "No current run"])))) @@ -1407,17 +1396,18 @@ (when (:button @app-state) [encounter-info-div ice])]) (when @run - [:h4 (tr [:game.current-phase "Current phase"]) ":" [:br] (get phase->title (:phase @run) (tr [:game.unknown-phase "Unknown phase"]))]) + [:h4 (tr [:game.current-phase "Current phase"]) ":" [:br] + (get phase->title (:phase @run) (tr [:game.unknown-phase "Unknown phase"]))]) (cond - (and (= "approach-ice" (:phase @run)) + (and (= :approach-ice (:phase @run)) ice) [cond-button (str (tr [:game.rez "Rez"]) " " (get-title ice)) (not (rezzed? ice)) #(send-command "rez" {:card ice :press-continue true})] - (or (= "encounter-ice" (:phase @run)) + (or (= :encounter-ice (:phase @run)) @encounters) [cond-button (tr [:game.fire-unbroken "Fire unbroken subs"]) @@ -1430,13 +1420,13 @@ (if @encounters ;;Encounter continue button - (let [pass-ice? (and (= "encounter-ice" (:phase @run)) + (let [pass-ice? (and (= :encounter-ice (:phase @run)) (= 1 (:encounter-count @encounters)))] [cond-button (if pass-ice? (str (tr [:game.continue-to "Continue to"]) " " (phase->next-phase-title run)) (tr [:game.continue "Continue"])) - (not= "corp" (:no-action @encounters)) + (not= :corp (:no-action @encounters)) #(send-command "continue")]) ;;Non-encounter continue button [cond-button @@ -1444,14 +1434,14 @@ (zero? (:position @run))) (tr [:game.no-further "No further actions"]) (str (tr [:game.continue-to "Continue to"]) " " (phase->next-phase-title run))) - (and (not= "initiation" (:phase @run)) - (not= "success" (:phase @run)) - (not= "corp" (:no-action @run))) + (and (not= :initiation (:phase @run)) + (not= :success (:phase @run)) + (not= :corp (:no-action @run))) #(send-command "continue")]) (when (and @run (<= (:encounter-count @encounters) 1) - (not= "success" (:phase @run))) + (not= :success (:phase @run))) [checkbox-button (tr [:game.stop-auto-pass "Stop auto-passing priority"]) (tr [:game.auto-pass "Auto-pass priority"]) @@ -1463,7 +1453,7 @@ (let [phase (:phase @run) next-phase (:next-phase @run) ice (get-current-ice) - pass-ice? (and (= "encounter-ice" phase) + pass-ice? (and (= :encounter-ice phase) (= 1 (:encounter-count @encounters)))] [:div.panel.blue-shade (when (and @encounters @@ -1492,14 +1482,14 @@ (not @encounters)) [cond-button (str (tr [:game.continue-to "Continue to"]) " " (phase->next-phase-title run)) - (not= "runner" (:no-action @run)) + (not= :runner (:no-action @run)) #(send-command "continue")] (and (zero? (:position @run)) (not @encounters) - (= "movement" phase)) + (= :movement phase)) [cond-button (tr [:game.breach-server "Breach server"]) - (not= "runner" (:no-action @run)) + (not= :runner (:no-action @run)) #(send-command "continue")]) (when @encounters @@ -1518,16 +1508,16 @@ (if pass-ice? (str (tr [:game.continue-to "Continue to"]) " " (phase->next-phase-title run)) (tr [:game.continue "Continue"])) - (not= "runner" (:no-action @encounters)) + (not= :runner (:no-action @encounters)) #(send-command "continue")]) (when (and @run - (not= "success" phase)) + (not= :success phase)) [cond-button (tr [:game.jack-out "Jack Out"]) - (and (= "movement" phase) + (and (= :movement phase) (not (:cannot-jack-out @run)) - (not= "runner" (:no-action @run))) + (not= :runner (:no-action @run))) #(send-command "jack-out")])])) (defn run-div @@ -1543,7 +1533,7 @@ (when base ;; This is the initial trace prompt (if (nil? strength) - (if (= "corp" player) + (if (= :corp player) ;; This is a trace prompt for the corp, show runner link + credits [:div.info (tr [:side.runner "Runner"]) ": " link [:span {:class "anr-icon link"}] " + " runner-credits [:span {:class "anr-icon credit"}]] @@ -1551,18 +1541,18 @@ [:div.info (tr [:game.trace "Trace"]) ": " (if bonus (+ base bonus) base) " + " corp-credits [:span {:class "anr-icon credit"}]]) ;; This is a trace prompt for the responder to the trace, show strength - (if (= "corp" player) + (if (= :corp player) [:div.info "vs Trace: " strength] [:div.info "vs Runner: " strength [:span {:class "anr-icon link"}]]))) [:div.credit-select ;; Inform user of base trace / link and any bonuses (when base (if (nil? strength) - (if (= "corp" player) + (if (= :corp player) (let [strength (if bonus (+ base bonus) base)] [:span (str strength " + ")]) [:span link " " [:span {:class "anr-icon link"}] (str " + " )]) - (if (= "corp" player) + (if (= :corp player) [:span link " " [:span {:class "anr-icon link"}] (str " + " )] (let [strength (if bonus (+ base bonus) base)] [:span (str strength " + ")])))) @@ -1584,52 +1574,43 @@ (tr [:game.ok "OK"])]])) (defn prompt-div - [me {:keys [card msg prompt-type choices] :as prompt-state}] - (let [id (atom 0)] - [:div.panel.blue-shade - (when (and card (not= "Basic Action" (:type card))) - [:<> - (let [get-nested-host (fn [card] (if (:host card) - (recur (:host card)) - card)) - get-zone (fn [card] (:zone (get-nested-host card))) - in-play-area? (fn [card] (= (get-zone card) ["play-area"])) - in-scored? (fn [card] (= (get-zone card) ["scored"])) - installed? (fn [card] (or (:installed card) - (= "servers" (first (get-zone card)))))] - (if (or (nil? (:side card)) - (installed? card) - (in-scored? card) - (in-play-area? card)) - [:div {:style {:text-align "center"} - :on-mouse-over #(card-highlight-mouse-over % card button-channel) - :on-mouse-out #(card-highlight-mouse-out % card button-channel)} - (tr [:game.card "Card"]) ": " (render-message (get-title card))] - [:div.prompt-card-preview [card-view card false]])) - [:hr]]) - [:h4 (render-message msg)] - (cond - ;; number prompt - (:number choices) - (let [n (:number choices)] - [:div - [:div.credit-select - [:select#credit {:default-value (:default choices 0) - :onKeyUp #(when (= "Enter" (.-key %)) - (-> "#number-submit" js/$ .click) - (.stopPropagation %))} - (doall (for [i (range (inc n))] - [:option {:key i :value i} i]))]] - [:button#number-submit {:on-click #(send-command "choice" - {:choice (-> "#credit" js/$ .val str->int)})} - (tr [:game.ok "OK"])]]) + [{:keys [card msg prompt-type choices] :as prompt-state}] + [:div.panel.blue-shade + (when (and card (not (basic-action? card))) + [:<> + (if (or (nil? (:side card)) + (installed? card) + (in-scored? card) + (in-play-area? card)) + [:div {:style {:text-align "center"} + :on-mouse-over #(card-highlight-mouse-over % card button-channel) + :on-mouse-out #(card-highlight-mouse-out % card button-channel)} + (tr [:game.card "Card"]) ": " (render-message (get-title card))] + [:div.prompt-card-preview [card-view card false]]) + [:hr]]) + [:h4 (render-message msg)] + (cond + ;; number prompt + (:number choices) + (let [n (:number choices)] + [:div + [:div.credit-select + [:select#credit {:default-value (:default choices 0) + :onKeyUp #(when (= "Enter" (.-key %)) + (-> "#number-submit" js/$ .click) + (.stopPropagation %))} + (doall (for [i (range (inc n))] + [:option {:key i :value i} i]))]] + [:button#number-submit {:on-click #(send-command "choice" + {:choice (-> "#credit" js/$ .val str->int)})} + (tr [:game.ok "OK"])]]) ;; trace prompts require their own logic - (= prompt-type "trace") + (= :trace prompt-type) [trace-div prompt-state] ;; choice of number of credits - (= choices "credit") + (= :credit choices) (let [n (get-in @game-state [(:side @game-state) :credit])] [:div [:div.credit-select @@ -1656,7 +1637,7 @@ ;; choice of specified counters on card (:counter choices) - (let [counter-type (keyword (:counter choices)) + (let [counter-type (:counter choices) num-counters (get-in prompt-state [:card :counter counter-type] 0)] [:div [:div.credit-select @@ -1680,11 +1661,11 @@ #(card-highlight-mouse-over % value button-channel) :on-mouse-out #(card-highlight-mouse-out % value button-channel)} - (render-message (or (not-empty (get-title value)) value))])))])) + (render-message (or (not-empty (get-title value)) value))])))]) (defn basic-actions [{:keys [side active-player end-turn runner-phase-12 corp-phase-12 me]}] [:div.panel.blue-shade - (if (= (keyword @active-player) side) + (if (= @active-player side) (when (and (not (or @runner-phase-12 @corp-phase-12)) (zero? (:click @me)) (not @end-turn)) @@ -1693,7 +1674,7 @@ (when @end-turn [:button {:on-click #(send-command "start-turn")} (tr [:game.start-turn "Start Turn"])])) - (when (and (= (keyword @active-player) side) + (when (and (= @active-player side) (or @runner-phase-12 @corp-phase-12)) [:button {:on-click #(send-command "end-phase-12")} (if (= side :corp) @@ -1746,7 +1727,7 @@ (playable? (get-in @me [:basic-action-card :abilities 0]))) #(send-command "credit")]]) -(defn button-pane [{:keys [side prompt-state]}] +(defn button-pane [{:keys [prompt-state]}] (let [autocomp (r/track (fn [] (get-in @prompt-state [:choices :autocomplete]))) show-discard? (r/track (fn [] (get-in @prompt-state [:show-discard]))) prompt-type (r/track (fn [] (get-in @prompt-state [:prompt-type]))) @@ -1762,20 +1743,20 @@ (reset! opened-by-system true)) @opened-by-system (do (-> ".me .discard-container .popup" js/$ .fadeOut) (reset! opened-by-system false))) - (if (= "select" @prompt-type) + (if (= :select @prompt-type) (set! (.-cursor (.-style (.-body js/document))) "url('/img/gold_crosshair.png') 12 12, crosshair") (set! (.-cursor (.-style (.-body js/document))) "default")) - (when (= "card-title" @prompt-type) + (when (= :card-title @prompt-type) (-> "#card-title" js/$ .focus))) :reagent-render - (fn [{:keys [side run encounters prompt-state me] :as button-pane-args}] + (fn [{:keys [side run encounters prompt-state] :as button-pane-args}] [:div.button-pane {:on-mouse-over #(card-preview-mouse-over % zoom-channel) :on-mouse-out #(card-preview-mouse-out % zoom-channel)} (cond (and @prompt-state - (not= "run" @prompt-type)) - [prompt-div me @prompt-state] + (not= :run @prompt-type)) + [prompt-div @prompt-state] (or @run @encounters) [run-div side run encounters] @@ -1865,8 +1846,7 @@ [:span.float-center.timer (str (:minutes @duration) "m:" - (:seconds @duration) "s")]) - )}))) + (:seconds @duration) "s")]))}))) (defn starting-timestamp [start-date timer] ;; I don't like using js/Date, but `toLocalTimeString` @@ -1948,11 +1928,11 @@ (when (and render-board? (not= "text" (.-type (.-activeElement js/document)))) (let [clicks (:click (@side @game-state)) - active-player-kw (keyword @active-player) + active-player-kw @active-player prompt-state (:prompt-state (@side @game-state)) - prompt-type (keyword (:prompt-type prompt-state)) - no-action (keyword (or (:no-action @run) - (:no-action @encounters)))] + prompt-type (:prompt-type prompt-state) + no-action (or (:no-action @run) + (:no-action @encounters))] (case (.-key e) " " (cond ;; keep default space behavior for focusable items @@ -1998,13 +1978,11 @@ nil)))) (defn gameboard [] - (let [active (r/cursor app-state [:active-page]) - start-date (r/cursor game-state [:start-date]) + (let [start-date (r/cursor game-state [:start-date]) timer (r/cursor game-state [:options :timer]) run (r/cursor game-state [:run]) encounters (r/cursor game-state [:encounters]) side (r/cursor game-state [:side]) - turn (r/cursor game-state [:turn]) end-turn (r/cursor game-state [:end-turn]) corp-phase-12 (r/cursor game-state [:corp-phase-12]) runner-phase-12 (r/cursor game-state [:runner-phase-12]) @@ -2029,7 +2007,7 @@ {:display-name "gameboard" :component-did-mount - (fn [this] + (fn [] (-> js/document (.addEventListener "keydown" (partial handle-key-down {:render-board? (and @corp @runner @side true)}))) @@ -2044,7 +2022,7 @@ (partial handle-click {:render-board? (and @corp @runner @side true)})))) :component-will-unmount - (fn [this] + (fn [] (-> js/document (.addEventListener "keydown" (partial handle-key-down {:render-board? (and @corp @runner @side true)}))) @@ -2084,7 +2062,6 @@ me-user (r/cursor game-state [me-side :user]) op-user (r/cursor game-state [op-side :user]) ;; prompts - me-prompt (r/cursor game-state [me-side :prompt]) prompt-state (r/cursor game-state [me-side :prompt-state]) ;; identity cards me-ident (r/cursor game-state [me-side :identity]) @@ -2096,8 +2073,7 @@ op-agenda-point (r/cursor game-state [op-side :agenda-point]) ;; servers corp-servers (r/cursor game-state [:corp :servers]) - runner-rig (r/cursor game-state [:runner :rig]) - sfx (r/cursor game-state [:sfx])] + runner-rig (r/cursor game-state [:runner :rig])] [:div.gameview [:div {:class [:gameboard (when @labeled-unrezzed-cards :show-unrezzed-card-labels)