From 3197d7a25ec0a6ea651e8c44e7a222f7293e3b37 Mon Sep 17 00:00:00 2001 From: NB Kelly Date: Sat, 14 Sep 2024 12:01:48 +1200 Subject: [PATCH] use stringer/strcat instead of str for all of our string composition --- project.clj | 1 + src/clj/game/cards/agendas.clj | 114 ++++++------- src/clj/game/cards/assets.clj | 97 +++++------ src/clj/game/cards/basic.clj | 9 +- src/clj/game/cards/events.clj | 183 ++++++++++---------- src/clj/game/cards/hardware.clj | 77 ++++----- src/clj/game/cards/ice.clj | 237 +++++++++++++------------- src/clj/game/cards/identities.clj | 107 ++++++------ src/clj/game/cards/operations.clj | 141 +++++++-------- src/clj/game/cards/programs.clj | 107 ++++++------ src/clj/game/cards/resources.clj | 147 ++++++++-------- src/clj/game/cards/upgrades.clj | 72 ++++---- src/clj/game/core/access.clj | 41 ++--- src/clj/game/core/actions.clj | 39 ++--- src/clj/game/core/bad_publicity.clj | 9 +- src/clj/game/core/board.clj | 7 +- src/clj/game/core/change_vals.clj | 31 ++-- src/clj/game/core/charge.clj | 7 +- src/clj/game/core/commands.clj | 41 ++--- src/clj/game/core/costs.clj | 205 +++++++++++----------- src/clj/game/core/damage.clj | 13 +- src/clj/game/core/def_helpers.clj | 42 ++--- src/clj/game/core/drawing.clj | 13 +- src/clj/game/core/engine.clj | 29 ++-- src/clj/game/core/expose.clj | 7 +- src/clj/game/core/flags.clj | 11 +- src/clj/game/core/ice.clj | 33 ++-- src/clj/game/core/initializing.clj | 7 +- src/clj/game/core/installing.clj | 71 ++++---- src/clj/game/core/mark.clj | 5 +- src/clj/game/core/memory.clj | 9 +- src/clj/game/core/moving.clj | 13 +- src/clj/game/core/optional.clj | 11 +- src/clj/game/core/payment.clj | 15 +- src/clj/game/core/pick_counters.clj | 25 +-- src/clj/game/core/play_instants.clj | 7 +- src/clj/game/core/process_actions.clj | 5 +- src/clj/game/core/prompts.clj | 27 +-- src/clj/game/core/psi.clj | 11 +- src/clj/game/core/rezzing.clj | 11 +- src/clj/game/core/runs.clj | 45 ++--- src/clj/game/core/sabotage.clj | 12 +- src/clj/game/core/say.clj | 11 +- src/clj/game/core/servers.clj | 11 +- src/clj/game/core/shuffling.clj | 9 +- src/clj/game/core/tags.clj | 9 +- src/clj/game/core/to_string.clj | 15 +- src/clj/game/core/toasts.clj | 4 +- src/clj/game/core/trace.clj | 23 +-- src/clj/game/core/turns.clj | 14 +- src/clj/game/macros.clj | 7 +- src/clj/game/main.clj | 5 +- src/clj/web/game.clj | 15 +- src/clj/web/lobby.clj | 25 +-- src/clj/web/pages.clj | 9 +- src/clj/web/stats.clj | 35 ++-- src/clj/web/system.clj | 5 +- 57 files changed, 1170 insertions(+), 1121 deletions(-) diff --git a/project.clj b/project.clj index 7a9a766304..50ad05a095 100644 --- a/project.clj +++ b/project.clj @@ -61,6 +61,7 @@ [org.clojure/data.csv "1.0.0"] [dev.weavejester/medley "1.8.0"] [org.slf4j/slf4j-nop "1.7.32"] + [stringer "0.4.1"] [integrant "0.8.0"] [cljc.java-time "0.1.18"] [time-literals "0.1.5"] diff --git a/src/clj/game/cards/agendas.clj b/src/clj/game/cards/agendas.clj index 47124f2de9..e8301bd639 100644 --- a/src/clj/game/cards/agendas.clj +++ b/src/clj/game/cards/agendas.clj @@ -1,7 +1,6 @@ (ns game.cards.agendas (:require [clojure.set :as set] - [clojure.string :as str] [game.core.access :refer [steal-cost-bonus]] [game.core.actions :refer [score]] [game.core.agendas :refer [update-all-advancement-requirements @@ -55,7 +54,8 @@ [game.core.winning :refer [check-win-by-agenda]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) (defn- add-agenda-point-counters "Adds a number of agenda counters to an agenda that checks for a win" @@ -111,7 +111,7 @@ :prompt "Choose a card to install and rez at no cost" :choices (cancellable (filter ice? choices) :sorted) :cancel-effect (effect (unregister-events card) - (system-msg (str "declines to use " (get-title card) " to install any of the top 3 cards or R&D")) + (system-msg (s/strcat "declines to use " (get-title card) " to install any of the top 3 cards or R&D")) (trash-cards eid choices {:unpreventable true :cause-card card})) :effect (req (wait-for (corp-install state side target nil {:ignore-all-cost true @@ -146,7 +146,7 @@ (wait-for (resolve-ability state side {:async true - :prompt (str "The top cards of R&D are (top->bottom): " + :prompt (s/strcat "The top cards of R&D are (top->bottom): " (enumerate-str (map get-title choices))) :choices ["OK"]} card nil) @@ -163,13 +163,13 @@ :choices ["Draw 1 card" "Gain 1 [Credits]" "No action"] :effect (req (case target "Gain 1 [Credits]" - (do (system-msg state :corp (str "uses " (:title card) " to gain 1 [Credits]")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to gain 1 [Credits]")) (gain-credits state :corp eid 1)) "Draw 1 card" - (do (system-msg state :corp (str "uses " (:title card) " to draw 1 card")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to draw 1 card")) (draw state :corp eid 1)) "No action" - (do (system-msg state :corp (str "declines to use " (:title card))) + (do (system-msg state :corp (s/strcat "declines to use " (:title card))) (effect-completed state side eid))))}]}) (defcard "Ancestral Imager" @@ -217,7 +217,7 @@ :install-state :rezzed-no-cost}))) :cancel-effect (effect (system-msg - (str "declines to use " + (s/strcat "declines to use " (get-title card) " to install any of the top 5 cards of R&D")) (effect-completed eid))} @@ -303,7 +303,7 @@ (move state :corp h :hand)) (do (system-msg state :corp - (str "uses " (:title card) + (s/strcat "uses " (:title card) " to trash " (quantify (count to-trash) "card") ", add " (quantify (count to-hq) "card") " to HQ, and arrange the top " (quantify (- 7 (count to-trash) (count to-hq)) "card") " of R&D")) @@ -424,7 +424,7 @@ (let [from (take target (shuffle (:hand runner)))] (doseq [c from] (move state :runner c :deck)) - (system-msg state side (str "uses " (:title card) " to pay " target + (system-msg state side (s/strcat "uses " (:title card) " to pay " target " [Credits] and add " (quantify target "card") " from the grip" " to the bottom of the stack." @@ -536,7 +536,7 @@ (continue-ability (let [chosen-ice target] {:async true - :prompt (str "Choose a server to install " (:title chosen-ice) " on") + :prompt (s/strcat "Choose a server to install " (:title chosen-ice) " on") :choices (filter #(not (#{"HQ" "Archives" "R&D"} %)) (installable-servers state chosen-ice)) :effect (effect (shuffle! :deck) @@ -568,7 +568,7 @@ (continue-ability (let [chosen-ice target] {:async true - :prompt (str "Choose a server to install " (:title chosen-ice) " on") + :prompt (s/strcat "Choose a server to install " (:title chosen-ice) " on") :choices (filter #(#{"HQ" "Archives" "R&D"} %) (installable-servers state chosen-ice)) :effect (effect (shuffle! :deck) @@ -671,9 +671,9 @@ (let [card (find-latest state card) stolen-agenda (find-latest state (:card context)) title (get-title stolen-agenda) - prompt (str "Forfeit Divested Trust to add " title + prompt (s/strcat "Forfeit Divested Trust to add " title " to HQ and gain 5 [Credits]?") - message (str "add " title " to HQ and gain 5 [Credits]") + message (s/strcat "add " title " to HQ and gain 5 [Credits]") card-side (if (in-runner-scored? state side card) :runner :corp)] (continue-ability @@ -703,7 +703,7 @@ :waiting-prompt true :prompt "Choose a card to derez" :choices {:card #(rezzed? %)} - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (effect (derez target {:source-card card}))}}) @@ -776,7 +776,7 @@ ["Done"])) :effect (req (shuffle! state side :deck) (if (= "Done" target) - (do (system-msg state side (str "uses " (:title card) " to shuffle R&D")) + (do (system-msg state side (s/strcat "uses " (:title card) " to shuffle R&D")) (effect-completed state side eid)) (corp-install state side eid target nil {:install-state :rezzed-no-cost @@ -963,13 +963,13 @@ :choices (req (cancellable (:deck corp) :sorted)) :msg (msg "add " (:title target) " to HQ from R&D") :cancel-effect (req (shuffle! state side :deck) - (system-msg state side (str "shuffles R&D")) + (system-msg state side (s/strcat "shuffles R&D")) (effect-completed state side eid)) :effect (req (move state side target :hand) (if (< n 3) (continue-ability state side (graft (inc n)) card nil) (do (shuffle! state side :deck) - (system-msg state side (str "shuffles R&D")) + (system-msg state side (s/strcat "shuffles R&D")) (effect-completed state side eid))))})] {:on-score {:async true @@ -1059,7 +1059,7 @@ (not (faceup? %)))} :effect (effect (corp-install eid target nil {:msg-keys {:install-source card :display-origin true}})) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid))}}) (defcard "Hyperloop Extension" @@ -1084,7 +1084,7 @@ :effect (effect (gain-bad-publicity :corp eid 1))}}} card nil) (let [n (* 3 (count-bad-pub state))] - (system-msg state side (str "uses " (:title card) " to gain " n " [Credits]")) + (system-msg state side (s/strcat "uses " (:title card) " to gain " n " [Credits]")) (gain-credits state side eid n))))}}) (defcard "Improved Protein Source" @@ -1098,8 +1098,8 @@ (defcard "Improved Tracers" {:move-zone (req (when (and (in-scored? card) (= :corp (:scored-side card))) - (system-msg state side (str "uses " (:title card) " to increase the strength of Tracer ice by 1")) - (system-msg state side (str "uses " (:title card) " to increase the base strength of all trace subroutines by 1")) + (system-msg state side (s/strcat "uses " (:title card) " to increase the strength of Tracer ice by 1")) + (system-msg state side (s/strcat "uses " (:title card) " to increase the base strength of all trace subroutines by 1")) (update-all-ice state side))) :static-abilities [{:type :ice-strength :req (req (has-subtype? target "Tracer")) @@ -1130,13 +1130,13 @@ :msg (msg "trash " (card-str state target)) :req (req (some rezzed? (all-installed state :corp))) :choices {:card #(rezzed? %)} - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (req (let [target-cost (:cost target)] (wait-for (trash state side target {:cause-card card}) (continue-ability state side - {:prompt (str "Choose a runner card that costs " target-cost " or less to trash") + {:prompt (s/strcat "Choose a runner card that costs " target-cost " or less to trash") :choices {:card #(and (installed? %) (runner? %) (<= (:cost %) target-cost))} @@ -1165,7 +1165,7 @@ (update-all-agenda-points state) (check-win-by-agenda state side) (effect-completed state side eid)) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid))}] {:on-score {:async true :effect (req (wait-for @@ -1250,7 +1250,7 @@ :msg (msg "rez " (enumerate-str (map :title targets)) ", ignoring all costs") :async true :cancel-effect (req - (system-msg state side (str "declines to use " (:title card))) + (system-msg state side (s/strcat "declines to use " (:title card))) (ice-free-rez state side [] card current-server eid)) :effect (req (ice-free-rez state side targets card current-server eid))} card nil)))}}}]})) @@ -1263,7 +1263,7 @@ (in-hand? %))} :msg (msg "trash " (quantify (count targets) "card") " from HQ") :async true - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to trash any cards from HQ")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to trash any cards from HQ")) (shuffle-into-rd-effect eid card 3)) :effect (req (wait-for (trash-cards state side targets {:unpreventable true :cause-card card}) (shuffle-into-rd-effect state side eid card 3)))}}) @@ -1287,7 +1287,7 @@ :effect (req (if (= (count targets) 2) (do (swap-ice state side (first targets) (second targets)) (system-msg state side - (str "swaps the position of " + (s/strcat "swaps the position of " (card-str state (first targets)) " and " (card-str state (second targets)))) @@ -1301,7 +1301,7 @@ (defcard "Mandatory Upgrades" {:move-zone (req (when (and (in-scored? card) (= :corp (:scored-side card))) - (system-msg state side (str "uses " (:title card) " to gain 1 addition [Click] per turn")) + (system-msg state side (s/strcat "uses " (:title card) " to gain 1 addition [Click] per turn")) (when (= :corp (:active-player @state)) (gain-clicks state :corp 1)) (gain state :corp :click-per-turn 1))) @@ -1341,13 +1341,13 @@ "No action"]) :effect (req (case target "Gain 7 [Credits]" - (do (system-msg state side (str "uses " (:title card) " to gain 7 [Credits]")) + (do (system-msg state side (s/strcat "uses " (:title card) " to gain 7 [Credits]")) (gain-credits state side eid 7)) "Do 7 meat damage" - (do (system-msg state side (str "uses " (:title card) " to do 7 meat damage")) + (do (system-msg state side (s/strcat "uses " (:title card) " to do 7 meat damage")) (damage state side eid :meat 7 {:card card})) "No action" - (do (system-msg state side (str "declines to use " (:title card))) + (do (system-msg state side (s/strcat "declines to use " (:title card))) (effect-completed state side eid))))}}) (defcard "Midnight-3 Arcology" @@ -1369,7 +1369,7 @@ (let [nq {:async true :effect (req (let [extra (int (/ (:runner-spent target) 2))] (if (pos? extra) - (do (system-msg state :corp (str "uses " (:title card) " to gain " extra " [Credits]")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to gain " extra " [Credits]")) (gain-credits state side eid extra)) (effect-completed state side eid))))}] {:static-abilities [{:type :trace-force-link @@ -1485,7 +1485,7 @@ (let [pp {:req (req (pos? (count (:hand runner)))) :async true :effect (req (let [c (first (shuffle (:hand runner)))] - (system-msg state side (str "uses " (:title card) " to force the Runner" + (system-msg state side (s/strcat "uses " (:title card) " to force the Runner" " to trash " (:title c) " from the grip at random")) (trash state side eid c {:cause-card card})))}] @@ -1509,7 +1509,7 @@ :async true :effect (effect (draw eid 1))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}}}) + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}}) (defcard "Posted Bounty" {:on-score {:optional @@ -1567,7 +1567,7 @@ :msg (msg "force the Runner to trash " (trash-count-str (:card context)) " and take 1 bad publicity") :async true :effect (req (wait-for (trash-cards state side targets {:cause-card card :cause :forced-to-trash}) - (system-msg state side (str "trashes " (enumerate-str (map :title targets)))) + (system-msg state side (s/strcat "trashes " (enumerate-str (map :title targets)))) (gain-bad-publicity state :corp eid 1)))}})) (defcard "Project Atlas" @@ -1581,7 +1581,7 @@ :req (req (pos? (get-counters card :agenda))) :msg (msg "add " (:title target) " to HQ from R&D") :choices (req (cancellable (:deck corp) :sorted)) - :cancel-effect (effect (system-msg (str "declines to use " (:title card)))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card)))) :effect (effect (shuffle! :deck) (move target :hand))}]}) @@ -1607,7 +1607,7 @@ (rezzed? %))} :cost [(->c :agenda 1)] :keep-menu-open :while-agenda-tokens-left - :msg (str "make a piece of ice gain \"[Subroutine] Do 1 net damage\" " + :msg (s/strcat "make a piece of ice gain \"[Subroutine] Do 1 net damage\" " "after all its other subroutines for the remainder of the run") :effect (effect (add-extra-sub! (get-card state target) (do-net-damage 1) @@ -1621,7 +1621,7 @@ :move-zone (req (when (and (in-scored? card) (= :runner (:scored-side card)) (not= (first (:previous-zone card)) :discard)) - (system-msg state side (str "uses " (:title card) " to place 4 agenda counters on itself")) + (system-msg state side (s/strcat "uses " (:title card) " to place 4 agenda counters on itself")) (add-counter state side (get-card state card) :agenda 4))) :events [{:event :runner-turn-begins :req (req (pos? (get-counters card :agenda))) @@ -1633,7 +1633,7 @@ (when (zero? (get-counters card :agenda)) (let [points (get-agenda-points card)] (system-msg state :runner - (str "gains " (quantify points "agenda point") + (s/strcat "gains " (quantify points "agenda point") " from " (:title card)))))) (check-win-by-agenda state side))}]}) @@ -1662,7 +1662,7 @@ (= :approach-ice (:phase run)))) :cost [(->c :agenda 1)] :keep-menu-open :while-agenda-tokens-left - :msg (str "make the approached piece of Bioroid ice gain \"[Subroutine] End the run\"" + :msg (s/strcat "make the approached piece of Bioroid ice gain \"[Subroutine] End the run\"" "after all its other subroutines for the remainder of this run") :effect (effect (add-extra-sub! (get-card state current-ice) {:label "End the run" @@ -1677,7 +1677,7 @@ (update! state side (assoc-in card [:counter :agenda] (+ 1 (get-counters card :agenda))))) (choose-swap [to-swap] {:async true - :prompt (str "Choose a card in HQ to swap with " (:title to-swap)) + :prompt (s/strcat "Choose a card in HQ to swap with " (:title to-swap)) :choices {:not-self true :card #(and (corp? %) (in-hand? %) @@ -1733,18 +1733,18 @@ (defcard "Rebranding Team" {:move-zone (req (when (and (in-scored? card) (= :corp (:scored-side card))) - (system-msg state side (str "uses " (:title card) " to make all assets gain Advertisement")))) + (system-msg state side (s/strcat "uses " (:title card) " to make all assets gain Advertisement")))) :static-abilities [{:type :gain-subtype :req (req (asset? target)) :value "Advertisement"}]}) (defcard "Reeducation" (letfn [(corp-final [chosen original] - {:prompt (str "The bottom cards of R&D will be " (enumerate-str (map :title chosen))) + {:prompt (s/strcat "The bottom cards of R&D will be " (enumerate-str (map :title chosen))) :choices ["Done" "Start over"] :async true :msg (req (let [n (count chosen)] - (str "add " (quantify n "card") " from HQ to the bottom of R&D and draw " (quantify n "card") + (s/strcat "add " (quantify n "card") " from HQ to the bottom of R&D and draw " (quantify n "card") (when (<= n (count (:hand runner))) (str ". The Runner randomly adds " (quantify n "card") @@ -1804,7 +1804,7 @@ (update-all-agenda-points state) (check-win-by-agenda state side) (effect-completed state side eid))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))))}}) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}) (defcard "Regulatory Capture" {:advancement-requirement (req (- (min 4 (count-bad-pub state))))}) @@ -1822,7 +1822,7 @@ (defcard "Remote Data Farm" {:move-zone (req (when (and (in-scored? card) (= :corp (:scored-side card))) - (system-msg state side (str "uses " (:title card) " to increase [their] maximum hand size by 2")))) + (system-msg state side (s/strcat "uses " (:title card) " to increase [their] maximum hand size by 2")))) :static-abilities [(corp-hand-size+ 2)]}) (defcard "Remote Enforcement" @@ -1842,7 +1842,7 @@ (continue-ability (let [chosen-ice target] {:async true - :prompt (str "Choose a server to install " (:title chosen-ice) " on") + :prompt (s/strcat "Choose a server to install " (:title chosen-ice) " on") :choices (filter #(not (#{"HQ" "Archives" "R&D"} %)) (installable-servers state chosen-ice)) :effect (effect (shuffle! :deck) @@ -1862,7 +1862,7 @@ :silent (req (empty? (filter #(= (:title %) (:title card)) (all-installed state :corp)))) :async true :effect (effect (continue-ability - {:prompt (str "Choose another installed copy of " (:title card) " to score") + {:prompt (s/strcat "Choose another installed copy of " (:title card) " to score") :choices {:card #(= (:title %) (:title card))} :interactive (req true) :async true @@ -1924,7 +1924,7 @@ (defcard "Self-Destruct Chips" {:move-zone (req (when (and (in-scored? card) (= :corp (:scored-side card))) - (system-msg state side (str "uses " (:title card) + (system-msg state side (s/strcat "uses " (:title card) " to decrease the Runner's maximum hand size by 1")))) :static-abilities [(runner-hand-size+ -1)]}) @@ -2045,24 +2045,24 @@ :cancel-effect (req (if (= side :runner) (wait-for (draw state :corp 1) (clear-wait-prompt state :corp) - (system-msg state :runner (str "declines to trash a card for " (:title card))) - (system-msg state :corp (str "uses " (:title card) " to draw 1 card and gain 5 [Credits]")) + (system-msg state :runner (s/strcat "declines to trash a card for " (:title card))) + (system-msg state :corp (s/strcat "uses " (:title card) " to draw 1 card and gain 5 [Credits]")) (gain-credits state :corp eid 5)) - (do (system-msg state :corp (str "declines to trash a card for " (:title card))) + (do (system-msg state :corp (s/strcat "declines to trash a card for " (:title card))) (clear-wait-prompt state :runner) (effect-completed state :corp eid)))) :effect (req (wait-for (trash state side target (if (= side :corp) {:unpreventable true :cause-card card} {:unpreventable true :cause-card card :cause :forced-to-trash})) - (system-msg state side (str "trashes " (card-str state target) " for " (:title card))) + (system-msg state side (s/strcat "trashes " (card-str state target) " for " (:title card))) (clear-wait-prompt state (other-side side)) - (show-wait-prompt state side (str (side-str (other-side side)) " to trash a card for " (:title card))) + (show-wait-prompt state side (s/strcat (side-str (other-side side)) " to trash a card for " (:title card))) (continue-ability state (other-side side) (stand (other-side side)) card nil)))})] {:on-score {:interactive (req true) :async true - :effect (effect (show-wait-prompt (str (side-str (other-side side)) " to trash a card for Standoff")) + :effect (effect (show-wait-prompt (s/strcat (side-str (other-side side)) " to trash a card for Standoff")) (continue-ability :runner (stand :runner) card nil))}})) (defcard "Stegodon MK IV" @@ -2271,7 +2271,7 @@ :async true :req (req (same-card? card (:card context))) :msg (msg (if (pos? (count (:deck runner))) - (str "trash " + (s/strcat "trash " (enumerate-str (map :title (take (adv4? state card) (:deck runner)))) " from the stack") "trash no cards from the stack (it is empty)")) diff --git a/src/clj/game/cards/assets.clj b/src/clj/game/cards/assets.clj index e3869300f3..78b7da3f02 100644 --- a/src/clj/game/cards/assets.clj +++ b/src/clj/game/cards/assets.clj @@ -62,7 +62,8 @@ [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] [jinteki.utils :refer :all] - [game.core.link :refer [get-link]])) + [game.core.link :refer [get-link]] + [stringer.core :as s])) ;;; Asset-specific helpers (defn- advance-ambush @@ -79,7 +80,7 @@ ability {:msg (msg "gain " (num-counters card) " [Credits]") :once :per-turn :req (req (:corp-phase-12 @state)) - :label (str "Gain " per-turn " [Credits] (start of turn)") + :label (s/strcat "Gain " per-turn " [Credits] (start of turn)") :async true :effect (req (wait-for (gain-credits state side (num-counters card)) (add-counter state side eid card counter-type (- (num-counters card)) nil)))}] @@ -169,7 +170,7 @@ (when (pos? unprevented) (shuffle! state :corp :deck)) (system-msg state :runner - (str "pays " target " [Credits] to prevent " + (s/strcat "pays " target " [Credits] to prevent " (quantify prevented "random card") " in HQ from being shuffled into R&D"))) (shuffle-into-deck state :corp :hand)))} @@ -189,7 +190,7 @@ (letfn [(select-archives-cards [total] {:async true :show-discard true - :prompt (str "Choose " (quantify total "card") " from Archives") + :prompt (s/strcat "Choose " (quantify total "card") " from Archives") :choices {:card #(and (corp? %) (in-discard? %)) :max total @@ -197,7 +198,7 @@ :effect (effect (complete-with-result eid targets))}) (select-hq-cards [total] {:async true - :prompt (str "Choose " (quantify total "card") " from HQ") + :prompt (s/strcat "Choose " (quantify total "card") " from HQ") :choices {:card #(and (corp? %) (in-hand? %)) :max total @@ -266,13 +267,13 @@ state side {:optional {:waiting-prompt true - :prompt (str "Move advancement tokens to " icename "?") + :prompt (s/strcat "Move advancement tokens to " icename "?") :yes-ability {:prompt "How many advancement tokens do you want to move?" :choices {:number (req (get-counters card :advancement))} :effect (effect (add-prop :corp ice :advance-counter target {:placed true}) (add-prop :corp card :advance-counter (- target) {:placed true}) - (system-msg (str "uses " (:title card) " to move " + (system-msg (s/strcat "uses " (:title card) " to move " (quantify target "advancement counter") " to " (card-str state ice))))}}} card nil)))}] @@ -291,7 +292,7 @@ :async true :effect (req (let [cnt (get-counters target :advancement)] (set-prop state side target :advance-counter (dec cnt)) - (system-msg state :corp (str "uses " (:title card) " to remove 1 advancement counter from " + (system-msg state :corp (s/strcat "uses " (:title card) " to remove 1 advancement counter from " (card-str state target) " and gains 3 [Credits]")) (gain-credits state :corp eid 3)))}]})) @@ -336,9 +337,9 @@ " from the top of R&D and gain 2 [Credits]") :effect (req (wait-for (reveal state side (make-eid state eid) top-card) (gain-credits state :corp eid 2)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to reveal the top card of R&D")))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to reveal the top card of R&D")))}}} card nil) - (do (system-msg state side (str "declines to use " (:title card) " to reveal the top card of R&D")) + (do (system-msg state side (s/strcat "declines to use " (:title card) " to reveal the top card of R&D")) (effect-completed state side eid))))))} ability {:label "Look at the top card of R&D (start of turn)" :once :per-turn @@ -363,7 +364,7 @@ {:req (req (not (in-discard? card))) :waiting-prompt true :prompt (msg "Pay 4 [Credits] to use " (:title card) " ability?") - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))} :yes-ability {:async true :cost [(->c :credit 4)] :msg "give the runner 2 tags" @@ -427,7 +428,7 @@ :poison true :on-access {:async true :effect (req (let [c (first (get-in @state [:runner :deck]))] - (system-msg state :corp (str "uses " (:title card) " to do 1 meat damage" + (system-msg state :corp (s/strcat "uses " (:title card) " to do 1 meat damage" " and to trash " (:title c) " from the top of the stack")) (wait-for (mill state :corp :runner 1) @@ -538,7 +539,7 @@ {:events [{:event :end-of-encounter :req (req (pos? (count (remove :broken (:subroutines (:ice context)))))) :msg (req (let [unbroken-count (count (remove :broken (:subroutines (:ice context))))] - (str "place " (quantify unbroken-count "power counter") " on itself"))) + (s/strcat "place " (quantify unbroken-count "power counter") " on itself"))) :effect (effect (add-counter :corp card :power (count (remove :broken (:subroutines (:ice context))))))}] :abilities [{:action true :cost [(->c :click 1) (->c :power 5)] @@ -559,7 +560,7 @@ "Take 1 tag"]) :msg (msg (if (= target "Take 1 tag") "give the runner 1 tag" - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :async true :effect (req (if (= target "Pay 1 [Credits]") (wait-for (pay state :runner (make-eid state eid) card (->c :credit 1)) @@ -832,13 +833,13 @@ state side (when (seq drawn) {:waiting-prompt true - :prompt (str "Choose " (quantify dbs "card") " to add to the bottom of R&D") + :prompt (s/strcat "Choose " (quantify dbs "card") " to add to the bottom of R&D") :choices {:max (min dbs (count drawn)) :card #(some (fn [c] (same-card? c %)) drawn) :all true} :effect (req (doseq [c (reverse targets)] (system-msg state side - (str "uses " (:title card) " to add the " + (s/strcat "uses " (:title card) " to add the " (pprint/cl-format nil "~:R" (inc (first (keep-indexed #(when (same-card? c %2) %1) drawn)))) " card drawn to the bottom of R&D")) (move state side c :deck) @@ -858,7 +859,7 @@ :events [{:event :successful-run :req (req this-server) :async true - :effect (effect (system-msg :runner (str "gains 2 [Credits] for a successful run " + :effect (effect (system-msg :runner (s/strcat "gains 2 [Credits] for a successful run " "on the Daily Quest server")) (gain-credits :runner eid 2))} (assoc ability :event :corp-turn-begins)] @@ -928,7 +929,7 @@ :label "Reveal an agenda from HQ or Archives" :msg (msg "reveal " (:title target) " from " (zone->name (get-zone target)) (let [target-agenda-points (get-agenda-points target)] - (str ", gain " target-agenda-points " [Credits], ")) + (s/strcat ", gain " target-agenda-points " [Credits], ")) " and shuffle it into R&D") :async true :effect (req (wait-for @@ -1020,7 +1021,7 @@ :async true :effect (req (let [counters (get-counters card :power) credits (* 2 counters)] - (system-msg state side (str "uses " (:title card) " to draw " (quantify counters "card") + (system-msg state side (s/strcat "uses " (:title card) " to draw " (quantify counters "card") " and gain " credits " [Credits]")) (wait-for (draw state side counters) (gain-credits state side eid credits))))}]}) @@ -1102,7 +1103,7 @@ :yes-ability {:msg "draw 1 card" :async true :effect (effect (draw eid 1))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to draw 1 card")))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to draw 1 card")))}}} ability {:once :per-turn :req (req (and (:corp-phase-12 @state) @@ -1193,7 +1194,7 @@ :waiting-prompt true :msg (msg (if (= target "Done") "shuffle R&D" - (str "add " (get-title target) " from R&D to HQ"))) + (s/strcat "add " (get-title target) " from R&D to HQ"))) :choices (req (conj (vec (sort-by :title (filter operation? (:deck corp)))) "Done")) :async true :effect (req (if (= target "Done") @@ -1347,7 +1348,7 @@ (defcard "Ibrahim Salem" (let [trash-ability (fn [card-type] {:req (req (seq (filter #(is-type? % card-type) (:hand runner)))) - :prompt (str "Choose a " card-type " to trash") + :prompt (s/strcat "Choose a " card-type " to trash") :choices (req (filter #(is-type? % card-type) (:hand runner))) :async true :effect (effect (trash eid target {:cause-card card})) @@ -1493,7 +1494,7 @@ :flags {:corp-phase-12 (req true)} :abilities [{:msg "look at the top card of the stack" :effect (effect (continue-ability - {:prompt (req (->> runner :deck first :title (str "The top card of the stack is "))) + {:prompt (req (->> runner :deck first :title (s/strcat "The top card of the stack is "))) :choices ["OK"]} card nil))} {:async true @@ -1597,7 +1598,7 @@ :cost [(->c :click 1) (->c :tag 1)] :msg (msg (if (= target "No action") "shuffle R&D" - (str "reveal " (:title target) " from R&D and add it to the top of R&D"))) + (s/strcat "reveal " (:title target) " from R&D and add it to the top of R&D"))) :choices (req (conj (vec (sort-by :title (filter operation? (:deck corp)))) "No action")) :async true :effect (req (if (= target "No action") @@ -1664,7 +1665,7 @@ (let [ability {:once :per-turn :interactive (req (>= 2 (get-counters card :credit))) :req (req (:corp-phase-12 @state)) - :label (str "Gain 2 [Credits] (start of turn)") + :label (s/strcat "Gain 2 [Credits] (start of turn)") :msg (msg "gain " (min 2 (get-counters card :credit)) " [Credits]") :async true :effect (req (let [credits (min 2 (get-counters card :credit))] @@ -1766,7 +1767,7 @@ (moon-pool-place-advancements (dec x)) card nil) (effect-completed state side eid)))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to place advancement counters")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to place advancement counters")) (effect-completed eid))})] (let [moon-pool-reveal-ability {:prompt "Choose up to 2 facedown cards from Archives to shuffle into R&D" @@ -1788,7 +1789,7 @@ (moon-pool-place-advancements agenda-count) card nil) (effect-completed state side eid))))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to reveal any cards in Archives")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to reveal any cards in Archives")) (effect-completed eid))} moon-pool-discard-ability {:prompt "Choose up to 2 cards from HQ to trash" @@ -1802,7 +1803,7 @@ state side moon-pool-reveal-ability card nil))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to trash any cards from HQ")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to trash any cards from HQ")) (continue-ability moon-pool-reveal-ability card nil))}] {:abilities [{:label "Trash up to 2 cards from HQ. Shuffle up to 2 cards from Archives into R&D" :cost [(->c :remove-from-game)] @@ -1870,7 +1871,7 @@ :prompt (msg (let [mus (count (filter #(and (= (:title card) (:title %)) (rezzed? %)) (all-installed state :corp)))] - (str "Choose " (quantify mus "card") " in Archives to shuffle into R&D"))) + (s/strcat "Choose " (quantify mus "card") " in Archives to shuffle into R&D"))) :choices {:card #(and (corp? %) (in-discard? %)) :max (req (count (filter #(and (= (:title card) (:title %)) @@ -1882,9 +1883,9 @@ :msg (msg "shuffle " (let [seen (filter :seen targets) n (count (filter #(not (:seen %)) targets))] - (str (enumerate-str (map :title seen)) + (s/strcat (enumerate-str (map :title seen)) (when (pos? n) - (str (when-not (empty? seen) " and ") + (s/strcat (when-not (empty? seen) " and ") (quantify n "card"))))) " into R&D") :effect (req (doseq [c targets] @@ -1992,8 +1993,8 @@ {:cost [(->c :advancement cost) (->c :trash-can)] :async true :effect (effect (gain-credits eid cred)) - :label (str "Gain " cred " [Credits]") - :msg (str "gain " cred " [Credits]")})] + :label (s/strcat "Gain " cred " [Credits]") + :msg (s/strcat "gain " cred " [Credits]")})] {:advanceable :always :abilities [(builder 1 5) (builder 2 8)]})) @@ -2014,7 +2015,7 @@ (effect-completed state side eid) (wait-for (trash state :corp card {:unpreventable true :cause-card card}) - (system-msg state :corp (str "trashes Nico Campaign" + (system-msg state :corp (s/strcat "trashes Nico Campaign" (when (seq (:deck corp)) " and draws 1 card"))) (draw state :corp eid 1))))))}] @@ -2029,7 +2030,7 @@ :on-access {:async true :msg (msg (if (= target "Suffer 1 core damage") "do 1 core damage" - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :player :runner :prompt "Choose one" :choices ["Suffer 1 core damage" "Add Nightmare Archive to score area"] @@ -2043,7 +2044,7 @@ {:events [{:event :corp-mandatory-draw :interactive (req true) :msg (msg (if (-> corp :deck count pos?) - (str "reveal " + (s/strcat "reveal " (-> corp :deck first :title) " from the top of R&D and add it to HQ") "reveal no cards from R&D (it is empty)")) @@ -2113,7 +2114,7 @@ (let [cnt (count (get-in @state [:runner :hand])) credits (quot cnt 2)] (system-msg state :corp - (str "uses " (:title card) " to force the runner to draw " + (s/strcat "uses " (:title card) " to force the runner to draw " "1 card and gain " credits " [Credits]")) (gain-credits state :corp eid credits))))}]}) @@ -2215,7 +2216,7 @@ (let [ab {:async true :req (req installed) :effect (req (let [hand (count (:hand runner)) - message (str "do " hand " net damage")] + message (s/strcat "do " hand " net damage")] (continue-ability state side {:psi {:not-equal @@ -2390,7 +2391,7 @@ :prompt "Choose a card that can be advanced" :choices {:req (req (can-be-advanced? state target))} :effect (effect (add-counter target :advancement num-counters {:placed true}) - (system-msg (str "uses " (:title card) " to move " (quantify num-counters "hosted advancement token") " to " (card-str state target))) + (system-msg (s/strcat "uses " (:title card) " to move " (quantify num-counters "hosted advancement token") " to " (card-str state target))) (effect-completed eid))} card nil)))}]}) @@ -2624,15 +2625,15 @@ {:player :runner :prompt "Choose one" :waiting-prompt true - :choices [(str "Take " dmg " net damage") "Add Shi.Kyū to score area"] + :choices [(s/strcat "Take " dmg " net damage") "Add Shi.Kyū to score area"] :async true :effect (req (if (str/starts-with? target "Add") - (do (system-msg state :runner (str "adds " (:title card) + (do (system-msg state :runner (s/strcat "adds " (:title card) " to [their] score area as an agenda worth " (quantify -1 "agenda point"))) (as-agenda state :runner card -1) (effect-completed state side eid)) - (do (system-msg state :runner (str "takes " dmg " net damage from " (:title card))) + (do (system-msg state :runner (s/strcat "takes " dmg " net damage from " (:title card))) (damage state :corp eid :net dmg {:card card}))))}) card targets))}}}}) @@ -2664,7 +2665,7 @@ {:req (req (not (in-discard? card))) :waiting-prompt true :prompt (msg "Pay 4 [Credits] to use " (:title card) " ability?") - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))} :yes-ability {:async true :cost [(->c :credit 4)] :msg "do 3 net damage and give the Runner 1 tag" @@ -2757,7 +2758,7 @@ :req (req (and (corp? target) (installed? target)))} :msg (msg "trash " (card-str state target) " and gain 3 [Credits]") - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (req (wait-for (trash state side target {:unpreventable true :cause-card card}) @@ -2977,7 +2978,7 @@ :effect (req (add-counter state side card :power -1) (if (not (pos? (get-counters (get-card state card) :power))) (wait-for (trash state side card {:cause-card card}) - (system-msg state :corp (str "uses " (:title card) " to do 4 meat damage")) + (system-msg state :corp (s/strcat "uses " (:title card) " to do 4 meat damage")) (damage state side eid :meat 4 {:card card})) (effect-completed state side eid)))}]}) @@ -3031,12 +3032,12 @@ :yes-ability {:async true :effect (req (wait-for (reveal state side (:hand runner)) - (system-msg state :corp (str "reveal " + (system-msg state :corp (s/strcat "reveal " (quantify (count (:hand runner)) "card") " from grip: " (enumerate-str (map :title (:hand runner))))) (continue-ability state side select-and-trash card nil)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] {:events [{:event :agenda-scored :interactive (req true) :async true @@ -3222,7 +3223,7 @@ {:prompt "Choose a resource" :req (req (seq (all-installed-runner-type state :resource))) :choices {:card #(resource? %)} - :msg (msg (str "add " (:title target) " to the top of the stack")) + :msg (msg (s/strcat "add " (:title target) " to the top of the stack")) :effect (req (move state :runner target :deck {:front true}))} card nil) (effect-completed state side eid)))}]}) diff --git a/src/clj/game/cards/basic.clj b/src/clj/game/cards/basic.clj index 9a5c083adf..16e06b4227 100644 --- a/src/clj/game/cards/basic.clj +++ b/src/clj/game/cards/basic.clj @@ -24,7 +24,8 @@ [game.core.to-string :refer [card-str]] [game.macros :refer [effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) ;; Card definitions (defcard "Corp Basic Action Card" @@ -130,18 +131,18 @@ (wait-for (resolve-ability state side (make-eid state eid) - {:prompt (str "Pay the additional cost to trash " (:title target) "?") + {:prompt (s/strcat "Pay the additional cost to trash " (:title target) "?") :choices [(when can-pay cost-strs) "No"] :async true :effect (req (if (= target "No") - (do (system-msg state side (str "declines to pay the additional cost to trash " (:title target))) + (do (system-msg state side (s/strcat "declines to pay the additional cost to trash " (:title target))) (effect-completed state side eid)) (wait-for (pay state side (make-eid state (assoc eid :additional-costs additional-costs :source-type :trash-card)) nil additional-costs) - (system-msg state side (str (:msg async-result) " as an additional cost to trash " (:title target))) + (system-msg state side (s/strcat (:msg async-result) " as an additional cost to trash " (:title target))) (complete-with-result state side eid target))))} card nil) (if async-result diff --git a/src/clj/game/cards/events.clj b/src/clj/game/cards/events.clj index b12399ccbd..d22966b21d 100644 --- a/src/clj/game/cards/events.clj +++ b/src/clj/game/cards/events.clj @@ -72,7 +72,8 @@ [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] [jinteki.utils :refer :all] - [jinteki.validator :refer [legal?]])) + [jinteki.validator :refer [legal?]] + [stringer.core :as s])) (defn- cutlery [subtype] @@ -159,7 +160,7 @@ :unsuccessful {:async true :effect (effect (gain-credits :runner eid (+ (:agenda-point runner) (:agenda-point corp)))) - :msg (msg (str "gain " (+ (:agenda-point runner) (:agenda-point corp)) " [Credits]"))}}}]}) + :msg (msg (s/strcat "gain " (+ (:agenda-point runner) (:agenda-point corp)) " [Credits]"))}}}]}) (defcard "Apocalypse" (let [corp-trash {:async true @@ -206,7 +207,7 @@ (doseq [c top-5] (move state side c :rfg)) (system-msg state side - (str "removes " + (s/strcat "removes " (enumerate-str (map :title top-5)) " from the game and draws 5 cards")) (draw state :runner eid 5)))}}) @@ -240,7 +241,7 @@ :async true :msg "place 4 [Credits] for paying trash costs"}] choice (fn choice [abis rem] - {:prompt (str "Choose an ability to resolve (" rem " remaining)") + {:prompt (s/strcat "Choose an ability to resolve (" rem " remaining)") :waiting-prompt true :choices (map #(capitalize (:msg %)) abis) :async true @@ -319,10 +320,10 @@ :effect (req (when-not (string? target) (move state side target :deck)) (system-msg state side - (str "looks at the top 2 cards of the stack" + (s/strcat "looks at the top 2 cards of the stack" (when-not (string? target) " and adds one to the bottom of the stack"))) - (system-msg state side (str "uses " (:title card) " to draw 2 cards")) + (system-msg state side (s/strcat "uses " (:title card) " to draw 2 cards")) (draw state :runner eid 2))}}) (defcard "Bravado" @@ -438,13 +439,13 @@ (defcard "Burner" (letfn [(move-ab [chosen-cards n] - {:prompt (str "Choose a card (" n " remaining)") + {:prompt (s/strcat "Choose a card (" n " remaining)") :choices chosen-cards :async true :effect (req (let [target-card target] (continue-ability state side - {:prompt (str "Choose where to put " (:title target-card)) + {:prompt (s/strcat "Choose where to put " (:title target-card)) :choices ["Top of R&D" "Bottom of R&D"] :async true :msg (msg "add " (:title target-card) " to the " @@ -477,7 +478,7 @@ :effect (req (let [chosen-cards (take 3 (shuffle (:hand corp)))] (system-msg state side - (str "reveals " (enumerate-str (map :title chosen-cards)) + (s/strcat "reveals " (enumerate-str (map :title chosen-cards)) " from HQ")) (continue-ability state side @@ -555,14 +556,14 @@ (resolve-ability state side identify-mark-ability card nil) (let [marked-server (:mark @state)] (update! state :runner (assoc card :card-target (central->name marked-server))) - (system-msg state side (str "uses " (:title card) " to gain 4 [Credits]")) + (system-msg state side (s/strcat "uses " (:title card) " to gain 4 [Credits]")) (wait-for (gain-credits state :runner 4) (continue-ability state side {:optional - {:prompt (str "Run on " (zone->name marked-server) "?") - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to make a run")))} - :yes-ability {:msg (str "make a run on " (zone->name marked-server)) + {:prompt (s/strcat "Run on " (zone->name marked-server) "?") + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to make a run")))} + :yes-ability {:msg (s/strcat "make a run on " (zone->name marked-server)) :async true :effect (effect (make-run eid marked-server))}}} card nil)))))}}) @@ -570,7 +571,7 @@ (defcard "CBI Raid" (letfn [(cbi-final [chosen original] {:player :corp - :prompt (str "The top cards of R&D will be " (enumerate-str (map :title chosen))) + :prompt (s/strcat "The top cards of R&D will be " (enumerate-str (map :title chosen))) :choices ["Done" "Start over"] :async true :effect (req (if (= target "Done") @@ -639,7 +640,7 @@ card nil)) (do (wait-for (reveal state side target) - (system-msg state :corp (str "reveals " (:title target) " from HQ")) + (system-msg state :corp (s/strcat "reveals " (:title target) " from HQ")) (continue-ability state :runner {:msg "gain [Click] and draw 1 card" @@ -732,7 +733,7 @@ :effect (req (let [compile-installed (first (filterv #(get-in % [:special :compile-installed]) (all-active-installed state :runner)))] (if (some? compile-installed) - (do (system-msg state :runner (str "moved " (:title compile-installed) + (do (system-msg state :runner (s/strcat "moved " (:title compile-installed) " to the bottom of the Stack")) (move state :runner compile-installed :deck) (effect-completed state side eid)) @@ -822,14 +823,14 @@ :prompt (msg "Spend " cost " [Credits] to prevent the trash of " title "?") :player :corp :yes-ability {:async true - :effect (req (system-msg state :corp (str "spends " cost " [Credits] to prevent " + :effect (req (system-msg state :corp (s/strcat "spends " cost " [Credits] to prevent " title " from being trashed at no cost")) (lose-credits state :corp eid cost))} :no-ability {:msg (msg "trash " title " at no cost") :async true :effect (effect (trash eid (assoc c :seen true) {:cause-card card}))}}} card nil) - (do (system-msg state side (str "uses " (:title card) " to trash " title " at no cost")) + (do (system-msg state side (s/strcat "uses " (:title card) " to trash " title " at no cost")) (trash state side eid (assoc c :seen true) nil)))))}]}) (defcard "Credit Kiting" @@ -973,14 +974,14 @@ :change-in-game-state (req (seq (:deck corp))) :effect (req (set-aside state :corp eid (take 8 (:deck corp))) (let [top-8 (sort-by :title (get-set-aside state :corp eid))] - (system-msg state side (str "uses " (get-title card) + (system-msg state side (s/strcat "uses " (get-title card) " to set aside " (enumerate-str (map get-title top-8)) " from the top of R&D")) (wait-for (resolve-ability state side {:async true - :prompt (str "The set aside cards are: " + :prompt (s/strcat "The set aside cards are: " (enumerate-str (map get-title top-8))) :choices ["OK"]} card nil) @@ -995,7 +996,7 @@ (assoc eid :source card :source-type :ability) card nil [(->c :click 1)])) :no-ability - {:effect (effect (system-msg (str "declines to use " + {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to access another card")))} :yes-ability @@ -1116,7 +1117,7 @@ :effect (req (let [installed-cards (filter #(get-in % [:special :diana-installed]) (all-active-installed state :runner))] (if (seq installed-cards) (do - (system-msg state :runner (str "trashes " (quantify (count installed-cards) "card") + (system-msg state :runner (s/strcat "trashes " (quantify (count installed-cards) "card") " (" (enumerate-str (map :title installed-cards)) ") at the end of the run from Diana's Hunt")) (trash-cards state :runner eid installed-cards {:unpreventable true @@ -1215,7 +1216,7 @@ (if-let [target async-result] (if (or (asset? target) (upgrade? target)) - (do (system-msg state :runner (str "uses " (:title card) " to trash " (:title target))) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to trash " (:title target))) (trash state :runner eid (assoc target :seen true) {:cause-card card})) (effect-completed state side eid)) (effect-completed state side eid))))}}) @@ -1255,7 +1256,7 @@ cards-to-trash (filter #(is-type? % target) cards-to-reveal) credits (* 4 (count cards-to-trash))] (system-msg state side - (str "uses " (:title card) " to reveal " + (s/strcat "uses " (:title card) " to reveal " (enumerate-str (map :title cards-to-reveal)) " from HQ")) (wait-for @@ -1263,7 +1264,7 @@ (if (pos? credits) (do (system-msg state side - (str "uses " (:title card) " to trash " + (s/strcat "uses " (:title card) " to trash " (enumerate-str (map :title cards-to-trash)) " from HQ and gain " credits " [Credits]")) @@ -1386,14 +1387,14 @@ :no-ability {:async true :effect (req (wait-for (reveal state side topcard) - (system-msg (str "reveals " + (system-msg (s/strcat "reveals " (:title topcard) " from the top of the stack and trashes it")) (trash eid topcard {:unpreventable true :cause-card card})))}}} card nil) (wait-for (reveal state side topcard) - (system-msg state side (str "reveals " (:title topcard) " from the top of the stack and trashes it")) + (system-msg state side (s/strcat "reveals " (:title topcard) " from the top of the stack and trashes it")) (trash state side eid topcard {:unpreventable true :cause-card card})))))}}) (defcard "Exclusive Party" @@ -1596,8 +1597,8 @@ {:prompt "Choose one" :choices [(when (and (can-rez? state :corp ice) (can-pay? state :corp eid ice nil (get-rez-cost state :corp ice nil))) - (str "Rez " (card-str state ice))) - (str "Trash " (card-str state ice))] + (s/strcat "Rez " (card-str state ice))) + (s/strcat "Trash " (card-str state ice))] :async true :msg (msg "force the Corp to " (decapitalize target)) :waiting-prompt true @@ -1629,7 +1630,7 @@ (effect (continue-ability (let [top-ten (take 10 (:deck runner))] - {:prompt (str "The top cards of the stack are (top->bottom): " (enumerate-str (map :title top-ten))) + {:prompt (s/strcat "The top cards of the stack are (top->bottom): " (enumerate-str (map :title top-ten))) :choices ["OK"] :async true :effect @@ -1648,7 +1649,7 @@ :effect (req (letfn [(log-and-trash-cards [cards] (system-msg state side - (str "uses " (get-title card) + (s/strcat "uses " (get-title card) " to trash " (enumerate-str (map :title cards)) " from the top of the stack")) @@ -1714,9 +1715,9 @@ :msg (msg "move " (let [seen (filter :seen targets) m (count (remove :seen targets))] - (str (enumerate-str (map :title seen)) + (s/strcat (enumerate-str (map :title seen)) (when (pos? m) - (str (when-not (empty? seen) " and ") + (s/strcat (when-not (empty? seen) " and ") (quantify m "unseen card"))) " into HQ, then trash 5 cards"))) :effect (req (doseq [c targets] @@ -1761,13 +1762,13 @@ (= 0 remaining-choices) (empty? remaining))] {:prompt (msg (if finished? - (str "Shuffling: " (enumerate-str to-shuffle)) - (str "Choose up to " remaining-choices + (s/strcat "Shuffling: " (enumerate-str to-shuffle)) + (s/strcat "Choose up to " remaining-choices (when (not-empty to-shuffle) " more") " cards." (when (not-empty to-shuffle) - (str "[br]Shuffling: " (enumerate-str to-shuffle)))))) + (s/strcat "[br]Shuffling: " (enumerate-str to-shuffle)))))) :async true :choices (req (if finished? ["OK" "Start over"] @@ -1784,7 +1785,7 @@ :effect (req (if (and (not (zone-locked? state :runner :discard)) (pos? (count (:discard runner)))) (continue-ability state side (choose-next '() nil (sort (distinct (map :title (:discard runner))))) card nil) - (do (system-msg state :runner (str "uses " (:title card) " to shuffle the stack")) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to shuffle the stack")) (shuffle! state :runner :deck) (effect-completed state side eid))))}})) @@ -1815,7 +1816,7 @@ (let [connection target] (if (can-pay? state side (assoc eid :source card :source-type :runner-install) connection nil [(->c :credit (install-cost state side connection))]) - {:optional {:prompt (str "Install " (:title connection) "?") + {:optional {:prompt (s/strcat "Install " (:title connection) "?") :yes-ability {:async true :effect (effect (runner-install (assoc eid :source card :source-type :runner-install) connection nil) (shuffle! :deck))} @@ -1945,7 +1946,7 @@ (defcard "Information Sifting" (letfn [(access-pile [cards pile pile-size] {:prompt "Choose a card to access. You must access all cards" - :choices [(str "Card from pile " pile)] + :choices [(s/strcat "Card from pile " pile)] :async true :req (req (if (:max-access run) (< (total-cards-accessed run) (:max-access run)) @@ -1959,11 +1960,11 @@ {:player :runner :waiting-prompt true :prompt "Choose a pile to access" - :choices [(str "Pile 1 (" (quantify (count p1) "card") ")") - (str "Pile 2 (" (quantify (count p2) "card") ")")] + :choices [(s/strcat "Pile 1 (" (quantify (count p1) "card") ")") + (s/strcat "Pile 2 (" (quantify (count p2) "card") ")")] :async true :effect (req (let [choice (if (str/starts-with? target "Pile 1") 1 2)] - (system-msg state side (str "chooses to access " target)) + (system-msg state side (s/strcat "chooses to access " target)) (continue-ability state side (access-pile (if (= 1 choice) p1 p2) choice (count (if (= 1 choice) p1 p2))) @@ -2004,7 +2005,7 @@ (if (seq programs) (wait-for (trash-cards state side programs {:unpreventable true :cause-card card}) - (system-msg state side (str "reveals " + (system-msg state side (s/strcat "reveals " (enumerate-str (map :title programs)) " from the top of the stack," " trashes them, and gains " @@ -2012,11 +2013,11 @@ (wait-for (gain-credits state side (count programs)) (doseq [c others] (move state side c :hand) - (system-msg state side (str "adds " (:title c) " to the grip"))) + (system-msg state side (s/strcat "adds " (:title c) " to the grip"))) (effect-completed state side eid))) (do (doseq [c others] (move state side c :hand) - (system-msg state side (str "adds " (:title c) " to the grip"))) + (system-msg state side (s/strcat "adds " (:title c) " to the grip"))) (effect-completed state side eid))))))}}) (defcard "Injection Attack" @@ -2057,7 +2058,7 @@ :effect (req (wait-for (resolve-ability state :corp (reorder-choice :corp (take 4 (:deck corp))) card targets) (let [top-4 (take 4 (get-in @state [:corp :deck]))] - (system-msg state :runner (str "reveals " + (system-msg state :runner (s/strcat "reveals " (enumerate-str (map :title top-4)) " from the top of R&D (top->bottom)")) (reveal state :runner eid top-4))))}}) @@ -2089,7 +2090,7 @@ {:prompt "Choose a program to install" :msg (msg (if (= target "Done") "shuffle the stack" - (str "install " (:title target) " from the stack"))) + (s/strcat "install " (:title target) " from the stack"))) :choices (req (concat (->> (:deck runner) (filter @@ -2112,7 +2113,7 @@ :effect (effect (continue-ability (charge-ability state side) card nil)) :msg "charge a card"}] choice (fn choice [abis rem] - {:prompt (str "Choose an ability to resolve (" rem " remaining)") + {:prompt (s/strcat "Choose an ability to resolve (" rem " remaining)") :waiting-prompt true :choices (map #(capitalize (:msg %)) abis) :async true @@ -2221,7 +2222,7 @@ :prompt "Choose an install cost from among your installed cards" ;; We don't want to generate 99 prompt buttons, so only add 99 at the end :choices (mapv str (for [x (->> current-values keys last inc (range 1) (#(concat % [99])))] - (str x " [Credit]: " + (s/strcat x " [Credit]: " (quantify (get current-values x 0) "card")))) :effect (effect (complete-with-result eid [(str->int (first (str/split target #" "))) @@ -2231,11 +2232,11 @@ :effect (req (wait-for (resolve-ability state side (select-install-cost state) card nil) (let [revealed (seq (take (second async-result) (:deck corp)))] - (system-msg state :runner (str "uses " (:title card) " to choose an install cost of " + (system-msg state :runner (s/strcat "uses " (:title card) " to choose an install cost of " (first async-result) " [Credit] and reveals " (if revealed - (str (enumerate-str (map :title revealed)) + (s/strcat (enumerate-str (map :title revealed)) " from the top of R&D (top->bottom)") "no cards"))) (wait-for @@ -2281,7 +2282,7 @@ :prompt (msg "Choose a piece of ice in " target " to trash") :choices {:card #(and (ice? %) (= serv (second (get-zone %))))} - :effect (effect (system-msg (str "trashes " (card-str state target))) + :effect (effect (system-msg (s/strcat "trashes " (card-str state target))) (trash :corp eid target {:cause-card card}))}) card nil))}}) @@ -2297,14 +2298,14 @@ top-n-msg (seq (take mill-count (:deck runner)))] (wait-for (mill state :runner :runner mill-count) (system-msg state :runner (if top-n-msg - (str "trashes " (enumerate-str (map :title top-n-msg)) + (s/strcat "trashes " (enumerate-str (map :title top-n-msg)) " from the top of the stack") "trashes no cards from the top of the stack")) (let [heap-count (min 3 (count (get-in @state [:runner :discard])))] (continue-ability state side (if (not (zone-locked? state :runner :discard)) - {:prompt (str "Choose " (quantify heap-count "card") " to shuffle into the stack") + {:prompt (s/strcat "Choose " (quantify heap-count "card") " to shuffle into the stack") :show-discard true :async true :choices {:max heap-count @@ -2314,7 +2315,7 @@ (in-discard? %))} :effect (req (doseq [c targets] (move state side c :deck)) - (system-msg state :runner (str "shuffles " (enumerate-str (map :title targets)) + (system-msg state :runner (s/strcat "shuffles " (enumerate-str (map :title targets)) " from the heap into the stack, and draws 1 card")) (shuffle! state :runner :deck) (draw state :runner eid 1))} @@ -2363,7 +2364,7 @@ (doseq [ice rezzed-ice] (derez state :runner ice {:no-msg true})) (when (seq rezzed-ice) - (system-msg state :runner (str "uses " (:title card) " to derez " (enumerate-str (map :title rezzed-ice)))))))}]}) + (system-msg state :runner (s/strcat "uses " (:title card) " to derez " (enumerate-str (map :title rezzed-ice)))))))}]}) (defcard "Legwork" {:makes-run true @@ -2428,11 +2429,11 @@ :req (req this-card-run) :effect (req (if (:did-steal target) (do (system-msg state :runner - (str "adds Mad Dash to [their] score area as an agenda worth 1 agenda point")) + (s/strcat "adds Mad Dash to [their] score area as an agenda worth 1 agenda point")) (as-agenda state :runner (get-card state card) 1) (effect-completed state side eid)) (do (system-msg state :runner - (str "suffers 1 meat damage from Mad Dash")) + (s/strcat "suffers 1 meat damage from Mad Dash")) (damage state side eid :meat 1 {:card card}))))}]}) (defcard "Making an Entrance" @@ -2449,7 +2450,7 @@ card nil) (wait-for (trash state side target {:unpreventable true :cause-card card}) - (system-msg state side (str "trashes " (:title target))) + (system-msg state side (s/strcat "trashes " (:title target))) (continue-ability state side (when-let [cards (seq (remove-once #(= % target) cards))] @@ -2480,7 +2481,7 @@ :value [blocked-server] :duration :end-of-turn})) (when (:successful target) - (system-msg state :runner (str "gains [Click] and adds Marathon to [their] grip")) + (system-msg state :runner (s/strcat "gains [Click] and adds Marathon to [their] grip")) (gain-clicks state :runner 1) (move state :runner card :hand) (unregister-events state side card)))}]}) @@ -2528,7 +2529,7 @@ (reveal state side targets) (gain-credits state side eid (* 1 (count targets)))))}) (tutor-abi [type] - {:prompt (str "Choose a " (decapitalize type) " resource") + {:prompt (s/strcat "Choose a " (decapitalize type) " resource") :choices (req (cancellable (filter #(has-subtype? % type) (:deck runner)) :sorted)) :msg (msg "add " (:title target) " from the stack to the grip and shuffle the stack") @@ -2545,7 +2546,7 @@ (continue-ability state side {:optional - {:prompt (str "Search the stack for a " (decapitalize choice) " resource?") + {:prompt (s/strcat "Search the stack for a " (decapitalize choice) " resource?") :yes-ability {:async true :msg (msg "search the stack for a " (decapitalize choice) " resource") @@ -2634,7 +2635,7 @@ (can-pay? state side (assoc eid :source card :source-type :runner-install) icebreaker nil [(->c :credit (install-cost state side icebreaker))])) {:optional - {:prompt (str "Install " (:title icebreaker) "?") + {:prompt (s/strcat "Install " (:title icebreaker) "?") :yes-ability {:async true :msg (msg " install " (:title icebreaker)) @@ -2695,7 +2696,7 @@ (installed? %))} :change-in-game-state (req (some resource? (all-active-installed state :runner))) :async true - :effect (req (system-msg state side (str "hosts On the Lam on " (:title target))) + :effect (req (system-msg state side (s/strcat "hosts On the Lam on " (:title target))) (install-as-condition-counter state side eid card target))} :interactions {:prevent [{:type #{:net :brain :meat :tag} :req (req true)}]} @@ -2719,7 +2720,7 @@ ashes-recur (fn ashes-recur [] {:optional {:req (req (not (zone-locked? state :runner :discard))) - :prompt (req (str "Remove Out of the Ashes from the game to make a run? (" + :prompt (req (s/strcat "Remove Out of the Ashes from the game to make a run? (" (count (filter #(= "Out of the Ashes" (:title %)) (:discard runner))) " available)")) :yes-ability @@ -2906,7 +2907,7 @@ (let [ice (:ice context)] (if (pos? (get-strength ice)) {:optional - {:prompt (str "Trash " (quantify (get-strength ice) "installed card") + {:prompt (s/strcat "Trash " (quantify (get-strength ice) "installed card") " to trash " (:title ice) "?") :once :per-run :yes-ability @@ -2915,7 +2916,7 @@ :msg (msg "trash " (card-str state ice)) :effect (effect (trash eid ice {:cause-card card}))}}} {:optional - {:prompt (str "Trash " (:title ice) "?") + {:prompt (s/strcat "Trash " (:title ice) "?") :once :per-run :yes-ability {:async true @@ -3019,14 +3020,14 @@ :effect (req (let [correct-guess ((if (= target "Even") even? odd?) spent)] (wait-for (lose-credits state :runner (make-eid state eid) spent) - (system-msg state :runner (str "spends " spent " [Credit]")) - (system-msg state :corp (str (if correct-guess " " " in") + (system-msg state :runner (s/strcat "spends " spent " [Credit]")) + (system-msg state :corp (s/strcat (if correct-guess " " " in") "correctly guesses " (decapitalize target))) (wait-for (trigger-event-simult state side :reveal-spent-credits nil nil spent) (if correct-guess (effect-completed state side eid) - (do (system-msg state :runner (str "gains " (* 2 spent) " [Credits]")) + (do (system-msg state :runner (s/strcat "gains " (* 2 spent) " [Credits]")) (gain-credits state :runner eid (* 2 spent))))))))}) (runner-choice [choices] {:player :runner @@ -3116,7 +3117,7 @@ (continue-ability state side {:msg (msg (if (pos? cards-to-draw) - (str "draw " (quantify cards-to-draw "card") " and gain 3 [Credits]") + (s/strcat "draw " (quantify cards-to-draw "card") " and gain 3 [Credits]") "gain 3 [Credits]")) :async true :effect (req (if (pos? cards-to-draw) @@ -3168,7 +3169,7 @@ (install-cards state side eid card (rest to-install) titles)) (do (move state side (find-latest state card) :rfg) - (system-msg state :runner (str "uses " (:title card) " to install " (enumerate-str titles) " facedown")) + (system-msg state :runner (s/strcat "uses " (:title card) " to install " (enumerate-str titles) " facedown")) (effect-completed state side eid))))] {:makes-run true :on-play {:async true @@ -3239,7 +3240,7 @@ :async true :msg (msg "make a run on " target) :effect (effect (make-run eid target card))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to make a run")))}}})] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to make a run")))}}})] {:makes-run true :on-play {:async true @@ -3307,8 +3308,8 @@ :async true :effect (req (wait-for (lose-credits state :runner (make-eid state eid) spent) - (system-msg state :runner (str "spends " spent " [Credit]")) - (system-msg state :corp (str " guesses " target " [Credit]")) + (system-msg state :runner (s/strcat "spends " spent " [Credit]")) + (system-msg state :corp (s/strcat " guesses " target " [Credit]")) (wait-for (trigger-event-simult state side :reveal-spent-credits nil nil spent) (if (not= spent (str->int target)) (continue-ability state :runner (choose-ice) card nil) @@ -3346,7 +3347,7 @@ (continue-ability state side {:optional - {:prompt (str "Charge " (:title rig-target) "?") + {:prompt (s/strcat "Charge " (:title rig-target) "?") :req (req (can-charge state side rig-target)) :yes-ability {:async true @@ -3373,7 +3374,7 @@ state side {:async true :show-discard true - :prompt (str "Choose " (quantify cards-to-move "card") + :prompt (s/strcat "Choose " (quantify cards-to-move "card") " to add from the heap to the grip") :msg (msg "add " (enumerate-str (map :title targets)) " from the heap to the grip") @@ -3615,7 +3616,7 @@ (continue-ability state side {:optional - {:prompt (str "Install " (:title revealed-card) " paying 10 [Credits] less?") + {:prompt (s/strcat "Install " (:title revealed-card) " paying 10 [Credits] less?") :waiting-prompt true :yes-ability {:msg (msg "reveal " rev-str " from the top of the stack") @@ -3646,7 +3647,7 @@ rest-of-deck (rest remainder) rev-str (if (= "" rev-str) (:title revealed-card) - (str rev-str ", " (:title revealed-card)))] + (s/strcat rev-str ", " (:title revealed-card)))] (if (program? revealed-card) (install-program state side eid card revealed-card rev-str) (spark-search-fn state side eid card rest-of-deck rev-str))) @@ -3755,7 +3756,7 @@ :async true :effect (effect (draw :runner eid 2))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}} + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}} card nil))}}) (defcard "Stimhack" @@ -3789,7 +3790,7 @@ :async true :effect (effect (gain-credits :runner eid 2))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}} + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}} card nil))}}) (defcard "Sure Gamble" @@ -3940,7 +3941,7 @@ (wait-for (mill state :runner (make-eid state eid) :runner 4) (let [trashed-cards async-result] (system-msg state side - (str "uses " (:title card) " to trash " + (s/strcat "uses " (:title card) " to trash " (enumerate-str (map :title trashed-cards)) " from the top of the stack")) (continue-ability @@ -3954,7 +3955,7 @@ (can-pay? state side (assoc eid :source card :source-type :runner-install) % nil [(->c :credit (install-cost state side % {:cost-bonus -3}))]) (in-discard? (get-card state %))) trashed-cards))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid)) :effect (req (let [card-to-install (first (seq (filter #(and (= (:title target) (:title %)) (in-discard? (get-card state %))) trashed-cards)))] (runner-install state side (assoc eid :source card :source-type :runner-install) card-to-install {:cost-bonus -3 @@ -4012,7 +4013,7 @@ {:on-play {:additional-cost [(->c :hardware 1)] :msg (msg (let [{:keys [title cost]} (trashed-hw state)] - (str "trash " title " and gain " (quot cost 2) " [Credits]"))) + (s/strcat "trash " title " and gain " (quot cost 2) " [Credits]"))) :async true :effect (req (let [{:keys [cost]} (trashed-hw state)] (wait-for (gain-credits state :runner (quot cost 2)) @@ -4158,7 +4159,7 @@ [{:event :pre-access-card :duration :end-of-game :req (req (same-card? :title burned-card target)) - :msg (msg (str "remove " (:title burned-card) " from the game")) + :msg (msg (s/strcat "remove " (:title burned-card) " from the game")) :effect (effect (move :corp target :rfg))}])] {:makes-run true :on-play {:prompt "Choose a server" @@ -4180,9 +4181,9 @@ {:effect (req (doseq [c choices] (move state :corp c :deck)) (shuffle! state :corp :deck)) - :msg (str "shuffle " (enumerate-str (map :title choices)) " into R&D")}))) + :msg (s/strcat "shuffle " (enumerate-str (map :title choices)) " into R&D")}))) (choose-cards [choices chosen] - {:prompt (str "Choose a card in HQ to shuffle into R&D (" (- 2 (count chosen)) " remaining)") + {:prompt (s/strcat "Choose a card in HQ to shuffle into R&D (" (- 2 (count chosen)) " remaining)") :player :runner :choices (concat choices ["Done"]) :not-distinct true @@ -4226,9 +4227,9 @@ (wait-for (trash state side topcard {:cause-card card}) (wait-for (gain-credits state side (if (event? topcard) 0 cost)) (system-msg state side - (str "shuffles the stack and trashes " (:title topcard) + (s/strcat "shuffles the stack and trashes " (:title topcard) (when-not (event? topcard) - (str " to gain " cost " [Credits]")))) + (s/strcat " to gain " cost " [Credits]")))) (effect-completed state side eid)))))}}) (defcard "Window of Opportunity" @@ -4280,11 +4281,11 @@ :waiting-prompt true :req (req (and (installed? (get-card state chosen-ice)) (not (rezzed? (get-card state chosen-ice))))) - :prompt (str "Rez " (card-str state chosen-ice) ", ignoring all costs?") + :prompt (s/strcat "Rez " (card-str state chosen-ice) ", ignoring all costs?") :yes-ability {:async true :effect (req - (system-msg state :corp (str "rezzes " (card-str state chosen-ice) ", ignoring all costs")) + (system-msg state :corp (s/strcat "rezzes " (card-str state chosen-ice) ", ignoring all costs")) (rez state :corp eid chosen-ice {:ignore-cost :all-costs}))}}}]) (derez state side target {:source-card card}) (effect-completed state side eid)))} diff --git a/src/clj/game/cards/hardware.clj b/src/clj/game/cards/hardware.clj index 39232fcbc5..38556d0fce 100644 --- a/src/clj/game/cards/hardware.clj +++ b/src/clj/game/cards/hardware.clj @@ -64,7 +64,8 @@ [jinteki.utils :refer :all] [game.core.set-aside :refer [set-aside get-set-aside]] [game.core.sabotage :refer [sabotage-ability]] - [game.core.mark :refer [identify-mark-ability mark-changed-event]])) + [game.core.mark :refer [identify-mark-ability mark-changed-event]] + [stringer.core :as s])) ;; Card definitions @@ -78,7 +79,7 @@ {:async true :effect (req (let [counters (:total-purged-counters context)] (wait-for (trash state side card {:cause-card card}) - (system-msg state side (str "trashes Acacia and gains " counters " [Credit]")) + (system-msg state side (s/strcat "trashes Acacia and gains " counters " [Credit]")) (gain-credits state side eid counters))))}}}]}) (defcard "Adjusted Matrix" @@ -110,10 +111,10 @@ (continue-ability state side {:optional {:prompt (msg "Prevent a \"when encountered\" ability on " (:title current-ice) (when (:ability-name target) - (str " (" (:ability-name target) ")"))) + (s/strcat " (" (:ability-name target) ")"))) :yes-ability {:cost [(->c :power 1)] :msg (msg "prevent the encounter ability on " (:title current-ice) (when (:ability-name target) - (str " (" (:ability-name target) ")"))) + (s/strcat " (" (:ability-name target) ")"))) :effect (req (swap! state assoc-in [:run :prevent-encounter-ability] true))}}} card targets)))}] :abilities [{:cost [(->c :power 1)] @@ -417,7 +418,7 @@ :effect (req (if (= "No action" target) (effect-completed state side eid) (do (system-msg state side - (str "uses " (:title card) " to add " target + (s/strcat "uses " (:title card) " to add " target " to the bottom of the stack")) (move state side (find-card target (:discard (:runner @state))) :deck) (effect-completed state side eid))))}] @@ -451,7 +452,7 @@ (let [trashed-cards async-result] (wait-for (draw state side (count (filter overlap trashed-card-names))) (system-msg state side - (str "uses " (:title card) " to trash " + (s/strcat "uses " (:title card) " to trash " (enumerate-str (map :title trashed-cards)) " from the grip and draw " (quantify (count async-result) "card"))) @@ -568,7 +569,7 @@ :events [{:event :play-event :req (req (first-event? state side :play-event)) :effect (req (system-msg state :runner - (str "can play another event without spending a [Click] by clicking on Comet")) + (s/strcat "can play another event without spending a [Click] by clicking on Comet")) (update! state side (assoc card :comet-event true)))}] :abilities [{:async true :label "Play an event in the grip twice" @@ -848,7 +849,7 @@ :req (req (:flame-out-trigger (:special (get-card state card)))) :effect (req (update! state side (assoc-in (get-card state card) [:special :flame-out-trigger] nil)) (if-let [hosted (first (:hosted card))] - (do (system-msg state :runner (str "trashes " (:title hosted) " from Flame-out")) + (do (system-msg state :runner (s/strcat "trashes " (:title hosted) " from Flame-out")) (trash state side eid hosted {:cause-card card})) (effect-completed state side eid)))}] {:implementation "Credit usage restriction not enforced" @@ -870,7 +871,7 @@ :async true :effect (req (let [credits (get-counters card :credit)] (update! state :runner (dissoc-in card [:counter :credit])) - (system-msg state :runner (str "takes " credits " hosted [Credits] from Flame-out")) + (system-msg state :runner (s/strcat "takes " credits " hosted [Credits] from Flame-out")) (register-flame-effect state card) (gain-credits state :runner eid credits)))}] :events [(assoc maybe-turn-end :event :runner-turn-ends) @@ -944,13 +945,13 @@ :autoresolve (get-autoresolve :auto-fire) :yes-ability {:effect (effect (system-msg :runner - (str "uses " (:title card) " to place 1 virus counter on itself")) + (s/strcat "uses " (:title card) " to place 1 virus counter on itself")) (add-counter :runner card :virus 1))}}} mult-ab {:prompt (msg "Place virus counters on " (:title card) "?") :choices {:number (req amt-trashed) :default (req amt-trashed)} :effect (effect (system-msg :runner - (str "uses " (:title card) " to place " + (s/strcat "uses " (:title card) " to place " (quantify target "virus counter") " on itself")) (add-counter :runner card :virus target))} @@ -975,15 +976,15 @@ finished? (or (= 3 (count to-shuffle)) (empty? set-aside-cards))] {:prompt (msg (if finished? - (str "Removing: " (if (not-empty set-aside-cards) + (s/strcat "Removing: " (if (not-empty set-aside-cards) (enumerate-str (map :title set-aside-cards)) "nothing") "[br]Shuffling: " (if (not-empty to-shuffle) (enumerate-str (map :title to-shuffle)) "nothing")) - (str "Choose " (- 3 (count to-shuffle)) " more cards to shuffle back." + (s/strcat "Choose " (- 3 (count to-shuffle)) " more cards to shuffle back." (when (not-empty to-shuffle) - (str "[br]Currently shuffling back: " (enumerate-str (map :title to-shuffle))))))) + (s/strcat "[br]Currently shuffling back: " (enumerate-str (map :title to-shuffle))))))) :async true :not-distinct true ; show cards separately :choices (req (if finished? @@ -1006,13 +1007,13 @@ :waiting-prompt true :effect (req (set-aside state side eid (take 6 (:deck runner))) (let [set-aside-cards (sort-by :title (get-set-aside state side eid))] - (system-msg state side (str (:latest-payment-str eid) "to use " (get-title card) + (system-msg state side (s/strcat (:latest-payment-str eid) "to use " (get-title card) " to set aside " (enumerate-str (map get-title set-aside-cards)) " from the top of the stack")) (wait-for (resolve-ability state side {:async true - :prompt (str "The set aside cards are: " + :prompt (s/strcat "The set aside cards are: " (enumerate-str (map get-title set-aside-cards))) :choices ["OK"]} card nil) @@ -1275,7 +1276,7 @@ :yes-ability {:msg "draw 1 card" :async true :effect (req (draw state :runner eid 1))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :static-abilities [(mu+ 2)] :abilities [(set-autoresolve :auto-fire "LilyPAD")]}) @@ -1334,7 +1335,7 @@ :effect (req (let [target (some #(when (pred %) (:card %)) targets) cost (trash-cost state side target)] (when cost - (system-msg state side (str "uses " (:title card) " to place " + (system-msg state side (s/strcat "uses " (:title card) " to place " (quantify cost "power counter") " on itself")) (add-counter state side card :power cost))))}]})) @@ -1577,7 +1578,7 @@ :async true :effect (req (if (pos? (:credit corp)) (wait-for (lose-credits state :corp 1) - (system-msg state side (str "uses " (:title card) " to gain 1 [Credits]")) + (system-msg state side (s/strcat "uses " (:title card) " to gain 1 [Credits]")) (gain-credits state :runner eid 1)) (effect-completed state side eid)))}]}) @@ -1596,7 +1597,7 @@ (assoc eid :source card :source-type :runner-install) target {:msg-keys {:install-source card :display-origin true}})) - :cancel-effect (effect (system-msg :runner (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg :runner (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid))} gain-credit-ability {:interactive (req true) @@ -1636,7 +1637,7 @@ :no-ability {:effect (effect (system-msg "does not add the top card of the the stack to the bottom"))}}} card nil)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :abilities [(set-autoresolve :auto-fire "Paragon")]}) (defcard "Patchwork" @@ -1653,13 +1654,13 @@ ;; Check if Patchwork can trigger (can-trigger? state side eid patchwork-ability card targets))) :custom-amount 2 - :custom (req (let [cost-type (str (when (= :play (:source-type eid)) "play") + :custom (req (let [cost-type (s/strcat (when (= :play (:source-type eid)) "play") (when (= :runner-install (:source-type eid)) "install")) patchwork card targetcard target] (continue-ability state side - {:prompt (str "Trash a card to lower the " cost-type + {:prompt (s/strcat "Trash a card to lower the " cost-type " cost of " (:title targetcard) " by 2 [Credits]") :async true :choices {:card #(and (in-hand? %) @@ -1716,7 +1717,7 @@ :async true :effect (req (wait-for (draw state :runner 1) (draw state :corp eid 1)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] {:static-abilities [(mu+ 1) (link+ 1)] :events [{:event :pass-ice @@ -1890,7 +1891,7 @@ :events [{:event :jack-out :async true :effect (req (let [card (first (shuffle (:hand corp)))] - (system-msg state :runner (str "force the Corp to reveal " (:title card) " from HQ")) + (system-msg state :runner (s/strcat "force the Corp to reveal " (:title card) " from HQ")) (reveal state :corp eid card)))}]}) (defcard "Replicator" @@ -1916,7 +1917,7 @@ :effect (req (wait-for (draw state :runner 1) (add-counter state side (get-card state card) :power 1) (if (= 3 (get-counters (get-card state card) :power)) - (do (system-msg state :runner (str "trashes " (:title card) " as it reached 3 power counters")) + (do (system-msg state :runner (s/strcat "trashes " (:title card) " as it reached 3 power counters")) (trash state side eid card {:unpreventable true :cause-card card})) (effect-completed state side eid))))} @@ -2156,13 +2157,13 @@ "Done"]) :effect (req (if (= target "Draw 1 card") (do (add-counter state side card :power -1) - (system-msg state side (str "uses " (:title card) + (system-msg state side (s/strcat "uses " (:title card) " to draw 1 card")) (draw state :runner eid 1)) (if (= target "Remove 1 tag") (do (add-counter state side card :power -1) - (system-msg state side (str "uses " (:title card) + (system-msg state side (s/strcat "uses " (:title card) " to remove 1 tag")) (lose-tags state :runner eid 1)) (effect-completed state :runner eid))))} @@ -2215,7 +2216,7 @@ :msg "look at the top card of R&D" :cost [(->c :trash-can)] :effect (effect (continue-ability - {:prompt (req (->> corp :deck first :title (str "The top card of R&D is "))) + {:prompt (req (->> corp :deck first :title (s/strcat "The top card of R&D is "))) :choices ["OK"]} card nil))}]}) @@ -2234,7 +2235,7 @@ :yes-ability {:msg "gain 2 [Credits]" :async true :effect (effect (gain-credits eid 2))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :abilities [(set-autoresolve :auto-fire "Supercorridor")]}) (defcard "Swift" @@ -2286,15 +2287,15 @@ (continue-ability state side {:prompt "Choose one" - :choices [(str "Install " (:title first-card)) - (when second-card (str "Install " (:title second-card))) + :choices [(s/strcat "Install " (:title first-card)) + (when second-card (s/strcat "Install " (:title second-card))) "No install"] :msg (msg "reveal " rev-str " from the top of the stack") :effect (req (if-not (= target "No install") (wait-for (runner-install state side (make-eid state {:source card :source-type :runner-install}) - (if (= target (str "Install " (:title first-card))) + (if (= target (s/strcat "Install " (:title first-card))) first-card second-card) {:ignore-all-cost true :msg-keys {:display-origin true @@ -2312,7 +2313,7 @@ rest-of-deck (rest remainder) rev-str (if (= "" rev-str) (:title revealed-card) - (str rev-str ", " (:title revealed-card)))] + (s/strcat rev-str ", " (:title revealed-card)))] (if (is-type? revealed-card type) (if-not first-card (wiz-search-fn state side eid card rest-of-deck type rev-str revealed-card) @@ -2348,7 +2349,7 @@ (continue-ability state side (sabotage-ability 3) card nil)) - (do (system-msg state side (str "uses " (:title card) " to place 1 power counter on itself")) + (do (system-msg state side (s/strcat "uses " (:title card) " to place 1 power counter on itself")) (add-counter state side card :power 1) (effect-completed state side eid))))}]}) @@ -2405,7 +2406,7 @@ {:optional {:prompt (msg "Swap " (:title stolen) " for an agenda in the Corp's score area?") :yes-ability - {:prompt (str "Choose a scored Corp agenda to swap with " (:title stolen)) + {:prompt (s/strcat "Choose a scored Corp agenda to swap with " (:title stolen)) :choices {:card #(in-corp-scored? state side %)} :msg (msg "swap " (:title stolen) " for " (:title target)) :effect (effect (swap-agendas target stolen))}}}) @@ -2473,12 +2474,12 @@ :async true :effect (req (if (= :hq (first (:server target))) (do - (system-msg state side (str "uses " (:title card) " to access 1 additional card from HQ this run")) + (system-msg state side (s/strcat "uses " (:title card) " to access 1 additional card from HQ this run")) (register-events state side card [(breach-access-bonus :hq 1 {:duration :end-of-run})]) (effect-completed state side eid)) - (do (system-msg state side (str "will use " (:title card) " to breach HQ when this run ends")) + (do (system-msg state side (s/strcat "will use " (:title card) " to breach HQ when this run ends")) (register-events state side card diff --git a/src/clj/game/cards/ice.clj b/src/clj/game/cards/ice.clj index 3a9d52f43c..35e50e9150 100644 --- a/src/clj/game/cards/ice.clj +++ b/src/clj/game/cards/ice.clj @@ -65,7 +65,8 @@ [game.core.update :refer [update!]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) ;;;; Helper functions specific for ice (defn reset-variable-subs @@ -166,7 +167,7 @@ "Ability to (maybe) draw a set number of cards" [qty] {:async true - :label (str "You may draw " (quantify qty "card")) + :label (s/strcat "You may draw " (quantify qty "card")) :effect (effect (maybe-draw eid card qty))}) (defn draw-up-to-sub @@ -174,7 +175,7 @@ ([qty] (draw-up-to-sub qty nil)) ([qty args] {:async true - :label (str "Draw up to " (quantify qty "card")) + :label (s/strcat "Draw up to " (quantify qty "card")) :effect (effect (draw-up-to eid card qty args))})) (defn runner-pays @@ -184,7 +185,7 @@ :effect (req (wait-for (pay state :runner (make-eid state eid) card cost) (when-let [payment-str (:msg async-result)] (system-msg state :runner - (str payment-str + (s/strcat payment-str " due to " (:title card) " subroutine"))) (effect-completed state side eid)))}) @@ -194,7 +195,7 @@ ([cost reason] {:player :runner :async true - :label (str "End the run unless the Runner pays " (build-cost-label cost)) + :label (s/strcat "End the run unless the Runner pays " (build-cost-label cost)) :prompt "Choose one" :waiting-prompt true :choices (req ["End the run" @@ -202,13 +203,13 @@ (capitalize (cost->string cost)))]) :msg (msg (if (= "End the run" target) (decapitalize target) - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :effect (req (if (= "End the run" target) (end-run state :corp eid card) (wait-for (pay state :runner (make-eid state eid) card cost) (when-let [payment-str (:msg async-result)] (system-msg state :runner - (str payment-str + (s/strcat payment-str " due to " (:title card) " " reason))) (effect-completed state side eid))))})) @@ -216,7 +217,7 @@ (defn end-the-run-unless-corp-pays [cost] {:async true - :label (str "End the run unless the Corp pays " (build-cost-label cost)) + :label (s/strcat "End the run unless the Corp pays " (build-cost-label cost)) :prompt "Choose one" :waiting-prompt true :choices (req ["End the run" @@ -234,22 +235,22 @@ [label prompt ability] {:player :runner :async true - :label (str "End the run unless the Runner " label) + :label (s/strcat "End the run unless the Runner " label) :prompt "Choose one" :waiting-prompt true :choices ["End the run" (capitalize prompt)] :effect (req (if (= "End the run" target) (do (system-msg state :corp - (str "uses " (:title card) " to end the run")) + (s/strcat "uses " (:title card) " to end the run")) (end-run state :corp eid card)) (continue-ability state side ability card nil)))}) (defn give-tags "Basic give runner n tags subroutine." [n] - {:label (str "Give the Runner " (quantify n "tag")) - :msg (str "give the Runner " (quantify n "tag")) + {:label (s/strcat "Give the Runner " (quantify n "tag")) + :msg (s/strcat "give the Runner " (quantify n "tag")) :async true :effect (effect (gain-tags :corp eid n))}) @@ -264,13 +265,13 @@ "Run a trace with specified base strength. If successful trigger specified ability" ([base {:keys [label] :as ability}] - {:label (str "Trace " base " - " label) + {:label (s/strcat "Trace " base " - " label) :trace {:base base :label label :successful ability}}) ([base ability un-ability] - (let [label (str (:label ability) " / " (:label un-ability))] - {:label (str "Trace " base " - " label) + (let [label (s/strcat (:label ability) " / " (:label un-ability))] + {:label (s/strcat "Trace " base " - " label) :trace {:base base :label label :successful ability @@ -284,15 +285,15 @@ (defn gain-credits-sub "Gain specified amount of credits" [credits] - {:label (str "Gain " credits " [Credits]") - :msg (str "gain " credits " [Credits]") + {:label (s/strcat "Gain " credits " [Credits]") + :msg (s/strcat "gain " credits " [Credits]") :async true :effect (effect (gain-credits eid credits))}) (defn corps-gains-and-runner-loses-credits [gain loss] - {:label (str "Gain " gain " [Credits], Runner loses " loss " [Credits]") - :msg (str "gain " gain " [Credits] and force the Runner to lose " loss " [Credits]") + {:label (s/strcat "Gain " gain " [Credits], Runner loses " loss " [Credits]") + :msg (s/strcat "gain " gain " [Credits] and force the Runner to lose " loss " [Credits]") :async true :effect (req (wait-for (gain-credits state :corp gain) (lose-credits state :runner eid loss)))}) @@ -308,12 +309,12 @@ (defn do-psi "Start a psi game, if not equal do ability" ([{:keys [label] :as ability}] - {:label (str "Psi Game - " label) - :msg (str "start a psi game (" label ")") + {:label (s/strcat "Psi Game - " label) + :msg (s/strcat "start a psi game (" label ")") :psi {:not-equal ability}}) ([{:keys [label-neq] :as neq-ability} {:keys [label-eq] :as eq-ability}] - {:label (str "Psi Game - " label-neq " / " label-eq) - :msg (str "start a psi game (" label-neq " / " label-eq ")") + {:label (s/strcat "Psi Game - " label-neq " / " label-eq) + :msg (s/strcat "start a psi game (" label-neq " / " label-eq ")") :psi {:not-equal neq-ability :equal eq-ability}})) @@ -326,8 +327,8 @@ (defn runner-loses-credits "Runner loses credits effect" [credits] - {:label (str "Make the Runner lose " credits " [Credits]") - :msg (str "force the Runner to lose " credits " [Credits]") + {:label (s/strcat "Make the Runner lose " credits " [Credits]") + :msg (s/strcat "force the Runner to lose " credits " [Credits]") :async true :effect (effect (lose-credits :runner eid credits))}) @@ -341,7 +342,7 @@ (runner? %))} :msg "add 1 installed card to the grip" :effect (effect (move :runner target :hand true) - (system-msg (str "adds " (:title target) + (system-msg (s/strcat "adds " (:title target) " to the grip")))}) (def trash-program-sub @@ -465,7 +466,7 @@ :async true :effect (effect (reveal eid targets)) :msg (let [sub-label #(:label (first (:subroutines (card-def %))))] - (msg "reveal " (enumerate-str (map #(str (:title %) " (" (sub-label %) ")") targets))))}) + (msg "reveal " (enumerate-str (map #(s/strcat (:title %) " (" (sub-label %) ")") targets))))}) (def resolve-grail "Ability for resolving a subroutine on a Grail ice in HQ." @@ -608,7 +609,7 @@ (def take-bad-pub ; Bad pub on rez effect {:async true - :effect (effect (system-msg (str "takes 1 bad publicity from " (:title card))) + :effect (effect (system-msg (s/strcat "takes 1 bad publicity from " (:title card))) (gain-bad-publicity :corp eid 1))}) ;; Card definitions @@ -648,7 +649,7 @@ :cost [(->c :trash-from-hand 1)] :async true :effect (effect (damage eid :net 2 {:card card}))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}} :subroutines [(do-net-damage 1)]}) (defcard "Ansel 1.0" @@ -698,7 +699,7 @@ :label "Trash the top 3 cards of the stack" :effect (req (system-msg state :corp - (str "uses " (:title card) " to trash " + (s/strcat "uses " (:title card) " to trash " (enumerate-str (map :title (take 3 (:deck runner)))) " from the top of the stack and trash itself")) (wait-for @@ -778,7 +779,7 @@ :async true :msg "force the Runner to encounter it" :effect (req (force-ice-encounter state side eid card))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}} :subroutines [(trace-ability 6 add-runner-card-to-grip)]}) (defcard "Archer" @@ -850,7 +851,7 @@ (pay state :runner eid card (->c :credit 2)))) :msg (msg (if (= "Take 1 net damage" target) "do 1 net damage" - (str "force the runner to " (decapitalize target))))} + (s/strcat "force the runner to " (decapitalize target))))} card nil)))}] {:events [{:event :pre-resolve-subroutine :req (req (threat-level 3 state)) @@ -886,7 +887,7 @@ (bailiff-gain-credits state side eid (dec n))) (effect-completed state side eid)))] {:on-break-subs {:msg (msg (let [n-subs (count (:broken-subs context))] - (str "gain " n-subs " [Credits] from the runner breaking subs"))) + (s/strcat "gain " n-subs " [Credits] from the runner breaking subs"))) :async true :effect (effect (bailiff-gain-credits eid (count (:broken-subs context))))} :subroutines [end-the-run]})) @@ -987,7 +988,7 @@ :effect (req (let [this (zone->name (second (get-zone card))) nice target] (continue-ability state side - {:prompt (str "Choose a location to install " (:title target)) + {:prompt (s/strcat "Choose a location to install " (:title target)) :choices (req (remove #(= this %) (installable-servers state nice))) :async true :effect (effect (corp-install eid nice target {:ignore-all-cost true @@ -1077,7 +1078,7 @@ :display-origin true} :index (:index card)}) (effect-completed state side eid))) - :cancel-effect (effect (system-msg :corp (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg :corp (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid))} end-the-run end-the-run] @@ -1378,12 +1379,12 @@ :effect (req (let [c (- target (second targets)) from (take c (:deck runner))] (system-msg state :corp - (str "looks at the top " (quantify c "card") " of the stack")) + (s/strcat "looks at the top " (quantify c "card") " of the stack")) (if (< 1 c) (continue-ability state side (dh-trash from) card nil) (wait-for (trash state side (first from) {:unpreventable true :cause :subroutine}) - (system-msg state :corp (str "trashes " (:title (first from)))) + (system-msg state :corp (s/strcat "trashes " (:title (first from)))) (effect-completed state side eid)))))})]})) (defcard "Data Loop" @@ -1393,7 +1394,7 @@ (continue-ability :runner (let [n (min 2 (count (:hand runner)))] - {:prompt (str "Choose " (quantify n "card") " in the grip to add to the top of the stack (second card targeted will be topmost)") + {:prompt (s/strcat "Choose " (quantify n "card") " in the grip to add to the top of the stack (second card targeted will be topmost)") :choices {:max n :all true :card #(and (in-hand? %) @@ -1416,7 +1417,7 @@ {:abilities [(power-counter-ability (give-tags 1))] :on-encounter {:msg (msg (if (= target "End the run") (decapitalize target) - (str "force the runner to " (decapitalize target) " on encountering it"))) + (s/strcat "force the runner to " (decapitalize target) " on encountering it"))) :player :runner :prompt "Choose one" :waiting-prompt true @@ -1466,7 +1467,7 @@ (cond (nil? trashed-card) (effect-completed state side eid) (odd? (:cost trashed-card)) - (do (system-msg state :corp (str "uses " (:title card) " to end the run")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to end the run")) (end-run state :corp eid card)) :else (effect-completed state side eid)))))}]}) @@ -1540,7 +1541,7 @@ (break-fn (rest unbroken-subs) (inc total)) card nil)) (let [msgs (when (pos? total) - (str "resolves " (quantify total "unbroken subroutine") + (s/strcat "resolves " (quantify total "unbroken subroutine") " on Endless EULA" " (\"[subroutine] " (:label sub) "\")"))] @@ -1774,20 +1775,20 @@ :effect (req (wait-for (trash state side target {:cause :subroutine}) (system-msg state :corp - (str "uses " (:title card) " to trash " (:title target))) + (s/strcat "uses " (:title card) " to trash " (:title target))) (wait-for (damage state side :meat 2 {:unpreventable true :card card}) (system-msg state :corp - (str "uses " (:title card) " to deal 2 meat damage")) + (s/strcat "uses " (:title card) " to deal 2 meat damage")) (system-msg state :corp - (str "uses " (:title card) " to end the run")) + (s/strcat "uses " (:title card) " to end the run")) (end-run state side eid card)))) :cancel-effect (req (wait-for (damage state side :meat 2 {:unpreventable true :card card}) (system-msg state :corp - (str "uses " (:title card) " to deal 2 meat damage")) + (s/strcat "uses " (:title card) " to deal 2 meat damage")) (system-msg state :corp - (str "uses " (:title card) " to end the run")) + (s/strcat "uses " (:title card) " to end the run")) (end-run state side eid card)))} card nil))})]}) @@ -1825,7 +1826,7 @@ (defcard "Funhouse" {:on-encounter {:msg (msg (if (= target "Take 1 tag") - (str "force the runner to " (decapitalize target) " on encountering it") + (s/strcat "force the runner to " (decapitalize target) " on encountering it") (decapitalize target))) :player :runner :prompt "Choose one" @@ -1846,7 +1847,7 @@ (when (can-pay? state :runner eid card nil [(->c :credit 4)]) "Pay 4 [Credits]")]) :msg (msg (if (= target "Pay 4 [Credits]") - (str "force the runner to " (decapitalize target)) + (s/strcat "force the runner to " (decapitalize target)) "give the runner 1 tag")) :effect (req (if (= "Take 1 tag" target) (gain-tags state :corp eid 1) @@ -1882,13 +1883,13 @@ (filter in-hand?) (map :title) not-empty)] - (str (enumerate-str h) + (s/strcat (enumerate-str h) " from HQ")) (when-let [d (->> targets (filter in-discard?) (map :title) not-empty)] - (str (enumerate-str d) + (s/strcat (enumerate-str d) " from Archives"))])) " and shuffle them into R&D")} draw-reveal-shuffle {:async true @@ -1912,7 +1913,7 @@ {:implementation "Auto breaking will break even with too few credits" :on-break-subs {:req (req (some :printed (:broken-subs context))) :msg (msg (let [n-subs (count (filter :printed (:broken-subs context)))] - (str "force the runner to lose " + (s/strcat "force the runner to lose " n-subs " [Credits] for breaking printed subs"))) :async true @@ -1987,7 +1988,7 @@ (register-lingering-effect state side card (prevent-sub-break-by t)) (effect-completed state side eid)))} card nil))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}}})) + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}}})) (defcard "Hákarl 1.0" {:runner-abilities [(bioroid-break 1 1)] @@ -2000,10 +2001,10 @@ :req (req (and (installed? target) (rezzed? target)))} :waiting-prompt true - :cancel-effect (effect (system-msg :corp (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (effect (derez target {:source-card card}) - (system-msg (str "prevents the runner from using printed abilities on bioroid ice for the rest of the turn")) + (system-msg (s/strcat "prevents the runner from using printed abilities on bioroid ice for the rest of the turn")) (register-lingering-effect card {:type :prevent-paid-ability @@ -2088,14 +2089,14 @@ from-archives (map :title (filter in-discard? targets))] (system-msg state side - (str "uses " (:title card) " to reveal " + (s/strcat "uses " (:title card) " to reveal " (enumerate-str (filter identity [(when (not-empty from-hq) - (str (enumerate-str from-hq) + (s/strcat (enumerate-str from-hq) " from HQ")) (when (not-empty from-archives) - (str (enumerate-str from-archives) + (s/strcat (enumerate-str from-archives) " from Archives"))])) ", shuffle them into R&D"))) (effect-completed state side eid)))} @@ -2126,7 +2127,7 @@ :effect (req (wait-for (trash-cards state :runner targets) (system-msg state :runner - (str "trashes " (enumerate-str (map :title targets)))) + (s/strcat "trashes " (enumerate-str (map :title targets)))) (effect-completed state side eid)))})) card nil)))}] {:subroutines [sub @@ -2218,13 +2219,13 @@ :choices (req (cancellable (:deck corp) :sorted)) :msg "add 1 card to HQ from R&D" :cancel-effect (req (shuffle! state side :deck) - (system-msg state side (str "shuffles R&D")) + (system-msg state side (s/strcat "shuffles R&D")) (effect-completed state side eid)) :effect (req (move state side target :hand) (if (< n 2) (continue-ability state side (hort (inc n)) card nil) (do (shuffle! state side :deck) - (system-msg state side (str "shuffles R&D")) + (system-msg state side (s/strcat "shuffles R&D")) (effect-completed state side eid))))})] (let [breakable-fn (req (when (or (> 3 (get-counters card :advancement)) (not (has-subtype? target "AI")) @@ -2244,10 +2245,10 @@ (wait-for (resolve-ability state side (hort 1) card nil) (do (system-msg state side - (str "uses " (:title card) " to add 2 cards to HQ from R&D, " + (s/strcat "uses " (:title card) " to add 2 cards to HQ from R&D, " "shuffle R&D, and end the run")) (end-run state side eid card))) - (do (system-msg state side (str "uses " (:title card) " to end the run")) + (do (system-msg state side (s/strcat "uses " (:title card) " to end the run")) (end-run state side eid card))))}]}))) (defcard "Hourglass" @@ -2299,7 +2300,7 @@ (defcard "Hydra" (letfn [(otherwise-tag [message ability] {:msg (msg (if tagged message "give the Runner 1 tag")) - :label (str (capitalize message) " if the Runner is tagged; otherwise, give the Runner 1 tag") + :label (s/strcat (capitalize message) " if the Runner is tagged; otherwise, give the Runner 1 tag") :async true :effect (req (if tagged (ability state :runner eid card nil) @@ -2406,7 +2407,7 @@ {:subroutines [end-the-run] :static-abilities [(ice-strength-bonus (req (count (:hand corp))))] :rez-cost-bonus (req (count (:hand corp))) - :leave-play (req (remove-watch state (keyword (str "iq" (:cid card)))))}) + :leave-play (req (remove-watch state (keyword (s/strcat "iq" (:cid card)))))}) (defcard "Ireress" (let [sub (runner-loses-credits 1) @@ -2423,7 +2424,7 @@ :effect (effect (damage eid :net 2 {:card card}))} :subroutines [(assoc runner-trash-installed-sub :effect (req (wait-for (trash state side target {:cause :subroutine}) - (system-msg state :corp (str "uses " (:title card) " to trash itself")) + (system-msg state :corp (s/strcat "uses " (:title card) " to trash itself")) (trash state :corp (make-eid state eid) card {:cause :subroutine}) (encounter-ends state side eid))))]}) @@ -2447,7 +2448,7 @@ :async true :msg (msg (if (= target "Take 1 tag") "give the Runner 1 tag" - (str "force the runner to " (decapitalize target) " on encountering it"))) + (s/strcat "force the runner to " (decapitalize target) " on encountering it"))) :effect (req (if (= target "Take 1 tag") (gain-tags state :runner eid 1) (wait-for (pay state :runner (make-eid state eid) card (->c :click 1)) @@ -2489,7 +2490,7 @@ :prompt "Choose a card to move to the top of the Stack" :choices {:card #(some (partial same-card? %) targets)} :effect (req (move state :runner target :deck {:front true}) - (system-msg state :runner (str "selected " (card-str state target) " to move to the top of the Stack")))}) + (system-msg state :runner (s/strcat "selected " (card-str state target) " to move to the top of the Stack")))}) card nil))}]}) (defcard "Kakugo" @@ -2504,7 +2505,7 @@ (letfn [(brain-damage-unless-runner-pays [cost text] {:player :runner :async true - :label (str "Do 1 core damage unless the Runner trashes 1 installed " text) + :label (s/strcat "Do 1 core damage unless the Runner trashes 1 installed " text) :prompt "Choose one" :waiting-prompt true :choices (req ["Take 1 core damage" @@ -2512,13 +2513,13 @@ (capitalize (cost->string cost)))]) :msg (msg (if (= "Take 1 core damage" target) "do 1 core damage" - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :effect (req (if (= "Take 1 core damage" target) (damage state side eid :brain 1 {:card card}) (wait-for (pay state :runner (make-eid state eid) card cost) (when-let [payment-str (:msg async-result)] (system-msg state :runner - (str payment-str " due to " (:title card)))) + (s/strcat payment-str " due to " (:title card)))) (effect-completed state side eid))))})] {:subroutines [(brain-damage-unless-runner-pays [(->c :resource 1)] "resource") (brain-damage-unless-runner-pays [(->c :hardware 1)] "piece of hardware") @@ -2548,7 +2549,7 @@ :msg (msg "force the Runner to breach HQ and access " (:title target)) :effect (req (wait-for (breach-server state :runner [:hq] {:no-root true :access-first target}) - (system-msg state :corp (str "uses " (:title card) " to trash itself")) + (system-msg state :corp (s/strcat "uses " (:title card) " to trash itself")) (trash state :corp (make-eid state eid) card {:cause :subroutine}) (encounter-ends state side eid)))}}}]}) @@ -2593,7 +2594,7 @@ (seq (all-installed-runner-type state :resource)))) :yes-ability {:async true :effect (effect (continue-ability on-rez-ability card nil))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}}})) + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}}})) (defcard "Komainu" {:on-encounter {:effect (effect (gain-variable-subs card (count (:hand runner)) (do-net-damage 1)))} @@ -2662,7 +2663,7 @@ :duration :end-of-run :req (req (same-card? card target)) :value (:subtypes target)}) - (system-msg state :corp (str "uses " (:title card) " to choose " (card-str state target))) + (system-msg state :corp (s/strcat "uses " (:title card) " to choose " (card-str state target))) (doseq [sub (:subroutines target)] (add-sub! state side (get-card state card) sub (:cid target) {:front true})) (register-events @@ -2683,7 +2684,7 @@ "End the run"]) :msg (msg (if (= target "End the run") (decapitalize target) - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :effect (req (if (= target "End the run") (end-run state :corp eid card) (do (doseq [c (:hand runner)] @@ -2698,7 +2699,7 @@ {:label "Reveal the top 3 cards of the Stack" :async true :effect (req (if (seq (:deck runner)) - (do (system-msg state side (str "uses " (:title card) " to reveal " + (do (system-msg state side (s/strcat "uses " (:title card) " to reveal " (enumerate-str (top-3-names state)) " from the top of the stack")) (wait-for @@ -2717,7 +2718,7 @@ (wait-for (trash state :corp card {:cause :subroutine}) (encounter-ends state side eid))))} card nil))) - (do (system-msg state side (str "uses " (:title card) + (do (system-msg state side (s/strcat "uses " (:title card) " to trash itself")) (wait-for (trash state :corp card {:cause :subroutine}) (encounter-ends state side eid)))))}]})) @@ -2744,7 +2745,7 @@ ;; long as the card is rezzed ;; if the card is hushed, it will not derez, so the subtypes will stay! ;; - nbkelly, jan '24 - (system-msg state side (str "uses " (:title card) " to make itself gain " target)) + (system-msg state side (s/strcat "uses " (:title card) " to make itself gain " target)) (register-lingering-effect state side card (let [ice card] @@ -2946,7 +2947,7 @@ :choices ["Corp gains 4 [Credits] and end the run" "Add Meridian to score area"] :msg (msg (if (str/starts-with? target "Corp") "gain 4 [Credits] and end the run" - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :player :runner :async true :effect (req (if (str/starts-with? target "Corp") @@ -3006,7 +3007,7 @@ :msg (msg "spend 1 hosted advancement counter from " (:title card) " to force the Runner to lose 3 [Credits]") :effect (effect (add-prop :corp card :advance-counter -1 {:placed true}) (lose-credits :runner eid 3))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}} :subroutines [(runner-loses-credits 3) end-the-run]}) @@ -3098,17 +3099,17 @@ (defcard "Mlinzi" (letfn [(net-or-mill [net-dmg mill-cnt] - {:label (str "Do " net-dmg " net damage") + {:label (s/strcat "Do " net-dmg " net damage") :player :runner :waiting-prompt true :prompt "Choose one" - :choices (req [(str "Take " net-dmg " net damage") + :choices (req [(s/strcat "Take " net-dmg " net damage") (when (can-pay? state :runner eid card nil [(->c :trash-from-deck mill-cnt)]) (capitalize (build-cost-label [(->c :trash-from-deck mill-cnt)])))]) :async true - :effect (req (if (= target (str "Take " net-dmg " net damage")) + :effect (req (if (= target (s/strcat "Take " net-dmg " net damage")) (do (system-msg state :corp - (str "uses " (:title card) " to do " + (s/strcat "uses " (:title card) " to do " net-dmg " net damage")) (damage state :runner eid :net net-dmg {:card card})) (wait-for (pay state :runner (make-eid state eid) card [(->c :trash-from-deck mill-cnt)]) @@ -3261,9 +3262,9 @@ :msg (msg "add " (let [seen (filter :seen targets) m (count (filter #(not (:seen %)) targets))] - (str (enumerate-str (map :title seen)) + (s/strcat (enumerate-str (map :title seen)) (when (pos? m) - (str (when-not (empty? seen) " and ") + (s/strcat (when-not (empty? seen) " and ") (quantify m "unseen card"))))) " to HQ")} {:label "Shuffle up to X cards from HQ into R&D" @@ -3281,9 +3282,9 @@ (next-ice-variable-subs end-the-run)) (defcard "Nightdancer" - (let [sub {:label (str "The Runner loses [Click], if able. " + (let [sub {:label (s/strcat "The Runner loses [Click], if able. " "You have an additional [Click] to spend during your next turn") - :msg (str "force the runner to lose a [Click], if able. " + :msg (s/strcat "force the runner to lose a [Click], if able. " "Corp gains an additional [Click] to spend during [their] next turn") :effect (req (lose-clicks state :runner 1) (swap! state update-in [:corp :extra-click-temp] (fnil inc 0)))}] @@ -3299,7 +3300,7 @@ (let [card (get-card state card) counters ((get-x-fn) state side eid card targets)] {:optional - {:prompt (str "Place " (quantify counters "advancement counter") " on another ice?") + {:prompt (s/strcat "Place " (quantify counters "advancement counter") " on another ice?") :yes-ability {:msg (msg "place " (quantify counters "advancement counter") " on " (card-str state target)) :choices {:card ice? @@ -3333,7 +3334,7 @@ :async true :waiting-prompt true :prompt "Choose one" - :choices [(str "Access " title) + :choices [(s/strcat "Access " title) (when (can-pay? state :runner eid card nil [(->c :credit 3)]) "Pay 3 [Credits]")] :msg (msg "force the Runner to " (decapitalize target)) @@ -3350,7 +3351,7 @@ :label "Add installed program to the top of the stack" :msg "add 1 installed program to the top of the stack" :effect (effect (move :runner target :deck {:front true}) - (system-msg (str "adds " (:title target) " to the top of the stack")))}]}) + (system-msg (s/strcat "adds " (:title target) " to the top of the stack")))}]}) (defcard "Pachinko" {:subroutines [end-the-run-if-tagged @@ -3378,7 +3379,7 @@ :async true :effect (req (let [n (count (filter #(is-type? % target) (:hand runner)))] (system-msg state side - (str "uses " (:title card) " to name " target ", reveal " + (s/strcat "uses " (:title card) " to name " target ", reveal " (enumerate-str (map :title (:hand runner))) " from the grip, and gain " (quantify n "subroutine"))) (wait-for @@ -3530,20 +3531,20 @@ (let [top-cards (take 3 (:deck corp)) top-names (map :title top-cards)] {:waiting-prompt true - :prompt (str "The top cards of R&D are (top->bottom): " (enumerate-str top-names)) + :prompt (s/strcat "The top cards of R&D are (top->bottom): " (enumerate-str top-names)) :choices ["Arrange cards" "Shuffle R&D"] :async true :effect (req (if (= target "Arrange cards") (wait-for (resolve-ability state side (reorder-choice :corp top-cards) card nil) - (system-msg state :corp (str "rearranges the top " + (system-msg state :corp (s/strcat "rearranges the top " (quantify (count top-cards) "card") " of R&D")) (continue-ability state side maybe-draw-effect card nil)) (do (shuffle! state :corp :deck) - (system-msg state :corp (str "shuffles R&D")) + (system-msg state :corp (s/strcat "shuffles R&D")) (continue-ability state side maybe-draw-effect card nil))))}) card nil))} {:label "Trash 1 card in HQ" @@ -3556,7 +3557,7 @@ :prompt "Choose a card in HQ to trash" :choices (req (cancellable (:hand corp) :sorted)) :async true - :cancel-effect (effect (system-msg :corp (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (req (wait-for (trash state :corp target {:cause :subroutine}) @@ -3564,7 +3565,7 @@ (continue-ability state side trash-resource-sub card nil)))} card nil) (wait-for (trash state :corp (make-eid state eid) card {:cause-card card}) - (system-msg state :corp (str "uses " (:title card) " to trash itself")) + (system-msg state :corp (s/strcat "uses " (:title card) " to trash itself")) (encounter-ends state side eid))))}]})) (defcard "Sagittarius" @@ -3594,7 +3595,7 @@ (if-not (seq matching-type) (effect-completed state side eid) (letfn [(resolve-extra-damage [x] - (system-msg state :corp (str "uses " (:title card) " to deal 1 additional net damage" (when (> x 1) (str " (" (dec x) " remaining)")))) + (system-msg state :corp (s/strcat "uses " (:title card) " to deal 1 additional net damage" (when (> x 1) (s/strcat " (" (dec x) " remaining)")))) (if-not (> x 1) (damage state side eid :net 1 {:card card}) (wait-for (damage side :net 1 {:card card}) @@ -3755,8 +3756,8 @@ (defcard "Slot Machine" (letfn [(top-3 [state] (take 3 (get-in @state [:runner :deck]))) - (effect-type [card] (keyword (str "slot-machine-top-3-" (:cid card)))) - (name-builder [card] (str (:title card) " (" (:type card) ")")) + (effect-type [card] (keyword (s/strcat "slot-machine-top-3-" (:cid card)))) + (name-builder [card] (s/strcat (:title card) " (" (:type card) ")")) (top-3-names [cards] (map name-builder cards)) (top-3-types [state card et] (->> (get-effects state :corp et card) @@ -3776,7 +3777,7 @@ :duration :end-of-encounter :value t3}) (system-msg state side - (str "uses " (:title card) " to put the top card of the stack to the bottom," + (s/strcat "uses " (:title card) " to put the top card of the stack to the bottom," " then reveal " (enumerate-str (top-3-names t3)) " from the top of the stack")) @@ -3797,7 +3798,7 @@ (= 3 (count (first (get-effects state :corp et card))))) (and (= unique-types 1) (= 2 (count (first (get-effects state :corp et card)))))) - (do (system-msg state :corp (str "uses " (:title card) " to gain 3 [Credits]")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to gain 3 [Credits]")) (gain-credits state :corp eid 3)) (effect-completed state side eid))))} {:label "Place 3 advancement tokens" @@ -4002,7 +4003,7 @@ {:optional {:prompt (msg "Gain 4 [Credits] and swap " (card-str state card) " with a piece of ice in HQ?") :waiting-prompt true - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))} :yes-ability {:prompt "Choose a piece of ice" :waiting-prompt true :choices (req (filter ice? (:hand corp))) @@ -4014,7 +4015,7 @@ {:prompt "You have no ice" :choices ["OK"] :waiting-prompt true - :effect (effect (system-msg :runner (str "declines to use " (:title card) " to install a card")))}) + :effect (effect (system-msg :runner (s/strcat "declines to use " (:title card) " to install a card")))}) card nil))}] :subroutines [end-the-run]}) @@ -4071,9 +4072,9 @@ (complete-with-result state side eid target)))} card nil) (system-msg state side - (str "uses " (:title card) " to " + (s/strcat "uses " (:title card) " to " (if async-result - (str "trash " (:title async-result) + (s/strcat "trash " (:title async-result) " and ends the run") "end the run"))) (end-run state side eid card)))}]}) @@ -4119,9 +4120,9 @@ {:on-encounter {:async true :effect (req (wait-for (pay state :runner (make-eid state eid) card [(->c :credit 3)]) (if (:cost-paid async-result) - (do (system-msg state :runner (str (:msg async-result) " on encountering " (:title card))) + (do (system-msg state :runner (s/strcat (:msg async-result) " on encountering " (:title card))) (effect-completed state side eid)) - (do (system-msg state :corp (str "uses " (:title card) " to end the run")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to end the run")) (end-run state :corp eid card)))))} :subroutines [end-the-run]}) @@ -4175,7 +4176,7 @@ :effect (req (let [this (zone->name (second (get-zone card))) nice target] (continue-ability state side - {:prompt (str "Choose a location to install " (:title target)) + {:prompt (s/strcat "Choose a location to install " (:title target)) :choices (req (remove #(= this %) (installable-servers state nice))) :async true :effect (effect (corp-install eid nice target {:ignore-install-cost true @@ -4214,7 +4215,7 @@ (defcard "Troll" {:on-encounter (trace-ability 2 {:msg (msg (if (= target "Spend [Click]") - (str "force the runner to " (decapitalize target)) + (s/strcat "force the runner to " (decapitalize target)) (decapitalize target))) :player :runner :prompt "Choose one" @@ -4293,7 +4294,7 @@ :yes-ability {:async true :effect (effect (continue-ability on-rez-ability card nil))} :no-ability - {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}}})) + {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}}})) (defcard "Upayoga" {:subroutines [(do-psi (runner-loses-credits 2)) @@ -4337,9 +4338,9 @@ :prompt "Choose a card that can be advanced" :msg (msg "place 1 advancement counter on " (card-str state target)) :effect (effect (add-prop target :advance-counter 1 {:placed true})) - :cancel-effect (effect (system-msg :corp (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))) (effect-completed eid))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}} :subroutines [(give-tags 1)]}) (defcard "Veritas" @@ -4398,7 +4399,7 @@ (reveal state side (:hand runner)) (let [delta (- target (second targets)) cards (filter #(<= (:cost %) delta) (:hand runner))] - (system-msg state side (str "uses " (:title card) " to trash " + (system-msg state side (s/strcat "uses " (:title card) " to trash " (enumerate-str (map :title cards)))) (trash-cards state side eid cards {:cause :subroutine}))))})]}) @@ -4426,15 +4427,15 @@ :async true :msg (msg "reveal " (:title target) " from R&D and add it to HQ") :choices (req (cancellable (filter #(ice? %) (:deck corp)) :sorted)) - :cancel-effect (effect (system-msg (str "uses " (:title card) " to shuffle R&D")) + :cancel-effect (effect (system-msg (s/strcat "uses " (:title card) " to shuffle R&D")) (shuffle! :deck)) :effect (req (wait-for (reveal state side target) (shuffle! state side :deck) (move state side target :hand) (effect-completed state side eid)))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card))))}}} :rez-sound "wave" - :subroutines [{:label (str "Gain 1 [Credits] for each rezzed piece of Harmonic ice") + :subroutines [{:label (s/strcat "Gain 1 [Credits] for each rezzed piece of Harmonic ice") :msg (msg "gain " (harmonic-ice-count corp) " [Credits]") :async true :effect (req (gain-credits state :corp eid (harmonic-ice-count corp)))}]}) @@ -4448,7 +4449,7 @@ :choices (req (:hand runner)) :not-distinct true :async true - :effect (effect (system-msg :runner (str "trashes " (:title target) " from the grip")) + :effect (effect (system-msg :runner (s/strcat "trashes " (:title target) " from the grip")) (trash :runner eid target {:cause :subroutine}))}]}) (defcard "Wendigo" @@ -4511,7 +4512,7 @@ :optional {:prompt (msg "Move " (:title (first (:deck corp))) " to the bottom of R&D?") :yes-ability {:msg "move the top card of R&D to the bottom" :effect (effect (move (first (:deck corp)) :deck))} - :no-ability {:effect (effect (system-msg :corp (str "declines to use " (:title card) " to move the top card of R&D to the bottom")))}}} + :no-ability {:effect (effect (system-msg :corp (s/strcat "declines to use " (:title card) " to move the top card of R&D to the bottom")))}}} (do-net-damage 1)]}) (defcard "Zed 1.0" diff --git a/src/clj/game/cards/identities.clj b/src/clj/game/cards/identities.clj index d14fe4993d..b976c82e96 100644 --- a/src/clj/game/cards/identities.clj +++ b/src/clj/game/cards/identities.clj @@ -59,7 +59,8 @@ [game.core.winning :refer [check-win-by-agenda]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) ;;; Helper functions for Draft cards (def draft-points-target @@ -114,7 +115,7 @@ state side {:optional {:waiting-prompt true - :prompt (req (str "Pay 1 [Credits] to prevent exposing " (card-str state (:card context)) "?")) + :prompt (req (s/strcat "Pay 1 [Credits] to prevent exposing " (card-str state (:card context)) "?")) :player :corp :no-ability {:async true @@ -125,7 +126,7 @@ (req (wait-for (pay state :corp (make-eid state eid) card [(->c :credit 1)]) (system-msg state :corp - (str (:msg async-result) + (s/strcat (:msg async-result) " to prevent exposing " (card-str state (:card context)))) (effect-completed state side eid)))}}} @@ -174,7 +175,7 @@ :async true :effect (req (let [to-be-trashed (remove #(in-coll? ["Archives" "R&D" "HQ" target saved] (zone->name (second (get-zone %)))) (all-installed state :corp))] - (system-msg state side (str "chooses " target " and " saved " to be saved from the rules apocalypse and trashes " + (system-msg state side (s/strcat "chooses " target " and " saved " to be saved from the rules apocalypse and trashes " (quantify (count to-be-trashed) "card"))) ;; these cards get trashed by the game and not by players (trash-cards state side eid to-be-trashed {:unpreventable true :game-trash true})))} @@ -204,7 +205,7 @@ (swap! state assoc-in [:runner :play-area] directives) (continue-ability state side - {:prompt (str "Choose 3 starting directives") + {:prompt (s/strcat "Choose 3 starting directives") :choices {:max 3 :all true :card #(and (runner? %) @@ -214,13 +215,13 @@ state side (make-eid state eid) (first targets) {:ignore-all-cost true - :custom-message (fn [_] (str "starts with " (:title (first targets)) " in play"))}) + :custom-message (fn [_] (s/strcat "starts with " (:title (first targets)) " in play"))}) (wait-for (runner-install state side (make-eid state eid) (second targets) {:ignore-all-cost true - :custom-message (fn [_] (str "starts with " (:title (second targets)) " in play"))}) + :custom-message (fn [_] (s/strcat "starts with " (:title (second targets)) " in play"))}) (wait-for (runner-install state side @@ -229,7 +230,7 @@ next first) {:ignore-all-cost true - :custom-message (fn [_] (str "starts with " (:title (-> targets + :custom-message (fn [_] (s/strcat "starts with " (:title (-> targets next next first)) " in play"))}) @@ -360,7 +361,7 @@ (if (has-subtype? program "Trojan") (update! state :runner (dissoc-in program [:special :street-artist])) (do - (system-msg state side (str "uses " (:title card) " to trash " (:title program))) + (system-msg state side (s/strcat "uses " (:title card) " to trash " (:title program))) (trash-cards state side eid [program] {:cause-card card})))))}])))} card nil))}]}) @@ -436,8 +437,8 @@ :choices ["Event" "Resource" "Program" "Hardware" "None"] :effect (req (update! state side (assoc card :card-target (if (= "None" target) nil target))) (if (= "None" target) - (system-msg state side (str "declines to use " (:title card))) - (system-msg state side (str "uses " (:title card) " to name " target))))} + (system-msg state side (s/strcat "declines to use " (:title card))) + (system-msg state side (s/strcat "uses " (:title card) " to name " target))))} {:event :runner-install :req (req (and (:card-target card) (is-type? (:card context) (:card-target card)) @@ -535,7 +536,7 @@ :effect (req (chosen-damage state :corp target))} card nil))} :no-ability - {:effect (req (system-msg state :corp (str "declines to use " (:title card))))}}}]}) + {:effect (req (system-msg state :corp (s/strcat "declines to use " (:title card))))}}}]}) (defcard "Cybernetics Division: Humanity Upgraded" {:static-abilities [(hand-size+ -1)]}) @@ -550,7 +551,7 @@ (assoc card :flipped true :face :back - :code (str (subs (:code card) 0 5) "flip")))))] + :code (s/strcat (subs (:code card) 0 5) "flip")))))] {:flags {:server-limit 1} :events [{:event :pre-first-turn :req (req (= side :corp)) @@ -573,7 +574,7 @@ :async true :effect (req (let [to-be-trashed (remove #(in-coll? ["Archives" "R&D" "HQ" target] (zone->name (second (get-zone %)))) (all-installed state :corp))] - (system-msg state side (str "chooses " target + (system-msg state side (s/strcat "chooses " target " to be saved from the rules apocalypse and trashes " (quantify (count to-be-trashed) "card"))) ; these cards get trashed by the game and not by players @@ -601,7 +602,7 @@ (swap! state assoc-in [:runner :register :trashed-card] true) (swap! state assoc-in [:runner :register :trashed-accessed-card] true) (system-msg state :runner - (str "uses " (:title card) " to" + (s/strcat "uses " (:title card) " to" " trash " (:title target) " at no cost")) (trash state side eid target nil))))}]}) @@ -638,7 +639,7 @@ :choices (cancellable (filter #(corp-installable-type? %) top)) :async true :cancel-effect - (effect (system-msg (str "declines to use " (get-title card) " to install a card from the top of R&D")) + (effect (system-msg (s/strcat "declines to use " (get-title card) " to install a card from the top of R&D")) (effect-completed eid)) :effect (effect (corp-install eid target nil {:msg-keys {:install-source card :index (first (keep-indexed #(when (same-card? target %2) %1) top)) @@ -706,7 +707,7 @@ (wait-for (resolve-ability state side (pick-virus-counters-to-spend play-or-rez) card nil) (if-let [msg (:msg async-result)] (do (system-msg state :runner - (str "uses " (:title card) " to" + (s/strcat "uses " (:title card) " to" " trash " (:title accessed-card) " at no cost, spending " msg)) (trash state side eid (assoc accessed-card :seen true) {:accessed true})) @@ -834,13 +835,13 @@ {:event :tags-changed :effect (req (if (is-tagged? state) (when-not (get-in @state [:runner :openhand]) - (system-msg state :corp (str "uses " (get-title card) " make the Runner play with [runner-pronoun] grip revealed")) - (system-msg state :corp (str "uses " (get-title card) " to see that the Runner currently has " + (system-msg state :corp (s/strcat "uses " (get-title card) " make the Runner play with [runner-pronoun] grip revealed")) + (system-msg state :corp (s/strcat "uses " (get-title card) " to see that the Runner currently has " (format-grip runner) " in [runner-pronoun] grip")) (reveal-hand state :runner)) (when (get-in @state [:runner :openhand]) - (system-msg state :corp (str "uses " (get-title card) " stop making the Runner play with [runner-pronoun] grip revealed")) - (system-msg state :corp (str "uses " (get-title card) " to note that the Runner had " + (system-msg state :corp (s/strcat "uses " (get-title card) " stop making the Runner play with [runner-pronoun] grip revealed")) + (system-msg state :corp (s/strcat "uses " (get-title card) " to note that the Runner had " (format-grip runner) " in [runner-pronoun] grip before it was concealed")) (conceal-hand state :runner))))}] :effect (req (when (is-tagged? state) @@ -868,15 +869,15 @@ card-type (:type itarget)] (if (some #(is-type? % (:type itarget)) (:hand runner)) {:optional - {:prompt (str "Install another " card-type " from the grip?") + {:prompt (s/strcat "Install another " card-type " from the grip?") :yes-ability - {:prompt (str "Choose a " card-type " to install") + {:prompt (s/strcat "Choose a " card-type " to install") :choices {:card #(and (is-type? % card-type) (in-hand? %))} :async true :effect (effect (runner-install (assoc eid :source card :source-type :runner-install) target {:msg-keys {:install-source card :display-origin true}}))}}} - {:prompt (str "You have no " card-type " to install") + {:prompt (s/strcat "You have no " card-type " to install") :choices ["Carry on!"] :prompt-type :bogus})) card nil))}]}) @@ -891,7 +892,7 @@ (assoc card :flipped true :face :back - :code (str (subs (:code card) 0 5) "flip") + :code (s/strcat (subs (:code card) 0 5) "flip") :subtype "Digital"))) (update-link state))] {:static-abilities [(link+ (req (:flipped card)) 1) @@ -926,7 +927,7 @@ :async true :effect (req (wait-for (draw state :runner 1) (wait-for (lose-credits state :runner (make-eid state eid) 1) - (system-msg state :runner (str "uses " (:title card) " to draw 1 card and lose 1 [Credits]")) + (system-msg state :runner (s/strcat "uses " (:title card) " to draw 1 card and lose 1 [Credits]")) (effect-completed state side eid))))}] :abilities [{:label "flip identity" :msg "flip [their] identity manually" @@ -945,7 +946,7 @@ :label "Reveal the top card of the Stack" :async true :effect (req (if-let [revealed-card (-> runner :deck first)] - (do (system-msg state side (str "uses " (:title card) " to reveal " + (do (system-msg state side (s/strcat "uses " (:title card) " to reveal " (:title revealed-card) " from the top of the Stack")) (reveal state side eid revealed-card)) (effect-completed state side eid)))} @@ -954,7 +955,7 @@ :label "Reveal a random card from the Grip" :async true :effect (req (if-let [revealed-card (-> runner :hand shuffle first)] - (do (system-msg state side (str "uses " (:title card) " to reveal " + (do (system-msg state side (s/strcat "uses " (:title card) " to reveal " (:title revealed-card) " from the Grip")) (reveal state side eid revealed-card)) (effect-completed state side eid)))}]}) @@ -1045,7 +1046,7 @@ :prompt (msg "Choose a copy of " (:title card) " to use this game") :choices ["The Brewery" "The Tank" "The Greenhouse"] :effect (effect (update! (assoc card :biotech-target target :face :front)) - (system-msg (str "has chosen a copy of " (:title card) " for this game")))}] + (system-msg (s/strcat "has chosen a copy of " (:title card) " for this game")))}] :abilities [{:label "Check chosen flip identity" :effect (req (case (:biotech-target card) "The Brewery" @@ -1065,16 +1066,16 @@ (update! state side (assoc (get-card state card) :biotech-used true)) (case flip "The Brewery" - (do (system-msg state side (str "uses " flip " to do 2 net damage")) + (do (system-msg state side (s/strcat "uses " flip " to do 2 net damage")) (update! state side (assoc card :code "brewery" :face :brewery)) (damage state side eid :net 2 {:card card})) "The Tank" - (do (system-msg state side (str "uses " flip " to shuffle Archives into R&D")) + (do (system-msg state side (s/strcat "uses " flip " to shuffle Archives into R&D")) (shuffle-into-deck state side :discard) (update! state side (assoc card :code "tank" :face :tank)) (effect-completed state side eid)) "The Greenhouse" - (do (system-msg state side (str "uses " flip " to place 4 advancement counters " + (do (system-msg state side (s/strcat "uses " flip " to place 4 advancement counters " "on a card that can be advanced")) (update! state side (assoc card :code "greenhouse" :face :greenhouse)) (continue-ability @@ -1083,7 +1084,7 @@ :choices {:req (req (can-be-advanced? state target))} :effect (effect (add-prop target :advance-counter 4 {:placed true}))} card nil)) - (toast state :corp (str "Unknown Jinteki Biotech: Life Imagined card: " flip) "error"))))}]}) + (toast state :corp (s/strcat "Unknown Jinteki Biotech: Life Imagined card: " flip) "error"))))}]}) (defcard "Jinteki: Personal Evolution" (let [ability {:async true @@ -1102,7 +1103,7 @@ (= (:damage-type context) :net) (pos? (:amount context)))) :effect (req (let [c (first (get-in @state [:runner :deck]))] - (system-msg state :corp (str "uses " (:title card) " to trash " (:title c) + (system-msg state :corp (s/strcat "uses " (:title card) " to trash " (:title c) " from the top of the stack")) (mill state :corp eid :runner 1)))}]}) @@ -1210,7 +1211,7 @@ :yes-ability {:msg "force the Corp to draw 1 card" :async true :effect (effect (draw :corp eid 1))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :abilities [(set-autoresolve :auto-fire "Laramy Fisk: Savvy Investor")]}) (defcard "Lat: Ethical Freelancer" @@ -1227,7 +1228,7 @@ :msg "draw 1 card" :effect (effect (draw :runner eid 1))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}} + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}} card nil))}] :abilities [(set-autoresolve :auto-fire "Lat: Ethical Freelancer")]}) @@ -1266,7 +1267,7 @@ (defcard "MaxX: Maximum Punk Rock" (let [ability {:msg (msg (let [deck (:deck runner)] (if (pos? (count deck)) - (str "trash " (enumerate-str (map :title (take 2 deck))) " from the stack and draw 1 card") + (s/strcat "trash " (enumerate-str (map :title (take 2 deck))) " from the stack and draw 1 card") "trash the top 2 cards from the stack and draw 1 card - but the stack is empty"))) :label "trash and draw cards" :once :per-turn @@ -1298,7 +1299,7 @@ :async true :effect (req (access-bonus state side breached-server 1 :end-of-access) (effect-completed state side eid))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to access 1 additional card")))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to access 1 additional card")))}}} card nil)))}]}) (defcard "MirrorMorph: Endless Iteration" @@ -1418,7 +1419,7 @@ :async true :effect (req (if (and (> 3 (count (:hand runner))) (:runner-phase-12 @state)) - (do (system-msg state :runner (str "uses " (:title card) " to gain 1 [Credits]")) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to gain 1 [Credits]")) (gain-credits state :runner eid 1)) (effect-completed state side eid)))}] {:flags {:drip-economy true @@ -1602,7 +1603,7 @@ :effect (effect (continue-ability {:optional - {:prompt (str "Trash " (:title (first (:deck corp))) "?") + {:prompt (s/strcat "Trash " (:title (first (:deck corp))) "?") :yes-ability {:msg "trash the top card of R&D" :async true @@ -1647,7 +1648,7 @@ (continue-ability state side {:optional - {:prompt (str "Rez " (:title inst-target) ", paying additional costs?") + {:prompt (s/strcat "Rez " (:title inst-target) ", paying additional costs?") :yes-ability {:msg (msg "rez " (:title inst-target) ", paying additional costs") :async true @@ -1695,8 +1696,8 @@ (ob-ability [target-cost] {:optional {:prompt (if (>= target-cost 0) - (str "Install a " target-cost "-cost card from your deck?") - (str "Shuffle your deck (search for a " target-cost "-cost card from your deck?)")) + (s/strcat "Install a " target-cost "-cost card from your deck?") + (s/strcat "Shuffle your deck (search for a " target-cost "-cost card from your deck?)")) :once :per-turn :waiting-prompt true :yes-ability @@ -1726,7 +1727,7 @@ :effect (effect (shuffle! :corp :deck))} card nil)))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}})] + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}})] {:events [{:event :corp-trash :req (req (and (installed? (:card context)) @@ -1788,7 +1789,7 @@ :choices {:req (req (and (installed? target) (can-be-advanced? state target)))} :msg (msg "place 1 advancement token on " (card-str state target)) :effect (effect (add-prop :corp eid target :advance-counter 1 {:placed true})) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid))}]}) (defcard "Quetzal: Free Spirit" @@ -1973,7 +1974,7 @@ (reduce +))] (continue-ability state side - {:prompt (str "Choose a piece of ice with no advancement tokens to place " + {:prompt (s/strcat "Choose a piece of ice with no advancement tokens to place " (quantify agenda-points "advancement token") " on") :choices {:card #(selectable-ice? %)} :msg (msg "place " (quantify agenda-points "advancement token") @@ -2011,7 +2012,7 @@ :msg (msg (let [[chosen other](if (= target c1) [c1 c2] [c2 c1])] - (str "add " (:title other) " from the heap to the grip." + (s/strcat "add " (:title other) " from the heap to the grip." " Corp removes " (:title chosen) " from the game"))) :effect (req (let [[chosen other] (if (= target c1) [c1 c2] @@ -2096,7 +2097,7 @@ :msg (msg "swap the positions of " (card-str state (first targets)) " and " (card-str state (second targets))) :effect (req (swap-ice state side (first targets) (second targets)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] {:events [(assoc swap-ability :event :agenda-scored) (assoc swap-ability :event :agenda-stolen)]})) @@ -2149,10 +2150,10 @@ :yes-ability {:effect (req (if-let [found-card (some #(when (= (:title %) (:title (:card context))) %) (concat (:deck corp) (:play-area corp)))] (do (move state side found-card :hand) - (system-msg state side (str "uses " (:title card) " to add a copy of " + (system-msg state side (s/strcat "uses " (:title card) " to add a copy of " (:title found-card) " to HQ, and shuffle R&D")) (shuffle! state side :deck)) - (do (system-msg state side (str "shuffles R&D")) + (do (system-msg state side (s/strcat "shuffles R&D")) (shuffle! state side :deck))))}}}]}) (defcard "The Masque: Cyber General" @@ -2189,7 +2190,7 @@ :async true :waiting-prompt true :msg (msg (if (= target "Pay [Click] and 2 [Credits]") - (str "force the runner to " (decapitalize target)) + (s/strcat "force the runner to " (decapitalize target)) "do 1 core damage")) :effect (req (if (= target "Pay [Click] and 2 [Credits]") (wait-for (pay state side (make-eid state eid) card [(->c :click 1) (->c :credit 2)]) @@ -2210,13 +2211,13 @@ (capitalize (cost->string (->c :trash-installed 1))))]) :msg (msg (if (= "End the run" target) (decapitalize target) - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :effect (req (if (= "End the run" target) (end-run state :corp eid card) (wait-for (pay state :runner (make-eid state eid) card (->c :trash-installed 1)) (when-let [payment-str (:msg async-result)] (system-msg state :runner - (str payment-str + (s/strcat payment-str " due to " (:title card) " subroutine"))) (effect-completed state side eid))))} diff --git a/src/clj/game/cards/operations.clj b/src/clj/game/cards/operations.clj index 0b68b5d991..6b013673af 100644 --- a/src/clj/game/cards/operations.clj +++ b/src/clj/game/cards/operations.clj @@ -55,7 +55,8 @@ [game.core.virus :refer [number-of-virus-counters]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) (defn- lockdown ;; Helper function for lockdowns. Enforces the "cannot play if there's another active lockdown" @@ -109,7 +110,7 @@ (not (seq remaining-cards)) {} (> (shuffle-count-fn state) starting-shuffle-count) - {:msg (str "is unable to continue resolving " (:title card))} + {:msg (s/strcat "is unable to continue resolving " (:title card))} (seq playable-cards) {:prompt "Choose an operation to play" :choices (cancellable playable-cards) @@ -159,7 +160,7 @@ :choices {:card #(and (corp-installable-type? %) (in-hand? %))} :async true - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card from HQ")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card from HQ")) (continue-ability lose-click-abi card nil)) :effect (req (wait-for (corp-install state side target nil {:msg-keys {:install-source card :display-origin true}}) @@ -202,13 +203,13 @@ :prompt "Choose a server" :choices ["Archives" "R&D" "HQ"] :effect - (effect (show-wait-prompt (str "Runner to decide on running " target)) + (effect (show-wait-prompt (s/strcat "Runner to decide on running " target)) (continue-ability (let [serv target] {:optional - {:prompt (str "Make a run on " serv "?") + {:prompt (s/strcat "Make a run on " serv "?") :player :runner - :yes-ability {:msg (str "let the Runner make a run on " serv) + :yes-ability {:msg (s/strcat "let the Runner make a run on " serv) :async true :effect (effect (clear-wait-prompt :corp) (make-run eid serv card) @@ -292,14 +293,14 @@ from-archives (map :title (filter in-discard? targets))] (system-msg state side - (str "uses " (:title card) " to reveal " + (s/strcat "uses " (:title card) " to reveal " (enumerate-str (filter identity [(when (not-empty from-hq) - (str (enumerate-str from-hq) + (s/strcat (enumerate-str from-hq) " from HQ")) (when (not-empty from-archives) - (str (enumerate-str from-archives) + (s/strcat (enumerate-str from-archives) " from Archives"))])) ", shuffle them into R&D and gain " (* 2 (count targets)) " [Credits]"))) @@ -400,14 +401,14 @@ (wait-for (gain-credits state :runner (count trashed-cards)) (system-msg state :runner - (str "trashes " (enumerate-str (map :title trashed-cards)) + (s/strcat "trashes " (enumerate-str (map :title trashed-cards)) " and gains " (count trashed-cards) " [Credits]")) (effect-completed state side eid)))))} card nil) (let [n (* 2 (num-installed state t))] (if (pos? n) - (do (system-msg state :corp (str "uses " (:title card) " to gain " n " [Credits]")) + (do (system-msg state :corp (s/strcat "uses " (:title card) " to gain " n " [Credits]")) (gain-credits state :corp eid n)) (effect-completed state side eid))))))}})) @@ -433,10 +434,10 @@ state side {:optional {:req (req (can-score? state side (get-card state card-to-score))) - :prompt (str "Score " (:title card-to-score) "?") + :prompt (s/strcat "Score " (:title card-to-score) "?") :yes-ability {:async true :effect (effect (score eid (get-card state card-to-score)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to score " (card-str state card-to-score))))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to score " (card-str state card-to-score))))}}} card nil))))}}) (defcard "Bioroid Efficiency Research" @@ -458,7 +459,7 @@ :req (req (and (same-card? (:ice context) (:host card)) (empty? (remove :broken (:subroutines (:ice context)))))) :effect (effect (system-msg :corp - (str "derezzes " (:title (:ice context)) + (s/strcat "derezzes " (:title (:ice context)) " and trashes Bioroid Efficiency Research")) (derez :corp (:ice context) {:source-card card}) (trash :corp eid card {:unpreventable true :cause-card card}))}]}) @@ -501,7 +502,7 @@ :effect (req (let [target-card (first (shuffle (:hand runner)))] (wait-for (reveal state side target-card) - (system-msg state side (str "shuffles " (:title target-card) " into the stack")) + (system-msg state side (s/strcat "shuffles " (:title target-card) " into the stack")) (move state :runner target-card :deck) (shuffle! state :runner :deck))))}}} card nil))})] @@ -564,7 +565,7 @@ :msg-keys {:install-source card :display-origin true}}) (let [agenda async-result] - (system-msg state side (str "hosts " (:title card) " on " (:title agenda))) + (system-msg state side (s/strcat "hosts " (:title card) " on " (:title agenda))) (install-as-condition-counter state side eid card agenda))))} :events [{:event :access :condition :hosted @@ -737,7 +738,7 @@ :choices (req (conj (vec (filter agenda? (:deck corp))) "None")) :msg (msg (if (= "None" target) "shuffle R&D" - (str "reveal " (:title target) " from R&D and add it to HQ"))) + (s/strcat "reveal " (:title target) " from R&D and add it to HQ"))) :effect (let [end-effect (req (system-msg state side "can not score agendas for the remainder of the turn") (swap! state assoc-in [:corp :register :cannot-score] (filter agenda? (all-installed state :corp))) @@ -783,7 +784,7 @@ :display-origin true}}))}) target nil) (end-effect state side eid card targets))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card")) (end-effect eid card targets))} card nil))))}}) @@ -919,7 +920,7 @@ :effect (effect (trash eid target {:cause-card card}))}}}}) (defcard "Enhanced Login Protocol" - {:on-play {:msg (str "add an additional cost of [Click]" + {:on-play {:msg (s/strcat "add an additional cost of [Click]" " to make the first run not through a card ability this turn")} :static-abilities [{:type :run-additional-cost @@ -959,7 +960,7 @@ :async true :waiting-prompt true :msg (msg "trash " (card-str state target) " and gain 3 [Credits]") - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to trash an installed card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to trash an installed card")) (effect-completed eid)) :effect (req (wait-for (trash state side target {:cause-card card}) (gain-credits state side eid 3)))} @@ -1031,7 +1032,7 @@ (installed? %))} :async true :effect (effect (system-msg :runner - (str "trashes " (:title target) + (s/strcat "trashes " (:title target) " to prevent Financial Collapse")) (trash :runner eid target {:unpreventable true :cause-card card :cause :forced-to-trash}))} :no-ability @@ -1050,7 +1051,7 @@ numtargets (count (filter #(= type (:type %)) (:hand runner)))] (system-msg state :corp - (str "uses " (:title card) " to choose " target + (s/strcat "uses " (:title card) " to choose " target " and reveal " (enumerate-str (map :title (sort-by :title (:hand runner)))) " from the grip")) @@ -1127,7 +1128,7 @@ ;; if current > total, this ability will auto-resolve and finish the chain of async methods. (when (<= current total) {:async true - :prompt (str "Choose one. Choice " current " of " total) + :prompt (s/strcat "Choose one. Choice " current " of " total) :choices ["Gain 2 [Credits]" "Draw 2 cards"] :msg (msg (decapitalize target)) :effect (req (if (= target "Gain 2 [Credits]") @@ -1160,9 +1161,9 @@ (not (has-subtype? % "Icebreaker"))) (all-active-installed state :runner)) numtargets (count trashtargets) - typemsg (str (when (= card-type "Program") "non-Icebreaker ") card-type + typemsg (s/strcat (when (= card-type "Program") "non-Icebreaker ") card-type (when-not (= card-type "Hardware") "s"))] - (system-msg state :corp (str "chooses to trash all " typemsg)) + (system-msg state :corp (s/strcat "chooses to trash all " typemsg)) (wait-for (resolve-ability state :runner {:async true @@ -1176,7 +1177,7 @@ :effect (req (wait-for (pay state :runner (make-eid state eid) card (->c :credit (* 3 (count targets)))) (system-msg state :runner - (str (:msg async-result) " to prevent the trashing of " + (s/strcat (:msg async-result) " to prevent the trashing of " (enumerate-str (map :title (sort-by :title targets))))) (effect-completed state side (make-result eid targets))))} card nil) @@ -1184,10 +1185,10 @@ cids-to-trash (set/difference (set (map :cid trashtargets)) (set (map :cid prevented))) cards-to-trash (filter #(cids-to-trash (:cid %)) trashtargets)] (when (not async-result) - (system-msg state :runner (str "chooses to not prevent Corp trashing all " typemsg))) + (system-msg state :runner (s/strcat "chooses to not prevent Corp trashing all " typemsg))) (wait-for (trash-cards state side cards-to-trash {:cause-card card}) (system-msg state :corp - (str "trashes all " + (s/strcat "trashes all " (when (seq prevented) "other ") typemsg ": " (enumerate-str (map :title (sort-by :title async-result))))) @@ -1224,7 +1225,7 @@ (corp-installable-type? %) (in-hand? %))} :async true - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card from HQ")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card from HQ")) (effect-completed eid)) :effect (req (wait-for (corp-install state :corp (make-eid state eid) target nil {:msg-keys {:install-source card :display-origin true}}) @@ -1289,7 +1290,7 @@ :effect (req (wait-for (trash-cards state side targets {:cause-card card}) (gain-credits state side eid 10)))} card nil) (do - (system-msg state side (str "uses " (:title card) " to gain 10 [Credits]")) + (system-msg state side (s/strcat "uses " (:title card) " to gain 10 [Credits]")) (gain-credits state side eid 10))))}}) (defcard "Hard-Hitting News" @@ -1304,7 +1305,7 @@ (defcard "Hasty Relocation" (letfn [(hr-final [chosen original] - {:prompt (str "The top cards of R&D will be " (enumerate-str (map :title chosen))) + {:prompt (s/strcat "The top cards of R&D will be " (enumerate-str (map :title chosen))) :choices ["Done" "Start over"] :async true :effect (req (if (= target "Done") @@ -1356,7 +1357,7 @@ :choices {:card #(and (installed? %) (resource? %))} :effect (effect (move :runner target :deck {:front true}) - (system-msg (str "adds " (:title target) " to the top of the Stack")))} + (system-msg (s/strcat "adds " (:title target) " to the top of the Stack")))} :unsuccessful {:msg "take 1 bad publicity" :effect (effect (gain-bad-publicity :corp 1))}}}}) @@ -1489,7 +1490,7 @@ (let [x (- target (second targets))] (system-msg state :corp - (str "uses " (:title card) " to reveal " + (s/strcat "uses " (:title card) " to reveal " (enumerate-str (map :title (sort-by :title (:hand runner)))) " from the grip and trash up to " x " resources or events")) (continue-ability state side (iop (dec x)) card nil))))} @@ -1529,7 +1530,7 @@ (update! state side (assoc-in c [:seen] false))) (shuffle! state :corp :discard) (continue-ability state side install-abi card nil))) - :cancel-effect (req (system-msg state :corp (str "declines to use " (:title card) " to trash any cards from HQ")) + :cancel-effect (req (system-msg state :corp (s/strcat "declines to use " (:title card) " to trash any cards from HQ")) (doseq [c (:discard (:corp @state))] (update! state side (assoc-in c [:seen] false))) (shuffle! state :corp :discard) @@ -1567,7 +1568,7 @@ (corp-installable-type? %) (in-hand? %))} :async true - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid)) :effect (effect (corp-install eid target nil {:msg-keys {:install-source card :display-origin true}}))} @@ -1628,7 +1629,7 @@ {:req (req tagged) :change-in-game-state (req (pos? (:credit runner))) :msg (msg (let [c (credit-diff state)] - (str "make the runner lose " c " [Credits], and gain " c " [Credits]"))) + (s/strcat "make the runner lose " c " [Credits], and gain " c " [Credits]"))) :async true :effect (req (let [c (credit-diff state)] (wait-for (lose-credits state :runner (make-eid state eid) c) @@ -1659,7 +1660,7 @@ :label "Trash MCA Informant host" :cost [(->c :click 1) (->c :credit 2)] :async true - :effect (effect (system-msg :runner (str "spends [Click] and 2 [Credits] to trash " + :effect (effect (system-msg :runner (s/strcat "spends [Click] and 2 [Credits] to trash " (card-str state (:host card)))) (trash :runner eid (get-card state (:host card)) {:cause-card (:host card)}))}]}) @@ -1690,7 +1691,7 @@ :successful {:msg "give the Runner X tags" :async true :effect (effect (system-msg - (str "gives the Runner " (quantify (- target (second targets)) "tag"))) + (s/strcat "gives the Runner " (quantify (- target (second targets)) "tag"))) (gain-tags eid (- target (second targets))))}}}}) (defcard "Mindscaping" @@ -1699,7 +1700,7 @@ :choices ["Gain 4 [Credits] and draw 2 cards" "Do 1 net damage per tag (up to 3)"] :msg (msg (if (= target "Do 1 net damage per tag (up to 3)") - (str "do " (min 3 (count-tags state)) " net damage") + (s/strcat "do " (min 3 (count-tags state)) " net damage") (decapitalize target))) :async true :effect (req (if (= "Do 1 net damage per tag (up to 3)" target) @@ -1805,14 +1806,14 @@ (map :title))] (wait-for (trash state :corp target {:cause-card card}) (shuffle! state :corp :deck) - (system-msg state side (str "uses " (:title card) " to trash " (:title target))) + (system-msg state side (s/strcat "uses " (:title card) " to trash " (:title target))) (wait-for (reveal state side revealed-cards) - (system-msg state side (str "reveals " (enumerate-str titles) " from R&D")) + (system-msg state side (s/strcat "reveals " (enumerate-str titles) " from R&D")) (let [ice (first r) zone (zone->name (second (get-zone target)))] (if ice - (do (system-msg state side (str "uses " (:title card) + (do (system-msg state side (s/strcat "uses " (:title card) " to install and rez " (:title ice) " from R&D at no cost")) @@ -1820,7 +1821,7 @@ :install-state :rezzed-no-cost :display-message false :index index})) - (do (system-msg state side (str "uses " (:title card) " to shuffle R&D")) + (do (system-msg state side (s/strcat "uses " (:title card) " to shuffle R&D")) (effect-completed state side eid))))))))}}) (defcard "Mutually Assured Destruction" @@ -1894,7 +1895,7 @@ "The Corp gains [Click][Click]"]) :msg (msg (if (= target "The Corp gains [Click][Click]") "gain [Click][Click]" - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :effect (req (if (= target "The Corp gains [Click][Click]") (do (gain-clicks state :corp 2) (effect-completed state side eid)) @@ -2179,7 +2180,7 @@ (effect (continue-ability (let [top-five (take 5 (:deck corp))] - {:prompt (str "The top cards of R&D are (top->bottom): " (enumerate-str (map get-title top-five))) + {:prompt (s/strcat "The top cards of R&D are (top->bottom): " (enumerate-str (map get-title top-five))) :waiting-prompt true :choices ["OK"] :async true @@ -2194,7 +2195,7 @@ (some #{"New remote"} (installable-servers state %))) top-five)) :effect (effect (continue-ability (install-card target) card nil)) - :cancel-effect (effect (system-msg (str "declines to use " (get-title card) " to install a card from the top of R&D")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (get-title card) " to install a card from the top of R&D")) (effect-completed eid))} card nil))}) card nil))}})) @@ -2234,7 +2235,7 @@ n (count cards)] (continue-ability state side - {:prompt (str "How many copies of " + {:prompt (s/strcat "How many copies of " title " do you want to reveal?") :choices {:number (req n)} :msg (msg "reveal " @@ -2242,7 +2243,7 @@ " of " title " from Archives" (when (pos? target) - (str " and add " + (s/strcat " and add " (if (= 1 target) "it" "them") " to HQ"))) :async true @@ -2259,7 +2260,7 @@ (defcard "Recruiting Trip" (let [rthelp (fn rt [total left selected] (if (pos? left) - {:prompt (str "Choose a Sysop (" (inc (- total left)) "/" total ")") + {:prompt (s/strcat "Choose a Sysop (" (inc (- total left)) "/" total ")") :choices (req (cancellable (filter #(and (has-subtype? % "Sysop") (not-any? #{(:title %)} selected)) (:deck corp)) :sorted)) :msg (msg "add " (:title target) " to HQ") @@ -2331,7 +2332,7 @@ (add-prop state side c :advance-counter (- (get-counters c :advancement)) {:placed true})) (add-prop state side target :advance-counter total-adv {:placed true}) (update-all-ice state side) - (system-msg state side (str "uses " (:title card) " to move " + (system-msg state side (s/strcat "uses " (:title card) " to move " (quantify total-adv "advancement counter") " to " (card-str state target))) (effect-completed state side eid)))}}) @@ -2375,7 +2376,7 @@ (when (seq leftover) (doseq [c leftover] (move state side c :rfg)) - (system-msg state side (str "removes " (count leftover) " copies of " (:title target) " from the game")))) + (system-msg state side (s/strcat "removes " (count leftover) " copies of " (:title target) " from the game")))) (effect-completed state side eid)))}}) (defcard "Restoring Face" @@ -2423,7 +2424,7 @@ :card #(and (corp? %) (in-hand? %))} :msg (msg (let [m (count targets)] - (str "trash " (quantify m "card") + (s/strcat "trash " (quantify m "card") " and gain " (* 2 m) " [Credits]"))) :async true :effect (req (wait-for (trash-cards state side targets {:unpreventable true :cause-card card}) @@ -2438,7 +2439,7 @@ :async true :effect (req (if (= target "Gain 2 [Credits]") (wait-for (gain-credits state side 2) - (system-msg state side (str "uses " (:title card) " to gain 2 [Credits]")) + (system-msg state side (s/strcat "uses " (:title card) " to gain 2 [Credits]")) (effect-completed state side eid)) (let [pre-purge-virus (number-of-virus-counters state)] (wait-for @@ -2448,7 +2449,7 @@ num-to-trash (quot num-virus-purged 3)] (wait-for (mill state :corp :runner num-to-trash) (system-msg state side - (str "uses " (:title card) " to purge " + (s/strcat "uses " (:title card) " to purge " (quantify num-virus-purged "virus counter") " and trash " (quantify num-to-trash "card") @@ -2513,7 +2514,7 @@ :change-in-game-state (req (pos? (count-bad-pub state))) :effect (req (let [bp-lost (max 0 (min (:agendapoints (last (:rfg corp))) (count-bad-pub state)))] - (system-msg state side (str "uses " (:title card) " to lose " bp-lost + (system-msg state side (s/strcat "uses " (:title card) " to lose " bp-lost " bad publicity and gain " bp-lost " [Credits]")) (if (pos? bp-lost) (wait-for (lose-bad-publicity state side bp-lost) @@ -2527,7 +2528,7 @@ (not (identity? target))))} :async true :effect (req (system-msg state side - (str "uses " (:title card) " to reveal " + (s/strcat "uses " (:title card) " to reveal " (enumerate-str (map :title (sort-by :title (:hand runner)))) " from the grip and trash any copies of " target)) (let [cards (filter #(= target (:title %)) (:hand runner))] @@ -2627,7 +2628,7 @@ :choices {:card #(and (installed? %) (runner? %)) :max 2} - :msg (msg (str "move " (enumerate-str (map :title targets)) " to the grip")) + :msg (msg (s/strcat "move " (enumerate-str (map :title targets)) " to the grip")) :effect (req (doseq [c targets] (move state :runner c :hand)))}}) @@ -2764,7 +2765,7 @@ {:optional {:player :runner :waiting-prompt true - :prompt (str "Take 1 tag to prevent " (:title c) " from being trashed?") + :prompt (s/strcat "Take 1 tag to prevent " (:title c) " from being trashed?") :yes-ability {:async true :msg (msg "take 1 tag to prevent " (:title c) @@ -2795,7 +2796,7 @@ {:async true :effect (req (wait-for (draw state side 3) - (system-msg state side (str "uses " (:title card) " to draw " + (system-msg state side (s/strcat "uses " (:title card) " to draw " (quantify (count async-result) "card"))) (continue-ability state side @@ -2958,7 +2959,7 @@ :effect (req (if (= (count targets) 2) (do (swap-ice state side (first targets) (second targets)) (system-msg state side - (str "uses " (:title card) " to swap " + (s/strcat "uses " (:title card) " to swap " (card-str state (first targets)) " with " (card-str state (second targets)))) @@ -3011,7 +3012,7 @@ :choices {:card-title (req (and (runner? target) (not (identity? target))))} :effect (effect (update! (assoc card :card-target target)) - (system-msg (str "uses " (:title card) " to name " target)))} + (system-msg (s/strcat "uses " (:title card) " to name " target)))} :events [(assoc gaincr :event :runner-install) (assoc gaincr :event :play-event)]})) @@ -3052,7 +3053,7 @@ {:player :runner :waiting-prompt true :prompt "Choose one" - :choices [(str "Add " (:title chosen) " to the top of the Stack") + :choices [(s/strcat "Add " (:title chosen) " to the top of the Stack") "Take 2 tags"] :async true :msg (msg "force the Runner to" (decapitalize target)) @@ -3073,7 +3074,7 @@ (wait-for (gain-tags state :corp (make-eid state eid) tags) (system-msg state side - (str "uses " (:title card) " to give the Runner " (quantify tags "tag"))) + (s/strcat "uses " (:title card) " to give the Runner " (quantify tags "tag"))) (effect-completed state nil eid))))}}}}) (defcard "Too Big to Fail" @@ -3152,7 +3153,7 @@ (continue-ability state side {:async true - :prompt (str "Choose a program with an install cost of no more than " + :prompt (s/strcat "Choose a program with an install cost of no more than " exceed " [Credits]") :choices {:card #(and (program? %) (installed? %) @@ -3168,7 +3169,7 @@ (in-discard? %))} :msg (msg "install and rez " (:title target) ", ignoring all costs") :async true - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid)) :effect (effect (corp-install eid target nil {:ignore-all-cost true :msg-keys {:install-source card @@ -3183,7 +3184,7 @@ (resource? %))} :async true :cancel-effect (effect - (system-msg (str "declines to use " (:title card) " to trash a resource")) + (system-msg (s/strcat "declines to use " (:title card) " to trash a resource")) (continue-ability ability card nil)) :effect (req (wait-for (trash state side target {:cause-card card}) (continue-ability state side ability card nil)))}})) @@ -3201,7 +3202,7 @@ :choices {:card #(and (in-hand? %) (corp? %) (not (operation? %)))} - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to install a card")) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to install a card")) (effect-completed eid)) :async true :effect (effect (corp-install eid target nil {:msg-keys {:install-source card @@ -3220,7 +3221,7 @@ :async true :effect (req (wait-for (trash state side target {:cause-card card}) (gain-bad-publicity state :corp eid 1))) - :cancel-effect (effect (system-msg (str "uses " (:title card) " to take 1 bad publicity")) + :cancel-effect (effect (system-msg (s/strcat "uses " (:title card) " to take 1 bad publicity")) (gain-bad-publicity eid 1))}}) (defcard "Violet Level Clearance" @@ -3261,14 +3262,14 @@ {:player :runner :waiting-prompt true :prompt "Choose one" - :choices [(str "Trash " (card-str state chosen)) + :choices [(s/strcat "Trash " (card-str state chosen)) "Suffer 4 meat damage"] :async true :effect (req (if (= target "Suffer 4 meat damage") (do (system-msg state side "suffers 4 meat damage") (damage state side eid :meat 4 {:card wake :unboostable true})) - (do (system-msg state side (str "trashes " (card-str state chosen))) + (do (system-msg state side (s/strcat "trashes " (card-str state chosen))) (trash state side eid chosen {:cause-card card :cause :forced-to-trash}))))}) card nil))}}) diff --git a/src/clj/game/cards/programs.clj b/src/clj/game/cards/programs.clj index 7071bd2755..6e236ef9d6 100644 --- a/src/clj/game/cards/programs.clj +++ b/src/clj/game/cards/programs.clj @@ -63,7 +63,8 @@ [game.core.virus :refer [get-virus-counters]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) (defn- power-counter-break "Only break ability uses power counters @@ -83,7 +84,7 @@ {:req (req (seq (filter #(has-subtype? % "Deva") (:hand runner)))) :label "Swap with a deva program from the grip" :cost [(->c :credit 2)] - :prompt (str "Choose a deva program to swap with " card-name) + :prompt (s/strcat "Choose a deva program to swap with " card-name) :choices {:card #(and (in-hand? %) (has-subtype? % "Deva"))} :msg (msg "swap in " (:title target) " from the grip") @@ -116,12 +117,12 @@ {:req (req (and (not-any? #(and (= title (:title %)) (get-in % [:special :heap-breaker-dont-install])) (all-active-installed state :runner)) - (not (get-in @state [:run :register (keyword (str "conspiracy-" title)) (:cid current-ice)])))) - :prompt (str "Install " title " from the heap?") + (not (get-in @state [:run :register (keyword (s/strcat "conspiracy-" title)) (:cid current-ice)])))) + :prompt (s/strcat "Install " title " from the heap?") :choices (req ["Yes" "No" (when (pos? (count (filter #(= title (:title %)) (all-active-installed state :runner)))) - (str "Don't ask again while " title " is installed"))]) + (s/strcat "Don't ask again while " title " is installed"))]) :async true :effect (req (continue-ability @@ -131,7 +132,7 @@ :effect (effect (runner-install :runner (assoc eid :source card :source-type :runner-install) card {:msg-keys {:install-source card :display-origin true}}))} ;; Add a register to note that the player was already asked about installing, ;; to prevent multiple copies from prompting multiple times. - (= target "No") {:effect (req (swap! state assoc-in [:run :register (keyword (str "conspiracy-" title)) (:cid current-ice)] true))} + (= target "No") {:effect (req (swap! state assoc-in [:run :register (keyword (s/strcat "conspiracy-" title)) (:cid current-ice)] true))} ;; mark that we never want to install this heap breaker while another copy is installed :else {:effect (req (let [heap-breakers (filter #(= title (:title %)) (all-active-installed state :runner))] @@ -145,9 +146,9 @@ [cost strength subtype] (merge (dissoc-req (break-sub cost strength subtype)) - {:label (str "add " strength " strength and " + {:label (s/strcat "add " strength " strength and " " break up to " - (quantify strength (str subtype " subroutine"))) + (quantify strength (s/strcat subtype " subroutine"))) :heap-breaker-pump strength ; strength gained :heap-breaker-break strength ; number of subs broken :cost cost @@ -227,7 +228,7 @@ [{:dynamic :auto-pump-and-break :cost total-cost :cost-label (build-cost-label total-cost) - :label (str "Match strength and fully break " + :label (s/strcat "Match strength and fully break " (:title current-ice))}]))) abs)))))}) @@ -248,9 +249,9 @@ (has-subtype? current-ice second-type) second-qty :else (throw (ex-info "What are we encountering?" current-ice)))) (hash-set first-type second-type) - {:label (str "break " - (quantify first-qty (str first-type " subroutine")) " or " - (quantify second-qty (str second-type " subroutine")))})) + {:label (s/strcat "break " + (quantify first-qty (s/strcat first-type " subroutine")) " or " + (quantify second-qty (s/strcat second-type " subroutine")))})) (defn- give-ice-subtype "Make currently encountered ice gain chosen type until end of encounter @@ -267,7 +268,7 @@ (effect (continue-ability {:optional - {:prompt (str "Pay " cost + {:prompt (s/strcat "Pay " cost " [Credits] to make " (:title (:ice context)) " gain " ice-type "?") :yes-ability @@ -290,7 +291,7 @@ (auto-icebreaker {:events [{:event :successful-run :silent (req true) - :effect (effect (system-msg (str "places 1 virus counter on " (:title card))) + :effect (effect (system-msg (s/strcat "places 1 virus counter on " (:title card))) (add-counter card :virus 1))}] :abilities [(break-sub [(->c :any-virus-counter 1)] 1 ice-type) (strength-pump [(->c :any-virus-counter 1)] 1)]})) @@ -314,7 +315,7 @@ (auto-icebreaker {:abilities [break pump - {:label (str "Derez " ice-type " being encountered") + {:label (s/strcat "Derez " ice-type " being encountered") :cost [(->c :credit 2) (->c :return-to-hand)] :req (req (and (get-current-encounter state) (rezzed? current-ice) @@ -330,7 +331,7 @@ (auto-icebreaker {:abilities [break pump - {:label (str "Bypass " ice-type " being encountered") + {:label (s/strcat "Bypass " ice-type " being encountered") :cost [(->c :trash-can)] :req (req (and (active-encounter? state) (has-subtype? current-ice ice-type))) @@ -727,7 +728,7 @@ (let [payment-str (:msg async-result)] (wait-for (reveal state side (make-eid state eid) cards) - (system-msg state side (str payment-str + (system-msg state side (s/strcat payment-str " to use " (:title card) " to force the Corp to reveal they drew " (enumerate-str (map :title cards)))) @@ -808,10 +809,10 @@ :req (req (same-card? (:ice context) (:host card))) :async true :effect (req (if (pos? (ice-strength state side (:ice context))) - (do (system-msg state side (str "uses " (:title card) " to place 1 virus counter on itself")) + (do (system-msg state side (s/strcat "uses " (:title card) " to place 1 virus counter on itself")) (add-counter state side card :virus 1) (effect-completed state side eid)) - (do (system-msg state side (str "uses " (:title card) " to trash " (card-str state (:ice context)))) + (do (system-msg state side (s/strcat "uses " (:title card) " to trash " (card-str state (:ice context)))) (trash state side eid (:ice context) {:cause-card card}))))}]}) (defcard "Cat's Cradle" @@ -876,7 +877,7 @@ :prompt (msg "Place 1 virus counter on " (:title card) "?") :yes-ability {:msg "place 1 virus counter on itself" :effect (effect (add-counter card :virus 1))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card) " to place 1 virus counter on itself")))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to place 1 virus counter on itself")))}}} {:event :successful-run :req (req (and (= :rd (target-server context)) this-card-run)) @@ -920,9 +921,9 @@ :msg (msg (let [local-virus (get-counters card :virus) global-virus (get-virus-counters state card) hivemind-virus (- global-virus local-virus)] - (str "gain " (* 2 global-virus) " [Credits], removing " (quantify local-virus "virus counter") " from itself" + (s/strcat "gain " (* 2 global-virus) " [Credits], removing " (quantify local-virus "virus counter") " from itself" (when (pos? hivemind-virus) - (str " (and " hivemind-virus " from Hivemind)")))))} + (s/strcat " (and " hivemind-virus " from Hivemind)")))))} (set-autoresolve :auto-place-counter "Consume placing virus counters on itself")]}) (defcard "Copycat" @@ -1089,7 +1090,7 @@ (system-msg state side "shuffles the stack") (effect-completed state side eid)) (do (host state side (get-card state card) target) - (system-msg state side (str "hosts " (:title target) " on Customized Secretary")) + (system-msg state side (s/strcat "hosts " (:title target) " on Customized Secretary")) (continue-ability state side (custsec-host (remove-once #(= % target) cards)) card nil))))}))] {:on-install {:async true @@ -1207,7 +1208,7 @@ :req (req (>= (get-virus-counters state card) 3)) :msg "look at the top card of R&D" :effect (effect (continue-ability - {:prompt (req (->> corp :deck first :title (str "The top card of R&D is "))) + {:prompt (req (->> corp :deck first :title (s/strcat "The top card of R&D is "))) :choices ["OK"]} card nil))}]}) @@ -1313,10 +1314,10 @@ (defcard "Equivocation" (let [force-draw (fn [title] {:optional - {:prompt (str "Force the Corp to draw " title "?") + {:prompt (s/strcat "Force the Corp to draw " title "?") :yes-ability {:async true - :effect (req (system-msg state :corp (str "is forced to draw " title)) + :effect (req (system-msg state :corp (s/strcat "is forced to draw " title)) (draw state :corp eid 1))}}}) rvl {:optional {:prompt "Reveal the top card of R&D?" @@ -1325,7 +1326,7 @@ :effect (req (let [topcard (-> corp :deck first :title)] (wait-for (reveal state side topcard) - (system-msg state :runner (str "reveals " topcard + (system-msg state :runner (s/strcat "reveals " topcard " from the top of R&D")) (continue-ability state side (force-draw topcard) card nil))))}}}] {:events [{:event :successful-run @@ -1393,9 +1394,9 @@ :waiting-prompt true :player :corp :choices (req [(when (can-pay? state :runner eid card nil [(->c :credit (rez-cost state side ice))]) - (str "Rez " (get-title ice))) - (str "Add " (get-title ice) " to HQ")]) - :effect (req (if (= target (str "Rez " (get-title ice))) + (s/strcat "Rez " (get-title ice))) + (s/strcat "Add " (get-title ice) " to HQ")]) + :effect (req (if (= target (s/strcat "Rez " (get-title ice))) (rez state side eid ice) (do (system-msg state :corp "adds the passed piece of ice to HQ") (move state :corp ice :hand) @@ -1423,7 +1424,7 @@ :effect (req (let [ice target] (add-icon state side card ice "FF" (faction-label card)) (system-msg state side - (str "selects " (card-str state ice) + (s/strcat "selects " (card-str state ice) " for " (:title card) "'s bypass ability")) (register-events state side card @@ -1438,7 +1439,7 @@ :effect (req (wait-for (pay state side (make-eid state eid) card [(->c :credit (count (:subroutines (get-card state ice))))]) (let [payment-str (:msg async-result) - msg-ab {:msg (str "bypass " (:title (:ice context)))}] + msg-ab {:msg (s/strcat "bypass " (:title (:ice context)))}] (print-msg state side msg-ab card nil payment-str)) (bypass-ice state) (effect-completed state side eid)))}}}])))} @@ -1454,7 +1455,7 @@ :req (req (pos? (get-virus-counters state card))) :cost [(->c :click 1) (->c :trash-can)] :label "Gain 2 [Credits] for each hosted virus counter" - :msg (msg (str "gain " (* 2 (get-virus-counters state card)) " [Credits]")) + :msg (msg (s/strcat "gain " (* 2 (get-virus-counters state card)) " [Credits]")) :async true :effect (effect (gain-credits eid (* 2 (get-virus-counters state card))))}]}) @@ -1502,7 +1503,7 @@ (if (not (get-in @state [:tag :tag-prevent])) (do (add-counter state side card :virus 2) (system-msg state side - (str "takes 1 tag to place 2 virus counters on God of War")) + (s/strcat "takes 1 tag to place 2 virus counters on God of War")) (effect-completed state side eid)) (effect-completed state side eid))))}]})) @@ -1807,7 +1808,7 @@ (continue-ability (let [ice (:ice context)] {:optional - {:prompt (str "Swap " (:title ice) " with another ice?") + {:prompt (s/strcat "Swap " (:title ice) " with another ice?") :yes-ability {:prompt "Choose another ice" :choices {:card #(and (installed? %) @@ -2264,7 +2265,7 @@ :async true :effect (req (when (= :deck where) (trigger-event state side :searched-stack) - (system-msg state side (str "uses " (:title card) " to shuffle the stack")) + (system-msg state side (s/strcat "uses " (:title card) " to shuffle the stack")) (shuffle! state side :deck)) (let [msg-keys {:install-source card :display-origin true}] @@ -2380,7 +2381,7 @@ :effect (effect (continue-ability (sabotage-ability 1) card nil))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :abilities [(set-autoresolve :auto-fire "Nga")]}) (defcard "Ninja" @@ -2584,7 +2585,7 @@ (runner-install state side eid target {:ignore-all-cost true :msg-keys {:display-origin true :install-source card}}))) - :cancel-effect (req (system-msg state side (str "uses Pawn to trash itself")) + :cancel-effect (req (system-msg state side (s/strcat "uses Pawn to trash itself")) (trash state side eid card {:cause-card card :unpreventable true}))} card nil)))}] @@ -2650,10 +2651,10 @@ (continue-ability (let [fired-subs (count (filter :fired (:subroutines (:ice context))))] {:optional - {:prompt (str "Trash the top card of the stack to trash " (quantify fired-subs "card") " from R&D?") + {:prompt (s/strcat "Trash the top card of the stack to trash " (quantify fired-subs "card") " from R&D?") :yes-ability {:async true - :msg (msg (str "trash " (:title (first (:deck runner))) + :msg (msg (s/strcat "trash " (:title (first (:deck runner))) " from the stack and" " trash " (quantify fired-subs "card") " from R&D")) :effect (req (wait-for (mill state :runner :runner 1) @@ -2689,7 +2690,7 @@ :effect (req (wait-for (pay state side (make-eid state eid) card [(->c :credit (count (:subroutines (get-card state current-ice))))]) (let [payment-str (:msg async-result) - msg-ab {:msg (str "bypass " (card-str state (:ice context)))}] + msg-ab {:msg (s/strcat "bypass " (card-str state (:ice context)))}] (print-msg state side msg-ab card nil payment-str)) (bypass-ice state) (effect-completed state side eid)))}}}]}) @@ -2715,13 +2716,13 @@ (continue-ability state side {:optional - {:prompt (str "Is " (:title card) " added to the grip?") + {:prompt (s/strcat "Is " (:title card) " added to the grip?") :waiting-prompt true :yes-ability {:msg "appease the rules" :cost [(->c :return-to-hand)]}}} card nil) (effect-completed state side eid)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}]}) + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}]}) (defcard "Pipeline" (auto-icebreaker {:abilities [(break-sub 1 1 "Sentry") @@ -2742,7 +2743,7 @@ (defcard "Pressure Spike" (letfn [(once [card] {:once :per-run - :once-key (str (:cid card) "-thread-pump")})] + :once-key (s/strcat (:cid card) "-thread-pump")})] {:implementation "Auto-breaking disabled for this card." :abilities [(break-sub 1 1 "Barrier") (strength-pump 2 3) @@ -2991,7 +2992,7 @@ :effect (req (trigger-event state side :searched-stack) (shuffle! state side :deck) (if (= target "Done") - (do (system-msg state side (str (:latest-payment-str eid) " to shuffle the Stack")) + (do (system-msg state side (s/strcat (:latest-payment-str eid) " to shuffle the Stack")) (effect-completed state side eid)) (runner-install state side (assoc eid :source card :source-type :runner-install) target {:msg-keys {:install-source card :display-origin true @@ -3132,8 +3133,8 @@ 2 "bottom " "this-should-not-happen ")] (if (= 1 (count (filter #{(:title target)} card-titles))) - (str "trash " (:title target)) - (str "trash " position (:title target))))) + (s/strcat "trash " (:title target)) + (s/strcat "trash " position (:title target))))) :effect (effect (trash :runner eid (assoc target :seen true) {:cause-card card}))} card nil)))}})] {:abilities [{:action true @@ -3240,7 +3241,7 @@ :unregister-once-resolved true :req (req true) :effect (req (update-current-encounter state :prevent-subroutine true)) - :msg (msg (str "prevent a subroutine (" (:label target) ") from resolving"))}] + :msg (msg (s/strcat "prevent a subroutine (" (:label target) ") from resolving"))}] {:abilities [{:action true :label "Make a run on targeted server" :cost [(->c :click 1) (->c :credit 2)] @@ -3306,7 +3307,7 @@ (>= (get-virus-counters state card) 5) (not (and (card-flag? h :untrashable-while-rezzed true) (rezzed? h)))) - (do (system-msg state :runner (str "uses " (:title card) " to trash " (card-str state h))) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to trash " (card-str state h))) (unregister-events state side card) (trash state :runner eid h {:cause-card card})) (effect-completed state side eid))))] @@ -3444,12 +3445,12 @@ {:choices {:card #(and (ice? %) (not (rezzed? %)))} :async true - :msg (str "name " chosen-subtype) + :msg (s/strcat "name " chosen-subtype) :effect (req (wait-for (expose state side target) (when (has-subtype? async-result chosen-subtype) (do (move state :corp async-result :hand) (system-msg state :runner - (str "add " (:title async-result) " to HQ")))) + (s/strcat "add " (:title async-result) " to HQ")))) (effect-completed state side eid)))})] {:events [{:event :successful-run :interactive (req true) @@ -3469,7 +3470,7 @@ :req (req (not (install-locked? state side))) :msg (msg (if (= target "Done") "shuffle the stack" - (str "install " (:title target) " from the stack, paying 3 [Credits] less"))) + (s/strcat "install " (:title target) " from the stack, paying 3 [Credits] less"))) :choices (req (concat (->> (:deck runner) (filter @@ -3495,7 +3496,7 @@ :req (req (and (runner? target) (installed? target)))} :msg (msg "trash " (:title target)) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (req (let [facedown-target (facedown? target)] diff --git a/src/clj/game/cards/resources.clj b/src/clj/game/cards/resources.clj index 27bc4ff472..338871dd8d 100644 --- a/src/clj/game/cards/resources.clj +++ b/src/clj/game/cards/resources.clj @@ -84,7 +84,8 @@ [game.utils :refer :all] [jinteki.utils :refer :all] [jinteki.validator :refer [legal?]] - [medley.core :refer [find-first]])) + [medley.core :refer [find-first]] + [stringer.core :as s])) (defn- genetics-trigger? "Returns true if Genetics card should trigger - does not work with Adjusted Chronotype" @@ -129,7 +130,7 @@ (defn bitey-boi [f] (let [selector (resolve f) - descriptor (str f)] + descriptor (s/strcat f)] {:abilities [{:req (req (and (get-current-encounter state) (rezzed? current-ice) (not (:broken (selector (:subroutines current-ice)))))) @@ -137,7 +138,7 @@ :breaks "All" :break-cost [(->c :trash-can)] :cost [(->c :trash-can)] - :label (str "Break the " descriptor " subroutine") + :label (s/strcat "Break the " descriptor " subroutine") :msg (msg "break the " descriptor " subroutine on " (:title current-ice) " (\"[subroutine] " (:label (selector (:subroutines current-ice))) "\")") :effect (req (break-subroutine! state current-ice (selector (:subroutines current-ice))))}]})) @@ -164,14 +165,14 @@ :async true :effect (req (if (zero? (count-tags state)) (do (gain-tags state :runner eid 1) - (system-msg state :runner (str "uses " (:title card) " to take 1 tag"))) + (system-msg state :runner (s/strcat "uses " (:title card) " to take 1 tag"))) (effect-completed state :runner eid)))} {:event :runner-turn-begins :async true :effect (req (if (not (has-bad-pub? state)) (do (gain-bad-publicity state :corp eid 1) (system-msg state :runner - (str "uses " (:title card) " to give the corp 1 bad publicity"))) + (s/strcat "uses " (:title card) " to give the corp 1 bad publicity"))) (effect-completed state :runner eid)))}]}) (defcard "Adjusted Chronotype" @@ -192,9 +193,9 @@ :req (req (and (:trash (second targets)) (not (in-discard? target)))) :prompt "Gain 1 [Credits] and reveal accessed card?" - :yes-ability {:msg (msg (str "gain 1 [Credits]" + :yes-ability {:msg (msg (s/strcat "gain 1 [Credits]" (when-not (installed? target) - (str " and reveal " (:title target))))) + (s/strcat " and reveal " (:title target))))) :async true :effect (effect (gain-credits eid 1))}}}] :abilities [(set-autoresolve :auto-fire "Aeneas Informant")]}) @@ -208,7 +209,7 @@ :req (req (and (runner? target) (installed? target)))} :msg (msg "trash " (:title target) " and gain 3 [Credits]") - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid)) :effect (req (wait-for (trash state side target {:unpreventable true :cause-card card}) (gain-credits state side eid 3)))}] @@ -351,7 +352,7 @@ (trash-if-empty [state side eid card] (if-not (empty? (:hosted (get-card state card))) (effect-completed state side eid) - (do (system-msg state side (str "trashes " (get-title card))) + (do (system-msg state side (s/strcat "trashes " (get-title card))) (trash state side eid card {:unpreventable true :source-card card}))))] {:on-install {:msg "shuffle the stack" :async true @@ -368,7 +369,7 @@ :choices {:req (req (same-card? card (:host target)))} :msg (msg "add " (get-title target) " to the grip") :once :per-turn - :cancel-effect (req (system-msg state side (str "declines to use " (get-title card))) + :cancel-effect (req (system-msg state side (s/strcat "declines to use " (get-title card))) (trash-if-empty state side eid card)) :async true :waiting-prompt true @@ -521,15 +522,15 @@ (cond ;; gain 1 credit (<= 5 c 9) - (do (system-msg state side (str "uses " b " to gain 1 [Credits]")) + (do (system-msg state side (s/strcat "uses " b " to gain 1 [Credits]")) (gain-credits state side eid 1)) ;; draw 1 card (<= 10 c 14) - (do (system-msg state side (str "uses " b " to draw 1 card")) + (do (system-msg state side (s/strcat "uses " b " to draw 1 card")) (draw state side eid 1)) ;; gain 1 click (<= 15 c) - (do (system-msg state side (str "uses " b " to gain [Click]")) + (do (system-msg state side (s/strcat "uses " b " to gain [Click]")) (gain-clicks state side 1) (effect-completed state side eid)) :else (effect-completed state side eid))))}] @@ -656,7 +657,7 @@ (wait-for (pay state :runner (make-eid state eid) card [(->c :credit (get-strength ice))]) (if-let [payment-str (:msg async-result)] (do (system-msg state :runner - (str (build-spend-msg payment-str "use") + (s/strcat (build-spend-msg payment-str "use") (:title card) " to bypass " (:title ice))) (register-events state :runner card @@ -666,7 +667,7 @@ :effect (req (bypass-ice state))}]) (effect-completed state side eid)) (do (system-msg state :runner - (str "can't afford to pay to bypass " (:title ice))) + (s/strcat "can't afford to pay to bypass " (:title ice))) (effect-completed state side eid))))))}}}]) (make-run eid target card))}]}) @@ -742,9 +743,9 @@ :choices {:card #(and (= (last (get-zone %)) :ices) (= chosen-server (rest (butlast (get-zone %)))))} :async true - :effect (effect (system-msg (str "trashes " (card-str state target))) + :effect (effect (system-msg (s/strcat "trashes " (card-str state target))) (trash :corp eid target {:unpreventable true :cause-card card :cause :forced-to-trash})) - :cancel-effect (effect (system-msg (str "declines to trash a piece of ice protecting " (zone->name chosen-server))) + :cancel-effect (effect (system-msg (s/strcat "declines to trash a piece of ice protecting " (zone->name chosen-server))) (register-events :runner card [{:event :breach-server @@ -855,7 +856,7 @@ card nil))} card targets) ;; Can't pay, don't access cards - (do (system-msg state :runner (str "could not afford to use " (:title card))) + (do (system-msg state :runner (s/strcat "could not afford to use " (:title card))) (effect-completed state nil eid)))))}})] {:abilities [{:action true :cost [(->c :click 1) (->c :trash-can)] @@ -891,7 +892,7 @@ (wait-for (gain-credits state :runner 1) (if (not (pos? (get-counters (get-card state card) :credit))) (wait-for (trash state :runner card {:unpreventable true :cause-card card}) - (system-msg state :runner (str "trashes Crowdfunding" + (system-msg state :runner (s/strcat "trashes Crowdfunding" (when (seq (:deck runner)) " and draws 1 card"))) (draw state :runner eid 1)) @@ -1259,9 +1260,9 @@ (defcard "Dummy Box" (letfn [(better-name [card-type] (if (= "hardware" card-type) "piece of hardware" card-type)) (dummy-prevent [card-type] - {:msg (str "prevent a " (better-name card-type) " from being trashed") + {:msg (s/strcat "prevent a " (better-name card-type) " from being trashed") :async true - :cost [(->c (keyword (str "trash-" card-type "-from-hand")) 1)] + :cost [(->c (keyword (s/strcat "trash-" card-type "-from-hand")) 1)] :effect (effect (trash-prevent (keyword card-type) 1))})] {:interactions {:prevent [{:type #{:trash-hardware :trash-resource :trash-program} :req (req (and (installed? (:prevent-target target)) @@ -1307,7 +1308,7 @@ :silent (req true) :async true :effect (req (let [target (first (shuffle (:hand corp)))] - (system-msg state :runner (str "uses " (:title card) " to force the Corp to reveal " (:title target) " from HQ")) + (system-msg state :runner (s/strcat "uses " (:title card) " to force the Corp to reveal " (:title target) " from HQ")) (reveal state :corp eid target))) :req (req (genetics-trigger? state side :successful-run))}]}) @@ -1412,7 +1413,7 @@ (defcard "Film Critic" (letfn [(get-agenda [card] (first (filter agenda? (:hosted card)))) (host-agenda? [agenda] - {:optional {:prompt (str "Host " (:title agenda) " on Film Critic?") + {:optional {:prompt (s/strcat "Host " (:title agenda) " on Film Critic?") :yes-ability {:effect (req (host state side card agenda) (swap! state dissoc :access)) :msg (msg "host " (:title agenda) " instead of accessing it")}}})] @@ -1428,7 +1429,7 @@ :req (req (get-agenda card)) :async true :msg (msg (let [c (get-agenda card)] - (str "add " (:title c) " to [their] score area and gain " + (s/strcat "add " (:title c) " to [their] score area and gain " (quantify (get-agenda-points c) "agenda point")))) :effect (req (let [c (move state :runner (get-agenda card) :scored)] (when (card-flag? c :has-events-when-stolen true) @@ -1464,7 +1465,7 @@ (-> @state :corp :deck count pos?))) :autoresolve (get-autoresolve :auto-peek) :prompt "Look at the top card of R&D?" - :yes-ability {:prompt (req (->> corp :deck first :title (str "The top card of R&D is "))) + :yes-ability {:prompt (req (->> corp :deck first :title (s/strcat "The top card of R&D is "))) :msg "look at the top card of R&D" :choices ["OK"]}}}] :abilities [(set-autoresolve :auto-peek "Find the Truth looking at the top card of R&D")] @@ -1472,7 +1473,7 @@ :prompt "Explicitly reveal cards the Runner draws?" :choices ["Yes" "No"] :effect (effect (update! (assoc-in card [:special :explicit-reveal](keyword (str/lower-case target)))) - (toast (str "From now on, " (:title card) " will " + (toast (s/strcat "From now on, " (:title card) " will " (when (= target "No") "Not") "explicitly reveal cards the Runner draws") "info"))}]}) @@ -1539,7 +1540,7 @@ :autoresolve (get-autoresolve :auto-fire) :yes-ability {:msg "lose [Click] and look at the top card of R&D" - :prompt (req (->> corp :deck first :title (str "The top card of R&D is "))) + :prompt (req (->> corp :deck first :title (s/strcat "The top card of R&D is "))) :choices ["OK"] :effect (effect (lose-clicks 1))}}}] {:req (req (< 1 (get-link state))) @@ -1672,10 +1673,10 @@ (continue-ability state side {:optional {:prompt (msg "Prevent a \"when encountered\" ability on " (:title current-ice) (when (:ability-name target) - (str " (" (:ability-name target) ")"))) + (s/strcat " (" (:ability-name target) ")"))) :once :per-turn :yes-ability {:msg (msg "prevent the encounter ability on " (:title current-ice) (when (:ability-name target) - (str " (" (:ability-name target) ")"))) + (s/strcat " (" (:ability-name target) ")"))) :effect (req (swap! state assoc-in [:run :prevent-encounter-ability] true))}}} card targets)))}] :abilities [(letfn [(ri [cards] @@ -1721,7 +1722,7 @@ :req (req (first-event? state side :run-ends #(is-mark? state (target-server (first %))))) :effect (req (if (first-event? state side :end-breach-server #(is-mark? state (:from-server (first %)))) - (do (system-msg state :runner (str "uses " (:title card) " to gain 2 [Credits]")) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to gain 2 [Credits]")) (gain-credits state :runner eid 2)) (effect-completed state side eid)))}]}) @@ -1752,7 +1753,7 @@ (wait-for (reveal state :corp (make-eid state eid) targets) (system-msg state side - (str "uses " (:title card) " to reveal " cards " from " target)) + (s/strcat "uses " (:title card) " to reveal " cards " from " target)) (effect-completed state side eid))))}]}) (defcard "Jackpot!" @@ -1774,7 +1775,7 @@ :choices {:number (req (get-counters card :credit))} :async true :effect (req (wait-for (gain-credits state :runner target) - (system-msg state :runner (str "trashes " (:title card) " to gain " target " [Credits]")) + (system-msg state :runner (s/strcat "trashes " (:title card) " to gain " target " [Credits]")) (trash state :runner eid card {:cause-card card})))}}}]}) (defcard "Jak Sinclair" @@ -1837,7 +1838,7 @@ :once :per-turn :yes-ability ability :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card) " to gain [Click]")) + {:effect (effect (system-msg (s/strcat "declines to use " (:title card) " to gain [Click]")) (update! (assoc-in card [:special :joshua-b] false)))}}} {:event :runner-turn-ends :interactive (req true) @@ -1876,7 +1877,7 @@ :yes-ability {:msg "place 1 power counter on itself" :async true :effect (req (add-counter state side eid card :power 1 {:placed true}))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}} {:event :counter-added :req (req (<= 4 (get-counters (get-card state card) :power))) :msg "add itself to [their] score area as an agenda worth 1 agenda point" @@ -1919,14 +1920,14 @@ (first-event? state side :corp-install #(and (not (ice? (:card (first %)))) (not (condition-counter? (:card (first %)))))))) :yes-ability {:msg (msg (if (seq (:deck runner)) - (str "trash " + (s/strcat "trash " (:title (first (:deck runner))) " from the stack and draw 1 card") "trash no cards from the stack (it is empty)")) :async true :effect (req (wait-for (mill state :runner :runner 1) (draw state :runner eid 1)))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}] + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}] :abilities [(set-autoresolve :auto-fire "Lago Paranoá Shelter")]}) (defcard "Laguna Velasco District" @@ -1941,8 +1942,8 @@ :choices (concat (filter program? cards) ["None"]) :async true :effect (req (if (= "None" target) - (system-msg state side (str "declines to use " (get-title card) " to add a program from the top of the stack to the grip")) - (do (system-msg state side (str "uses " (get-title card) " to add " (-> target :title) " from the top of the stack to the grip")) + (system-msg state side (s/strcat "declines to use " (get-title card) " to add a program from the top of the stack to the grip")) + (do (system-msg state side (s/strcat "uses " (get-title card) " to add " (-> target :title) " from the top of the stack to the grip")) (move state side target :hand))) (continue-ability state side @@ -2055,7 +2056,7 @@ :msg (msg "bypass " (:title current-ice) (when (pos? (:click runner)) - (str " and loses " + (s/strcat " and loses " (apply str (repeat (:click runner) "[Click]"))))) :cost [(->c :trash-can)] :effect (req (bypass-ice state) @@ -2153,7 +2154,7 @@ :prompt "Look at the top card of the stack?" :autoresolve (get-autoresolve :auto-fire) :yes-ability - {:prompt (req (->> runner :deck first :title (str "The top card of the stack is "))) + {:prompt (req (->> runner :deck first :title (s/strcat "The top card of the stack is "))) :msg "look at the top card of the stack" :choices ["OK"]}}}] {:flags {:runner-turn-draw true @@ -2201,7 +2202,7 @@ :prompt "Choose a card to rez, ignoring the rez cost" :choices {:card (complement rezzed?)} :async true - :effect (effect (system-msg :corp (str "uses " (:title card) " to rez " (:title target) " at no cost")) + :effect (effect (system-msg :corp (s/strcat "uses " (:title card) " to rez " (:title target) " at no cost")) (rez eid target {:ignore-cost :rez-cost :no-msg true}))} card nil)) :abilities [{:cost [(->c :trash-can)] @@ -2330,11 +2331,11 @@ (event-count state side :pre-damage #(= :net (:type (first %))))) 2)) (start-trace [type] - (let [message (str "avoid any " (if (= type :net) + (let [message (s/strcat "avoid any " (if (= type :net) "amount of net damage" "number of tags"))] {:player :corp - :label (str "Trace 0 - if unsuccessful, " message) + :label (s/strcat "Trace 0 - if unsuccessful, " message) :trace {:base 0 :unsuccessful {:async true :msg message @@ -2376,16 +2377,16 @@ :choices ["Event" "Hardware" "Program" "Resource"] :async true :effect (req (let [c (first (get-in @state [:runner :deck]))] - (system-msg state side (str "uses " (:title card) " to name " target + (system-msg state side (s/strcat "uses " (:title card) " to name " target " and reveal " (:title c) " from the top of the stack")) (wait-for (reveal state side c) (if (is-type? c target) - (do (system-msg state side (str "gains 2 [Credits] and draws " (:title c))) + (do (system-msg state side (s/strcat "gains 2 [Credits] and draws " (:title c))) (wait-for (gain-credits state side 2) (draw state side eid 1))) - (do (system-msg state side (str "trashes " (:title c))) + (do (system-msg state side (s/strcat "trashes " (:title c))) (mill state side eid :runner 1))))))}]}) (defcard "Order of Sol" @@ -2420,9 +2421,9 @@ (defcard "Paige Piper" (letfn [(pphelper [title cards] {:optional - {:prompt (str "Search the stack for additional copies of " title "?") + {:prompt (s/strcat "Search the stack for additional copies of " title "?") :yes-ability - {:prompt (str "How many copies of " title " would you like to get?") + {:prompt (s/strcat "How many copies of " title " would you like to get?") :choices (take (inc (count cards)) ["0" "1" "2" "3" "4" "5"]) :msg "shuffle the stack" :async true @@ -2430,7 +2431,7 @@ (trigger-event state side :searched-stack) (shuffle! state :runner :deck) (when (pos? target) - (system-msg state side (str "adds " + (system-msg state side (s/strcat "adds " (quantify target "cop" "y" "ies") " of " title " to the heap"))) (trash-cards state side eid (take target cards) {:unpreventable true :cause-card card})))}}})] @@ -2608,7 +2609,7 @@ (pay state :runner (make-eid state eid) card [(->c :credit target)]) (if-let [payment-str (:msg async-result)] (do (system-msg state side - (str (build-spend-msg payment-str "use") (:title card) + (s/strcat (build-spend-msg payment-str "use") (:title card) " to remove " (quantify target "power counter") " from " (:title paydowntarget))) (if (= num-counters target) @@ -2778,7 +2779,7 @@ card nil))} :on-trash {:async true :effect (req (system-msg state :runner - (str "trashes " + (s/strcat "trashes " (enumerate-str (map :title (take 3 (:deck runner)))) " from the stack due to " (:title card) " being trashed")) (mill state :runner eid :runner 3))}}) @@ -2812,7 +2813,7 @@ :effect (req (trigger-event state side :searched-stack) (shuffle! state side :deck) (if (= target "Done") - (do (system-msg state side (str (:latest-payment-str eid) " to use " (:title card) " to shuffle the Stack")) + (do (system-msg state side (s/strcat (:latest-payment-str eid) " to use " (:title card) " to shuffle the Stack")) (effect-completed state side eid)) (runner-install state side (assoc eid :source card :source-type :runner-install) target {:msg-keys {:display-origin true @@ -2831,7 +2832,7 @@ (filter #(not (has-subtype? % "Virtual")) (get-in runner [:rig :resource])) (:hand runner))] - (str "prevent all damage, trash " + (s/strcat "prevent all damage, trash " (quantify (count cards) "card") " (" (enumerate-str (map :title cards)) ")," " lose " (quantify (:credit (:runner @state)) "credit") @@ -2863,7 +2864,7 @@ :events [{:event :runner-turn-ends :async true :effect (req (if (< (count (:hand runner)) (hand-size state :runner)) - (do (system-msg state :runner (str "uses " (:title card) " to draw 1 card")) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to draw 1 card")) (draw state :runner eid 1)) (effect-completed state :runner eid)))}]}) @@ -2884,7 +2885,7 @@ (let [payment-str (:msg async-result) card (move state :corp target :rfg)] (system-msg state side - (str payment-str + (s/strcat payment-str " and remove " (:title target) " from the game")) (complete-with-result state side eid card)))))}}}) @@ -3029,7 +3030,7 @@ (system-msg state side "takes 1 core damage from Stim Dealer")) (do (add-counter state side card :power 1) (gain-clicks state side 1) - (system-msg state side (str "uses " (:title card) " to gain [Click]")))))}]}) + (system-msg state side (s/strcat "uses " (:title card) " to gain [Click]")))))}]}) (defcard "Stoneship Chart Room" {:abilities [{:label "Draw 2 cards" @@ -3209,7 +3210,7 @@ (has-subtype? (:card context) "Security"))) :unsuccessful {:effect (effect (gain-bad-publicity :corp 1) - (system-msg :corp (str "takes 1 bad publicity")))}}}]}) + (system-msg :corp (s/strcat "takes 1 bad publicity")))}}}]}) (defcard "The Artist" {:abilities [{:action true @@ -3251,10 +3252,10 @@ ; (not (used-this-turn? (:cid card) state)))) ; :once :per-turn ; :async true - ; :effect (effect (system-msg (str "places 1 power counter on " (:title card))) + ; :effect (effect (system-msg (s/strcat "places 1 power counter on " (:title card))) ; (add-counter card :power 1))}] :abilities [{:label "Manually place 1 power counter" - :effect (effect (system-msg (str "manually places 1 power counter on " (:title card))) + :effect (effect (system-msg (s/strcat "manually places 1 power counter on " (:title card))) (add-counter card :power 1))} {:action true :label "Shuffle back cards with [Trash] abilities" @@ -3313,7 +3314,7 @@ :all true} :effect (req (system-msg state side - (str "uses " (:title card) " to add the " + (s/strcat "uses " (:title card) " to add the " (pprint/cl-format nil "~:R" (inc (first (keep-indexed #(when (same-card? target %2) %1) cards)))) " card on the top of the stack to the bottom")) @@ -3374,7 +3375,7 @@ :async true :msg (msg (if (= target "The Runner draws 2 cards") "draw 2 cards" - (str "force the Corp to " (decapitalize target)))) + (s/strcat "force the Corp to " (decapitalize target)))) :effect (req (if (= target "The Runner draws 2 cards") (draw state :runner eid 2) (mill state :corp eid :corp 1)))} @@ -3387,7 +3388,7 @@ :async true :effect (req (wait-for (resolve-ability state side (pick-virus-counters-to-spend 2) card nil) (if (:msg async-result) - (do (system-msg state side (str "spends " (:msg async-result))) + (do (system-msg state side (s/strcat "spends " (:msg async-result))) (continue-ability state side corp-choice card nil)) (effect-completed state side eid))))}}}] {:events [maybe-spend-2 @@ -3470,7 +3471,7 @@ (defcard "The Turning Wheel" (letfn [(ttw-ab [name server] - {:label (str "Access an additional card in " name) + {:label (s/strcat "Access an additional card in " name) :cost [(->c :power 2)] :req (req run) :keep-menu-open :while-2-power-tokens-left @@ -3479,7 +3480,7 @@ card [(breach-access-bonus server 1 {:duration :end-of-run})]))}) (ttw-bounce [name server] {:action true - :label (str "Shortcut: Bounce " name) + :label (s/strcat "Shortcut: Bounce " name) :cost [(->c :click 1)] :keep-menu-open :while-clicks-left :msg (msg "bounce off of " name " for a token (shortcut)") @@ -3494,7 +3495,7 @@ :effect (req (when (and (not (:agenda-stolen card)) (#{:hq :rd} (target-server target))) (add-counter state side card :power 1) - (system-msg state :runner (str "uses " (:title card) " to place 1 power counter on itself"))) + (system-msg state :runner (s/strcat "uses " (:title card) " to place 1 power counter on itself"))) (update! state side (dissoc (get-card state card) :agenda-stolen))) :silent (req true)}] :abilities [(ttw-ab "R&D" :rd) @@ -3665,7 +3666,7 @@ :async true :effect (req (if (and (<= 2 (get-link state)) (:runner-phase-12 @state)) - (do (system-msg state :runner (str "uses " (:title card) " to gain 1 [Credits]")) + (do (system-msg state :runner (s/strcat "uses " (:title card) " to gain 1 [Credits]")) (gain-credits state :runner eid 1)) (effect-completed state side eid)))}] {:flags {:drip-economy true} @@ -3685,7 +3686,7 @@ (installed? target) (is-eligible? target)))} :msg (msg "add " (:title target) " to the grip and place 2 [Credits] on itself") - :cancel-effect (req (system-msg state :runner (str "declines to use " (:title card))) + :cancel-effect (req (system-msg state :runner (s/strcat "declines to use " (:title card))) (effect-completed state side eid)) :effect (req (move state side target :hand) (add-counter state side card :credit 2) @@ -3712,10 +3713,10 @@ :async true :effect (req (cond (= "Remove 1 tag" target) (do (lose-tags state :runner eid 1) - (system-msg state :runner (str "uses " (:title card) + (system-msg state :runner (s/strcat "uses " (:title card) " to " (decapitalize target)))) (= "Gain 2 [Credits]" target) (do (gain-credits state :runner eid 2) - (system-msg state :runner (str "uses " (:title card) + (system-msg state :runner (s/strcat "uses " (:title card) " to " (decapitalize target)))) :else (effect-completed state side eid)))} :events [{:event :runner-lose-tag @@ -3770,7 +3771,7 @@ :prompt "Name an agenda" :choices {:card-title (req (and (corp? target) (agenda? target)))} - :effect (effect (system-msg (str "trashes " (:title card) + :effect (effect (system-msg (s/strcat "trashes " (:title card) " to use " (:title card) " to name " (:title target))) (register-events @@ -3809,10 +3810,10 @@ :prompt (msg "Draw " (:title (first (:deck corp))) "?") :yes-ability {:async true - :effect (effect (system-msg (str "draws " (:title (first (:deck corp))))) + :effect (effect (system-msg (s/strcat "draws " (:title (first (:deck corp))))) (draw eid 1))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}} + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}} card nil)))}] {:events [(assoc ability :event :runner-turn-begins)] :abilities [ability]})) @@ -3827,7 +3828,7 @@ :effect (req (lose-clicks state side 1) (if (get-in @state [:per-turn (:cid card)]) (effect-completed state side eid) - (do (system-msg state side (str "uses " (:title card) " to draw 2 cards and lose [Click]")) + (do (system-msg state side (s/strcat "uses " (:title card) " to draw 2 cards and lose [Click]")) (draw state side eid 2))))}] :abilities [{:msg "draw 2 cards and lose [Click]" :once :per-turn diff --git a/src/clj/game/cards/upgrades.clj b/src/clj/game/cards/upgrades.clj index ea8d881f24..cde3e932b1 100644 --- a/src/clj/game/cards/upgrades.clj +++ b/src/clj/game/cards/upgrades.clj @@ -1,6 +1,5 @@ (ns game.cards.upgrades (:require - [clojure.string :as str] [cond-plus.core :refer [cond+]] [game.core.access :refer [access-bonus set-only-card-to-access installed-access-trigger @@ -56,7 +55,8 @@ [game.core.update :refer [update!]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer :all] - [jinteki.utils :refer :all])) + [jinteki.utils :refer :all] + [stringer.core :as s])) ;; Helpers (defn mobile-sysop-event @@ -110,7 +110,7 @@ :async true :effect (req (if (:did-steal context) (do (gain-tags state :corp eid 2) - (system-msg state :corp (str "uses " (:title card) " to give the Runner 2 tags"))) + (system-msg state :corp (s/strcat "uses " (:title card) " to give the Runner 2 tags"))) (effect-completed state side eid)))}] {:events [ability] :on-trash @@ -143,7 +143,7 @@ {:req (req (rezzed? card)) :waiting-prompt true :prompt (msg "Pay 2 [Credits] to use " (:title card) " ability?") - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))} + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))} :yes-ability {:async true :cost [(->c :credit 2)] :msg "do 2 meat damage" @@ -231,7 +231,7 @@ :effect (effect (trash eid (get-card state ice) {:cause-card card}))}]) (force-ice-encounter state side eid ice))))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}}]}) + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}]}) (defcard "Bamboo Dome" {:install-req (req (filter #{"R&D"} targets)) @@ -239,7 +239,7 @@ :cost [(->c :click 1)] :req (req (pos? (count (:deck corp)))) :async true - :msg (msg (str "reveal " (enumerate-str (map :title (take 3 (:deck corp)))) " from the top of R&D")) + :msg (msg (s/strcat "reveal " (enumerate-str (map :title (take 3 (:deck corp)))) " from the top of R&D")) :label "Add 1 card from top 3 of R&D to HQ" :waiting-prompt true :effect (req @@ -319,7 +319,7 @@ (wait-for (draw state :corp 1) (system-msg state :corp - (str "gains 5 [Credits] and draws 1 card. " + (s/strcat "gains 5 [Credits] and draws 1 card. " "Black Level Clearance is trashed")) (trash state :corp eid card {:cause-card card}))))))}]}) @@ -335,7 +335,7 @@ (continue-ability state side {:optional - {:prompt (str "Derez another piece of ice to give " + {:prompt (s/strcat "Derez another piece of ice to give " (:title rezzed-card) " +3 strength for the remainder of the run?") :waiting-prompt true @@ -409,7 +409,7 @@ (same-server? card %))) count pos?) - {:prompt (str "Place 1 advancement counter on an ice protecting " (zone->name (second (get-zone card)))) + {:prompt (s/strcat "Place 1 advancement counter on an ice protecting " (zone->name (second (get-zone card)))) :choices {:card #(and (ice? %) (same-server? % card))} :msg (msg "place 1 advancement counter on " (card-str state target)) @@ -432,11 +432,11 @@ :waiting-prompt true :prompt "Choose one" :choices [(when (can-pay? state :runner eid card nil [(->c :credit cost)]) - (str "Pay " cost " [Credits]")) + (s/strcat "Pay " cost " [Credits]")) "End the run"] :msg (msg (if (= target "End the run") (decapitalize target) - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :effect (req (if (= target "End the run") (end-run state side eid card) (wait-for (pay state :runner (make-eid state eid) card (->c :credit cost)) @@ -464,7 +464,7 @@ (set-next-phase state :approach-ice) (update-all-ice state side) (update-all-icebreakers state side) - (system-msg state :corp (str "trashes " (:title card) " to make the runner approach " + (system-msg state :corp (s/strcat "trashes " (:title card) " to make the runner approach " (:title (get-in (:ices (card->server state card)) [(:position run)])) " again")) (wait-for (resolve-ability state :runner (make-eid state eid) (offer-jack-out) card nil) @@ -560,7 +560,7 @@ (defcard "Daruma" (let [choose-swap (fn [to-swap] - {:prompt (str "Choose a card to swap with " (:title to-swap)) + {:prompt (s/strcat "Choose a card to swap with " (:title to-swap)) :choices {:not-self true :card #(and (corp? %) (not (or (operation? %) @@ -714,7 +714,7 @@ (protecting-same-server? card (:ice context)))) :msg (msg (let [deck (:deck runner)] (if (pos? (count deck)) - (str "trash " (enumerate-str (map :title (take 2 deck))) " from the stack") + (s/strcat "trash " (enumerate-str (map :title (take 2 deck))) " from the stack") "trash no cards from the stack (it is empty)"))) :async true :effect (effect (mill :corp eid :runner 2))}]}) @@ -748,7 +748,7 @@ :async true :effect (req (force-ice-encounter state side eid target-card))}])) (trash state side eid (assoc card :seen true) {:unpreventable true :cause-card card}))} - :no-ability {:effect (effect (system-msg (str "declines to use " (:title card))))}}}}) + :no-ability {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}}) (defcard "Georgia Emelyov" {:events [{:event :unsuccessful-run @@ -783,11 +783,11 @@ :waiting-prompt true :prompt "Choose one" :choices [(when (can-pay? state :runner eid card nil (->c :credit credit-cost)) - (str "Pay " credit-cost " [Credits]")) + (s/strcat "Pay " credit-cost " [Credits]")) "End the run"] :msg (msg (if (= "End the run" target) (decapitalize target) - (str "force the runner to " (decapitalize target)))) + (s/strcat "force the runner to " (decapitalize target)))) :effect (req (if (= "End the run" target) (end-run state :corp eid card) (wait-for (pay state :runner (make-eid state eid) card (->c :credit credit-cost)) @@ -840,7 +840,7 @@ :choices ["Trash 1 scored agenda" "End the run"] :async true :effect (req (if (= target "End the run") - (do (system-msg state :runner (str "declines to pay the additional cost from " (:title card))) + (do (system-msg state :runner (s/strcat "declines to pay the additional cost from " (:title card))) (end-run state side eid card)) (if (seq (:scored runner)) (continue-ability state :runner @@ -849,11 +849,11 @@ :choices {:max 1 :card #(is-scored? state side %)} :effect (req (wait-for (trash state side target {:unpreventable true :cause-card card :cause :forced-to-trash}) - (system-msg state :runner (str "trashes " (:title target) + (system-msg state :runner (s/strcat "trashes " (:title target) " as an additional cost to initiate a run")) (effect-completed state side eid)))} card nil) - (do (system-msg state :runner (str "cannot pay the additional cost from " (:title card))) + (do (system-msg state :runner (s/strcat "cannot pay the additional cost from " (:title card))) (end-run state side eid card)))))}] {:events [{:event :run :async true @@ -877,7 +877,7 @@ :waiting-prompt true :msg (msg (if (= target "The Corp removes 1 bad publicity") "remove 1 bad publicity" - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :prompt "Choose one" :choices ["Take 1 tag" "The Corp removes 1 bad publicity"] :effect (req (if (= target "Take 1 tag") @@ -931,7 +931,7 @@ (continue-ability state side (choose-ice remaining grids) card nil) (wait-for (reveal state side ice) - (system-msg state side (str "reveals that they drew " (:title ice))) + (system-msg state side (s/strcat "reveals that they drew " (:title ice))) (wait-for (corp-install state side ice server {:cost-bonus -4 :msg-keys {:install-source card :known true @@ -946,7 +946,7 @@ (if (= 1 (count grids)) (install-ice ice ices grids (-> (first grids) :zone second zone->name)) {:async true - :prompt (str "Choose a server to install " (:title ice)) + :prompt (s/strcat "Choose a server to install " (:title ice)) :choices (conj (mapv #(-> % :zone second zone->name) grids) "None") :effect (effect (continue-ability (install-ice ice ices grids target) card nil))})) (choose-ice [ices grids] @@ -1000,7 +1000,7 @@ :async true :msg (msg (if (= target "End the run") (decapitalize target) - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :effect (req (if (= target "Take 1 tag") (gain-tags state :runner eid 1) (end-run state side eid card)))}]}) @@ -1074,7 +1074,7 @@ (move state side target :hand) (effect-completed state side eid)))} :no-ability - {:effect (effect (system-msg (str "declines to use " (:title card))))}}}]}) + {:effect (effect (system-msg (s/strcat "declines to use " (:title card))))}}}]}) (defcard "Manegarm Skunkworks" {:events [{:event :approach-server @@ -1101,7 +1101,7 @@ (system-msg state side (:msg async-result)) (effect-completed state :runner eid))] [:else - (system-msg state :corp (str "uses " (:title card) " to end the run")) + (system-msg state :corp (s/strcat "uses " (:title card) " to end the run")) (end-run state :corp eid card)]))}]}) (defcard "Manta Grid" @@ -1154,14 +1154,14 @@ (purge state side) (if (rezzed? card) (do - (system-msg state side (str "uses " (:title card) " to do 1 net damage")) + (system-msg state side (s/strcat "uses " (:title card) " to do 1 net damage")) (damage state side eid :net 1 {:card card})) (effect-completed state side eid))))} :no-ability {:async true - :effect (req (system-msg state :corp (str "declines to use " (:title card))) + :effect (req (system-msg state :corp (s/strcat "declines to use " (:title card))) (if (rezzed? card) (do - (system-msg state side (str "uses " (:title card) " to do 1 net damage")) + (system-msg state side (s/strcat "uses " (:title card) " to do 1 net damage")) (damage state side eid :net 1 {:card card})) (effect-completed state side eid)))}}} :abilities [{:label "Purge virus counters" @@ -1213,7 +1213,7 @@ :async true :msg (msg (if (= target "Suffer 1 core damage") "do 1 core damage" - (str "force the Runner to " (decapitalize target)))) + (s/strcat "force the Runner to " (decapitalize target)))) :effect (req (if (= target "Suffer 1 core damage") (damage state :corp eid :brain 1 {:card card}) (do (lose-clicks state :runner (:click runner)) @@ -1250,7 +1250,7 @@ :unregister-once-resolved true :effect (req (if-let [accessed-cards (reduce + (vals (:cards-accessed target)))] (do (system-msg state :corp - (str "gains " (* 2 accessed-cards) + (s/strcat "gains " (* 2 accessed-cards) " [Credits] from "(:title card))) (gain-credits state :corp eid (* 2 accessed-cards))) (effect-completed state side eid)))} @@ -1452,7 +1452,7 @@ (let [n target] {:async true :cost [(->c :credit n)] - :msg (str "give the Runner " (quantify n "tag")) + :msg (s/strcat "give the Runner " (quantify n "tag")) :effect (effect (gain-tags :corp eid n))}) card nil))}] {:on-trash {:silent (req true) @@ -1530,7 +1530,7 @@ :async true :effect (req (let [spent (str->int target)] (add-counter state :corp card :power spent) - (system-msg state :corp (str "uses " (:title card) " to place " + (system-msg state :corp (s/strcat "uses " (:title card) " to place " (quantify spent "power counter") " on itself")) (lose-credits state :corp eid spent)))}}) @@ -1791,9 +1791,9 @@ :msg-keys {:install-source card :display-origin true}}) (shuffle! state :corp :deck) - (system-msg state side (str "shuffles R&D")) + (system-msg state side (s/strcat "shuffles R&D")) (effect-completed state side eid))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card))) (effect-completed eid))}] {:install-req (req (remove #{"HQ" "R&D" "Archives"} targets)) :events [(assoc ability @@ -1879,7 +1879,7 @@ :successful {:async true :msg (msg (let [n (min 2 (count (all-installed state :runner)))] - (str "force the runner to trash " + (s/strcat "force the runner to trash " (quantify n "installed card") (when (not (pos? n)) "but there are no installed cards to trash")))) diff --git a/src/clj/game/core/access.clj b/src/clj/game/core/access.clj index 981b54b7e5..b2599de014 100644 --- a/src/clj/game/core/access.clj +++ b/src/clj/game/core/access.clj @@ -21,7 +21,8 @@ [jinteki.utils :refer [add-cost-to-label]] [clojure.set :as clj-set] [medley.core :refer [find-first]] - [clojure.string :as string])) + [clojure.string :as string] + [stringer.core :as s])) (defn no-trash-or-steal [state] @@ -61,7 +62,7 @@ access-ability (access-ab card) ability (add-cost-label-to-ability access-ability (card-ability-cost state :runner access-ability card)) label (add-cost-to-label ability)] - (str "[" title "] " label))) + (s/strcat "[" title "] " label))) (defn access-non-agenda "Access a non-agenda. Show a prompt to trash for trashable cards." @@ -89,7 +90,7 @@ can-pay (when trash-cost (can-pay? state :runner trash-eid card nil [(->c :credit trash-cost)])) trash-cost-str (when can-pay - [(str "Pay " trash-cost " [Credits] to trash")]) + [(s/strcat "Pay " trash-cost " [Credits] to trash")]) ; Is the runner is forced to trash this card with only credits? (NAT) must-trash-with-credits? (and can-pay (get-in @state [:runner :register :must-trash-with-credits])) @@ -127,7 +128,7 @@ (continue-ability state :runner {:async true - :prompt (str "You accessed " (:title card) ".") + :prompt (s/strcat "You accessed " (:title card) ".") :choices choices :effect (req (cond ; Can't or won't trash or use an ability @@ -146,7 +147,7 @@ (swap! state assoc-in [:run :did-access] true))) (swap! state assoc-in [:runner :register :trashed-card] true) (swap! state assoc-in [:runner :register :trashed-accessed-card] true) - (system-msg state side (str (:msg async-result) " to trash " + (system-msg state side (s/strcat (:msg async-result) " to trash " (:title card) " from " (name-zone :corp (get-zone card)))) (wait-for (trash state side card {:accessed true}) @@ -189,7 +190,7 @@ _ (update-all-agenda-points state) c (get-card state c) points (get-agenda-points c)] - (system-msg state :runner (str "steals " (:title c) " and gains " (quantify points "agenda point"))) + (system-msg state :runner (s/strcat "steals " (:title c) " and gains " (quantify points "agenda point"))) (swap! state update-in [:runner :register :stole-agenda] #(+ (or % 0) (:agendapoints c 0))) (play-sfx state side "agenda-steal") (when (:breach @state) @@ -238,9 +239,9 @@ no-action-str (when-not (= steal-str ["Steal"]) ["No action"]) prompt-str (if (not (string/blank? cost-strs)) - (str " " cost-strs " to steal?") + (s/strcat " " cost-strs " to steal?") "") - prompt-str (str "You accessed " (:title card) "." prompt-str) + prompt-str (s/strcat "You accessed " (:title card) "." prompt-str) choices (vec (concat ability-strs steal-str no-action-str))] ;; Steal costs are additional costs and can be denied by the runner. (continue-ability @@ -252,7 +253,7 @@ ;; Can't steal or pay, or won't pay additional costs to steal (= target "No action") (do (when-not (find-cid (:cid card) (:deck corp)) - (system-msg state side (str "decides to not pay to steal " (:title card)))) + (system-msg state side (s/strcat "decides to not pay to steal " (:title card)))) (access-end state side eid card)) ;; Steal normally @@ -268,7 +269,7 @@ :source-type :runner-steal :action :steal-cost)) nil cost) - (system-msg state side (str (:msg async-result) " to steal " + (system-msg state side (s/strcat (:msg async-result) " to steal " (:title card) " from " (name-zone :corp (get-zone card)))) (steal-agenda state side eid card)) @@ -319,14 +320,14 @@ (let [cost-str (join-cost-strs cost-msg)] (when-not no-msg (system-msg state side - (str (if (seq cost-msg) - (str cost-str " to access ") + (s/strcat (if (seq cost-msg) + (s/strcat cost-str " to access ") "accesses ") title (when card - (str " from " (name-zone :corp zone))))))) + (s/strcat " from " (name-zone :corp zone))))))) (if (reveal-access? state side card) - (do (system-msg state side (str "must reveal they accessed " (:title card))) + (do (system-msg state side (s/strcat "must reveal they accessed " (:title card))) (reveal state :runner eid card)) (effect-completed state side eid))) @@ -342,8 +343,8 @@ ([cost ability] (let [ab (if (pos? cost) (assoc ability :cost [(->c :credit cost)]) ability) prompt (if (pos? cost) - (req (str "Pay " cost " [Credits] to use " (:title card) " ability?")) - (req (str "Use " (:title card) " ability?")))] + (req (s/strcat "Pay " cost " [Credits] to use " (:title card) " ability?")) + (req (s/strcat "Use " (:title card) " ability?")))] (installed-access-trigger cost ab prompt))) ([cost ability prompt] (let [cost (if (number? cost) [(->c :credit cost)] cost)] @@ -408,7 +409,7 @@ can-pay (when (not-empty cost) (can-pay? state side (make-eid state eid) nil nil cost)) prompt-str (if can-pay - (str cost-str " to access this card?") + (s/strcat cost-str " to access this card?") "You can't pay the cost to access this card.") choices (if can-pay ["Pay to access" "No action"] @@ -828,7 +829,7 @@ (continue-ability state :corp {:async true - :prompt (str "Choose a card in HQ for the Runner to access") + :prompt (s/strcat "Choose a card in HQ for the Runner to access") :waiting-prompt true :choices {:all true :card #(and (in-hand? %) @@ -1174,7 +1175,7 @@ ;; Present the normal options :else {:async true - :prompt (str "Choose a card to access. You must access all cards") + :prompt (s/strcat "Choose a card to access. You must access all cards") :choices choices :effect (req (cond @@ -1339,7 +1340,7 @@ "Starts the breach routines for the run's server." ([state side eid server] (breach-server state side eid server nil)) ([state side eid server args] - (system-msg state side (str "breaches " (zone->name server))) + (system-msg state side (s/strcat "breaches " (zone->name server))) (wait-for (trigger-event-simult state side :breach-server nil (first server)) (swap! state assoc :breach {:breach-server (first server) :from-server (first server)}) (let [args (clean-access-args args) diff --git a/src/clj/game/core/actions.clj b/src/clj/game/core/actions.clj index 631499c40a..82bc2efff0 100644 --- a/src/clj/game/core/actions.clj +++ b/src/clj/game/core/actions.clj @@ -27,7 +27,8 @@ [game.core.toasts :refer [toast]] [game.core.update :refer [update!]] [game.macros :refer [continue-ability req wait-for]] - [game.utils :refer [dissoc-in quantify remove-once same-card? same-side? server-cards to-keyword]])) + [game.utils :refer [dissoc-in quantify remove-once same-card? same-side? server-cards to-keyword]] + [stringer.core :as s])) (defn- update-click-state "Update :click-states to hold latest 4 moments before performing actions." @@ -88,7 +89,7 @@ (not= side (to-keyword (:side card))) (any-effects state side :prevent-paid-ability true? card [ability ability-idx]))] (when blocking-prompt? - (toast state side (str "You cannot play abilities while other abilities are resolving.") + (toast state side (s/strcat "You cannot play abilities while other abilities are resolving.") "warning")) (when-not cannot-play (do-play-ability state side eid (assoc args :ability-idx ability-idx :ability ability)))))) @@ -101,7 +102,7 @@ eid (make-eid state {:source card :source-type :ability}) expend-ab (expend (:expend card))] (resolve-ability state side eid expend-ab card nil)) - (toast state side (str "You cannot play abilities while other abilities are resolving.") + (toast state side (s/strcat "You cannot play abilities while other abilities are resolving.") "warning"))) (defn play @@ -150,7 +151,7 @@ (let [move-card-to (partial move state s c) card-prompts (filter #(same-card? :title % c) (get-in @state [side :prompt])) log-move (fn [verb & text] - (system-msg state side (str verb " " from-str + (system-msg state side (s/strcat verb " " from-str (when (seq text) (apply str " " text)))))] (case server @@ -182,9 +183,9 @@ (defn- prompt-error [context prompt prompt-args] - (.println *err* (with-out-str (print-stack-trace (Exception. (str "Error " context))))) - (.println *err* (str "Prompt: " prompt)) - (.println *err* (str "Prompt args: " prompt-args))) + (.println *err* (with-out-str (print-stack-trace (Exception. (s/strcat "Error " context))))) + (.println *err* (s/strcat "Prompt: " prompt)) + (.println *err* (s/strcat "Prompt args: " prompt-args))) (defn- maybe-pay [state side eid card choices choice] @@ -230,8 +231,8 @@ (when effect (effect (or choice card))) (finish-prompt state side prompt card)) - (toast state side (str "You cannot choose " choice " for this effect.") "warning")) - (toast state side (str "Could not find a card named " choice ".") "warning"))) + (toast state side (s/strcat "You cannot choose " choice " for this effect.") "warning")) + (toast state side (s/strcat "Could not find a card named " choice ".") "warning"))) (prompt-error "in a card-title prompt" prompt args)) ;; Otherwise, choices is a sequence of strings and/or cards @@ -314,7 +315,7 @@ (wait-for (pay state side (make-eid state eid) card total-pump-cost) (dotimes [_ times-pump] (resolve-ability state side (dissoc pump-ability :cost :msg) (get-card state card) nil)) - (system-msg state side (str (build-spend-msg (:msg async-result) "increase") + (system-msg state side (s/strcat (build-spend-msg (:msg async-result) "increase") "the strength of " (:title card) " to " (get-strength (get-card state card)))) (effect-completed state side eid))))) @@ -392,7 +393,7 @@ [(remove :broken (:subroutines current-ice))])] (wait-for (resolve-ability state side (play-heap-breaker-auto-pump-and-break-impl state side sub-groups-to-break current-ice) card nil) (system-msg state side - (str (build-spend-msg payment-str "increase") + (s/strcat (build-spend-msg payment-str "increase") "the strength of " (:title card) " to " (get-strength (get-card state card)) " and break all subroutines on " (:title current-ice))) @@ -490,12 +491,12 @@ (wait-for (resolve-ability state side (play-auto-pump-and-break-impl state side sub-groups-to-break current-ice break-ability) card nil) (system-msg state side (if (pos? times-pump) - (str (build-spend-msg payment-str "increase") + (s/strcat (build-spend-msg payment-str "increase") "the strength of " (:title card) " to " (get-strength (get-card state card)) " and break all " (when (< 1 unbroken-subs) unbroken-subs) " subroutines on " (:title current-ice)) - (str (build-spend-msg payment-str "use") + (s/strcat (build-spend-msg payment-str "use") (:title card) " to break " (if some-already-broken @@ -515,7 +516,7 @@ [state side args] (if (no-blocking-or-prevent-prompt? state side) ((dynamic-abilities (:dynamic args)) state (keyword side) args) - (toast state side (str "You cannot play abilities while other abilities are resolving.") + (toast state side (s/strcat "You cannot play abilities while other abilities are resolving.") "warning"))) @@ -551,7 +552,7 @@ sub (nth (:subroutines card) subroutine nil)] (when card (resolve-subroutine! state side card sub))) - (toast state side (str "You cannot fire subroutines while abilities are being resolved.") + (toast state side (s/strcat "You cannot fire subroutines while abilities are being resolved.") "warning"))) (defn play-unbroken-subroutines @@ -560,7 +561,7 @@ (if (no-blocking-or-prevent-prompt? state side) (when-let [card (get-card state card)] (resolve-unbroken-subs! state side card)) - (toast state side (str "You cannot fire subroutines while abilities are being resolved.") + (toast state side (s/strcat "You cannot fire subroutines while abilities are being resolved.") "warning"))) ;;; Corp actions @@ -639,7 +640,7 @@ (->c :click (if-not no-cost 1 0)) (->c :credit (if-not no-cost 1 0))) (if-let [payment-str (:msg async-result)] - (do (system-msg state side (str (build-spend-msg payment-str "advance") (card-str state card))) + (do (system-msg state side (s/strcat (build-spend-msg payment-str "advance") (card-str state card))) (update-advancement-requirement state card) (add-prop state side (get-card state card) :advance-counter 1) (play-sfx state side "click-advance") @@ -657,7 +658,7 @@ _ (update-all-agenda-points state) c (get-card state c) points (get-agenda-points c)] - (system-msg state :corp (str "scores " (:title c) + (system-msg state :corp (s/strcat "scores " (:title c) " and gains " (quantify points "agenda point"))) (implementation-msg state card) (set-prop state :corp (get-card state c) :advance-counter 0) @@ -691,5 +692,5 @@ (if (string/blank? (:msg payment-result)) (effect-completed state side eid) (do - (system-msg state side (str (:msg payment-result) " to score " (:title card))) + (system-msg state side (s/strcat (:msg payment-result) " to score " (:title card))) (resolve-score state side eid card)))))))))) diff --git a/src/clj/game/core/bad_publicity.clj b/src/clj/game/core/bad_publicity.clj index 9397a4bec4..15a8d7f76d 100644 --- a/src/clj/game/core/bad_publicity.clj +++ b/src/clj/game/core/bad_publicity.clj @@ -7,7 +7,8 @@ [game.core.prompts :refer [clear-wait-prompt show-prompt show-wait-prompt]] [game.core.say :refer [system-msg]] [game.core.toasts :refer [toast]] - [game.macros :refer [wait-for]])) + [game.macros :refer [wait-for]] + [stringer.core :as s])) (defn bad-publicity-prevent [state side n] @@ -19,7 +20,7 @@ [state side eid n] (if (pos? n) (do (gain state :corp :bad-publicity n) - (toast state :corp (str "Took " n " bad publicity!") "info") + (toast state :corp (s/strcat "Took " n " bad publicity!") "info") (trigger-event-sync state side (make-result eid n) :corp-gain-bad-publicity {:amount n})) (effect-completed state side eid))) @@ -48,12 +49,12 @@ (swap! state assoc-in [:prevent :current] :bad-publicity) (show-prompt state :corp nil - (str "Avoid " (when (< 1 n) "any of the ") n " bad publicity?") ["Done"] + (s/strcat "Avoid " (when (< 1 n) "any of the ") n " bad publicity?") ["Done"] (fn [_] (let [prevent (get-in @state [:bad-publicity :bad-publicity-prevent])] (system-msg state :corp (if prevent - (str "avoids " + (s/strcat "avoids " (if (= prevent Integer/MAX_VALUE) "all" prevent) " bad publicity") "will not avoid bad publicity")) diff --git a/src/clj/game/core/board.clj b/src/clj/game/core/board.clj index 2b4338ba13..8714cd20b7 100644 --- a/src/clj/game/core/board.clj +++ b/src/clj/game/core/board.clj @@ -6,7 +6,8 @@ [game.core.card-defs :refer [card-def]] [game.core.eid :refer [make-eid]] [game.core.servers :refer [is-remote? zones->sorted-names]] - [game.utils :refer [dissoc-in to-keyword]])) + [game.utils :refer [dissoc-in to-keyword]] + [stringer.core :as s])) (defn corp-servers-cards [state] (for [server (vals (:servers (:corp @state))) @@ -188,8 +189,8 @@ "HQ" [:servers :hq] "R&D" [:servers :rd] "Archives" [:servers :archives] - "New remote" [:servers (keyword (str "remote" (:rid @state)))] - [:servers (->> (string/split server #" ") last (str "remote") keyword)])))) + "New remote" [:servers (keyword (s/strcat "remote" (:rid @state)))] + [:servers (->> (string/split server #" ") last (s/strcat "remote") keyword)])))) (defn card->server "Returns the server map that this card is installed in or protecting." diff --git a/src/clj/game/core/change_vals.clj b/src/clj/game/core/change_vals.clj index ec203aa407..2c7349660b 100644 --- a/src/clj/game/core/change_vals.clj +++ b/src/clj/game/core/change_vals.clj @@ -9,7 +9,8 @@ [game.core.memory :refer [available-mu update-mu]] [game.core.say :refer [system-msg]] [game.core.tags :refer [update-tag-status]] - [game.macros :refer [req]])) + [game.macros :refer [req]] + [stringer.core :as s])) (defn- change-msg "Send a system message indicating the property change" @@ -18,8 +19,8 @@ (= kw :brain-damage) "core damage" :else (name kw))] (system-msg state side - (str "sets " (.replace key "-" " ") " to " new-val - " (" (if (pos? delta) (str "+" delta) delta) ")")))) + (s/strcat "sets " (.replace key "-" " ") " to " new-val + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")")))) (defn- change-map "Change a player's property using the :mod system" @@ -36,8 +37,8 @@ :value [:regular delta]}) (update-mu state) (system-msg state side - (str "sets unused [mu] to " (available-mu state) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets unused [mu] to " (available-mu state) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-tags "Change a player's tag count" @@ -45,8 +46,8 @@ (gain state :runner :tag delta) (update-tag-status state) (system-msg state :runner - (str "sets Tags to " (get-in @state [:runner :tag :total]) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets Tags to " (get-in @state [:runner :tag :total]) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-bad-pub "Change a player's base bad pub count" @@ -55,8 +56,8 @@ (deduct state :corp [:bad-publicity (Math/abs delta)]) (gain state :corp :bad-publicity delta)) (system-msg state :corp - (str "sets Bad Publicity to " (get-in @state [:corp :bad-publicity :base]) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets Bad Publicity to " (get-in @state [:corp :bad-publicity :base]) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-agenda-points "Change a player's total agenda points, using floating effects." @@ -71,8 +72,8 @@ :value delta})) (update-all-agenda-points state side) (system-msg state side - (str "sets [their] agenda points to " (get-in @state [side :agenda-point]) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets [their] agenda points to " (get-in @state [side :agenda-point]) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-link "Change the runner's link, using floating effects." @@ -83,8 +84,8 @@ :value delta}) (update-link state) (system-msg state side - (str "sets [their] [link] to " (get-link state) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets [their] [link] to " (get-link state) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-hand-size "Change the player's hand-size, using floating effects." @@ -97,8 +98,8 @@ :value delta})) (update-hand-size state side) (system-msg state side - (str "sets [their] hand size to " (hand-size state side) - " (" (if (pos? delta) (str "+" delta) delta) ")"))) + (s/strcat "sets [their] hand size to " (hand-size state side) + " (" (if (pos? delta) (s/strcat "+" delta) delta) ")"))) (defn- change-generic "Change a player's base generic property." diff --git a/src/clj/game/core/charge.clj b/src/clj/game/core/charge.clj index a7001cc33a..5759231627 100644 --- a/src/clj/game/core/charge.clj +++ b/src/clj/game/core/charge.clj @@ -5,7 +5,8 @@ [game.core.eid :refer [effect-completed]] [game.core.say :refer [system-msg]] [game.macros :refer [req msg effect]] - [game.core.props :refer [add-counter]])) + [game.core.props :refer [add-counter]] + [stringer.core :as s])) (defn can-charge "A card can be charged if it has at least one power counter" @@ -34,7 +35,7 @@ :prompt "Choose an installed card" :choices {:card #(can-charge state side %)} :async true - :msg (msg "charge " (:title target) (when (> n 1) (str n " times"))) - :cancel-effect (effect (system-msg (str "declines to use " (:title card) " to charge a card")) + :msg (msg "charge " (:title target) (when (> n 1) (s/strcat n " times"))) + :cancel-effect (effect (system-msg (s/strcat "declines to use " (:title card) " to charge a card")) (effect-completed eid)) :effect (req (charge-card state side eid target n))}))) diff --git a/src/clj/game/core/commands.clj b/src/clj/game/core/commands.clj index c53b3f596d..b870dfa1e1 100644 --- a/src/clj/game/core/commands.clj +++ b/src/clj/game/core/commands.clj @@ -37,7 +37,8 @@ [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]] - [jinteki.utils :refer [str->int]])) + [jinteki.utils :refer [str->int]] + [stringer.core :as s])) (defn- constrain-value "Constrain value to [min-value max-value]" @@ -46,7 +47,7 @@ (defn- set-adv-counter [state side target value] (set-prop state side target :advance-counter value) - (system-msg state side (str "sets advancement counters to " value " on " + (system-msg state side (s/strcat "sets advancement counters to " value " on " (card-str state target))) (trigger-event state side :advancement-placed {:card target})) @@ -63,7 +64,7 @@ (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) + body (s/strcat "Link to bug replay: https://jinteki.net/bug-report/" (:gameid @state) "?b=" (:bug-reported @state) "\n\n" "Description:\n\n" "[EDITME] Please describe the steps to reproduce your bug and the resulting effect here.")] @@ -71,7 +72,7 @@ "Thanks for helping us make the game better! The replay was saved. " "Please report a bug following " [:a {:target "_blank" - :href (str "https://github.com/mtgred/netrunner/issues/new?title=" + :href (s/strcat "https://github.com/mtgred/netrunner/issues/new?title=" (string/replace title #" " "%20") "&body=" (string/replace (string/replace body #" " "%20") #"\n" "%0A"))} @@ -96,13 +97,13 @@ (not counter-type) (toast state side - (str "Could not infer what counter type you mean. Please specify one manually, by typing " + (s/strcat "Could not infer what counter type you mean. Please specify one manually, by typing " "'/counter TYPE " value "', where TYPE is advance, agenda, credit, power, bad publicity, or virus.") "error" {:time-out 0 :close-button true}) :else (do (update! state side (assoc-in target [:counter counter-type] value)) - (system-msg state side (str "sets " (name counter-type) " counters to " value " on " + (system-msg state side (s/strcat "sets " (name counter-type) " counters to " value " on " (card-str state target))))))))} (make-card {:title "/counter command"}) nil)) @@ -142,7 +143,7 @@ (command-adv-counter state side value) (resolve-ability state side {:effect (effect (update! (assoc-in target [:counter counter-type] value)) - (system-msg (str "sets " (name counter-type) " counters to " value " on " + (system-msg (s/strcat "sets " (name counter-type) " counters to " value " on " (card-str state target)))) :choices {:card (fn [t] (same-side? (:side t) side))}} (make-card {:title "/counter command"}) nil))))) @@ -167,14 +168,14 @@ (defn command-roll [state side value] (let [value (constrain-value value 1 1000)] - (system-msg state side (str "rolls a " value " sided die and rolls a " (inc (rand-int value)))))) + (system-msg state side (s/strcat "rolls a " value " sided die and rolls a " (inc (rand-int value)))))) (defn command-set-mark "Sets a central server as the mark for the turn" [state side [server & _]] (when (and (= :runner side) (is-central? (unknown->kw server))) - (system-msg state side (str "sets " server " as the mark for this turn")) + (system-msg state side (s/strcat "sets " server " as the mark for this turn")) (set-mark state (unknown->kw server)))) (defn command-undo-click @@ -193,7 +194,7 @@ :history current-history :run nil)] (reset! state last-click-state)) - (system-say state side (str "[!] " (if (= side :corp) "Corp" "Runner") " uses the undo-click command")) + (system-say state side (s/strcat "[!] " (if (= side :corp) "Corp" "Runner") " uses the undo-click command")) (doseq [s [:runner :corp]] (toast state s "Game reset to start of click"))))) @@ -237,17 +238,17 @@ (resolve-ability state side (if (= side :corp) - {:prompt (str "Choose a card to install" (when ignore-all-cost " (ignoring all costs)")) + {:prompt (s/strcat "Choose a card to install" (when ignore-all-cost " (ignoring all costs)")) :choices {:card #(and (corp? %) (not (installed? %)))} :async true :effect (req (corp-install state side eid target nil {:ignore-all-cost ignore-all-cost}))} - {:prompt (str "Choose a card to install" (when ignore-all-cost " (ignoring all costs)")) + {:prompt (s/strcat "Choose a card to install" (when ignore-all-cost " (ignoring all costs)")) :choices {:card #(and (runner? %) (not (installed? %)))} :async true :effect (req (runner-install state side eid target {:ignore-all-cost ignore-all-cost}))}) - (make-card {:title (str "/install" (when ignore-all-cost "-free") " command")}) nil))) + (make-card {:title (s/strcat "/install" (when ignore-all-cost "-free") " command")}) nil))) (defn command-install-free [state side] @@ -290,7 +291,7 @@ (show-prompt state side nil - (str "The top " (quantify n "card") + (s/strcat "The top " (quantify n "card") " of your deck " (if (< 1 n) "are" "is") " (top->bottom): " (->> (get-in @state [side :deck]) (take n) @@ -322,7 +323,7 @@ (when card (swap! state update-in [side :hand] #(concat % [(assoc card :zone [:hand])])))) (catch Exception ex - (toast state side (str card-name " isn't a real card")))))) + (toast state side (s/strcat card-name " isn't a real card")))))) (defn command-reload-id [state side] @@ -336,9 +337,9 @@ (disable-identity state side) (swap! state assoc-in [side :identity] new-id) (card-init state side new-id {:resolve-effect true :init-data true})) - (toast state side (str card-name " isn't a valid card")))) + (toast state side (s/strcat card-name " isn't a valid card")))) (catch Exception ex - (toast state side (str card-name " isn't a real card")))))) + (toast state side (s/strcat card-name " isn't a real card")))))) (defn command-replace-id [state side args] @@ -352,9 +353,9 @@ (disable-identity state side) (swap! state assoc-in [side :identity] new-id) (card-init state side new-id {:resolve-effect true :init-data true})) - (toast state side (str card-name " isn't a valid card")))) + (toast state side (s/strcat card-name " isn't a valid card")))) (catch Exception ex - (toast state side (str card-name " isn't a real card")))))) + (toast state side (s/strcat card-name " isn't a real card")))))) (defn command-host [state side] @@ -412,7 +413,7 @@ "/bp" #(swap! %1 assoc-in [%2 :bad-publicity :base] (constrain-value value -1000 1000)) "/bug" command-bug-report "/card-info" #(resolve-ability %1 %2 - {:effect (effect (system-msg (str "shows card-info of " + {:effect (effect (system-msg (s/strcat "shows card-info of " (card-str state target) ": " (get-card state target)))) :choices {:card (fn [t] (same-side? (:side t) %2))}} diff --git a/src/clj/game/core/costs.clj b/src/clj/game/core/costs.clj index f34ded4b7d..6ec13919eb 100644 --- a/src/clj/game/core/costs.clj +++ b/src/clj/game/core/costs.clj @@ -21,7 +21,8 @@ [game.core.update :refer [update!]] [game.core.virus :refer [number-of-virus-counters]] [game.macros :refer [continue-ability req wait-for]] - [game.utils :refer [enumerate-str quantify same-card?]])) + [game.utils :refer [enumerate-str quantify same-card?]] + [stringer.core :as s])) ;; Click (defmethod value :click [cost] (:cost/amount cost)) @@ -55,7 +56,7 @@ ;; and so we can look through the events and figure out WHICH abilities were used ;; I don't think it will break anything (swap! state assoc-in [side :register :spent-click] true) - (complete-with-result state side eid {:paid/msg (str "spends " (label cost)) + (complete-with-result state side eid {:paid/msg (s/strcat "spends " (label cost)) :paid/type :click :paid/value (value cost)})))) @@ -67,7 +68,7 @@ (apply str))) (defmethod value :lose-click [cost] (:cost/amount cost)) (defmethod label :lose-click [cost] - (str "Lose " (lose-click-label cost))) + (s/strcat "Lose " (lose-click-label cost))) (defmethod payable? :lose-click [cost state side _ _] (<= 0 (- (get-in @state [side :click]) (value cost)))) @@ -79,7 +80,7 @@ (if (= side :corp) :corp-spent-click :runner-spent-click) {:value (value cost)}) (swap! state assoc-in [side :register :spent-click] true) - (complete-with-result state side eid {:paid/msg (str "loses " (lose-click-label cost)) + (complete-with-result state side eid {:paid/msg (s/strcat "loses " (lose-click-label cost)) :paid/type :lose-click :paid/value (value cost)}))) @@ -139,7 +140,7 @@ (= :all-stealth v) (value cost) v v :else 0))) -(defmethod label :credit [cost] (str (value cost) " [Credits]")) +(defmethod label :credit [cost] (s/strcat (value cost) " [Credits]")) (defmethod payable? :credit [cost state side eid card] (and (<= 0 (- (total-available-stealth-credits state side eid card) (stealth-value cost))) @@ -160,7 +161,7 @@ (value cost)) (swap! state update-in [:stats side :spent :credit] (fnil + 0) (value cost)) (complete-with-result state side eid - {:paid/msg (str "pays " (:msg pay-async-result)) + {:paid/msg (s/strcat "pays " (:msg pay-async-result)) :paid/type :credit :paid/value (:number pay-async-result) :paid/targets (:targets pay-async-result)})))) @@ -171,7 +172,7 @@ (if (= side :corp) :corp-spent-credits :runner-spent-credits) (value cost)) (swap! state update-in [:stats side :spent :credit] (fnil + 0) (value cost)) - (complete-with-result state side eid {:paid/msg (str "pays " (value cost) " [Credits]") + (complete-with-result state side eid {:paid/msg (s/strcat "pays " (value cost) " [Credits]") :paid/type :credit :paid/value (value cost)}))) :else @@ -183,7 +184,7 @@ (defmethod value :x-credits [_] 0) ;We put stealth credits in the third slot rather than the empty second slot for consistency with credits (defmethod stealth-value :x-credits [cost] (or (:cost/stealth cost) 0)) -(defmethod label :x-credits [_] (str "X [Credits]")) +(defmethod label :x-credits [_] (s/strcat "X [Credits]")) (defmethod payable? :x-credits [cost state side eid card] (and (pos? (total-available-credits state side eid card)) @@ -205,7 +206,7 @@ (pos? (count (provider-func)))) (wait-for (resolve-ability state side (pick-credit-providing-cards provider-func eid cost stealth-value) card nil) (swap! state update-in [:stats side :spent :credit] (fnil + 0) cost) - (complete-with-result state side eid {:paid/msg (str "pays " (:msg async-result)) + (complete-with-result state side eid {:paid/msg (s/strcat "pays " (:msg async-result)) :paid/type :x-credits :paid/value (:number async-result) :paid/targets (:targets async-result)})) @@ -216,11 +217,11 @@ (if (= side :corp) :corp-spent-credits :runner-spent-credits) cost) (swap! state update-in [:stats side :spent :credit] (fnil + 0) cost) - (complete-with-result state side eid {:paid/msg (str "pays " cost " [Credits]") + (complete-with-result state side eid {:paid/msg (s/strcat "pays " cost " [Credits]") :paid/type :x-credits :paid/value cost}))) :else - (complete-with-result state side eid {:paid/msg (str "pays 0 [Credits]") + (complete-with-result state side eid {:paid/msg (s/strcat "pays 0 [Credits]") :paid/type :x-credits :paid/value 0}))))} card nil)) @@ -237,7 +238,7 @@ (wait-for (trash state :corp (make-eid state eid) (assoc (get-card state card) :seen true)) (complete-with-result state side eid - {:paid/msg (str "trashes " (:title card) " from HQ") + {:paid/msg (s/strcat "trashes " (:title card) " from HQ") :paid/type :expend :paid/value 1 :paid/targets [card]})))) @@ -252,14 +253,14 @@ [cost state side eid card] (wait-for (trash state side card {:cause :ability-cost :unpreventable true}) - (complete-with-result state side eid {:paid/msg (str "trashes " (:title card)) + (complete-with-result state side eid {:paid/msg (s/strcat "trashes " (:title card)) :paid/type :trash-can :paid/value 1 :paid/targets [card]}))) ;; Forfeit (defmethod value :forfeit [cost] (:cost/amount cost)) -(defmethod label :forfeit [cost] (str "forfeit " (quantify (value cost) "Agenda"))) +(defmethod label :forfeit [cost] (s/strcat "forfeit " (quantify (value cost) "Agenda"))) (defmethod payable? :forfeit [cost state side _eid _card] (<= 0 (- (count (get-in @state [side :scored])) (value cost)))) @@ -267,7 +268,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "Agenda") " to forfeit") + {:prompt (s/strcat "Choose " (quantify (value cost) "Agenda") " to forfeit") :async true :choices {:max (value cost) :all true @@ -282,7 +283,7 @@ (wait-for (checkpoint state nil (make-eid state eid) {:durations [:game-trash]}) (complete-with-result state side eid - {:paid/msg (str "forfeits " (quantify (value cost) "agenda") + {:paid/msg (s/strcat "forfeits " (quantify (value cost) "agenda") " (" (enumerate-str (map :title targets)) ")") :paid/type :forfeit :paid/value (value cost) @@ -300,7 +301,7 @@ (wait-for (forfeit state side (make-eid state eid) card {:msg false}) (complete-with-result state side eid - {:paid/msg (str "forfeits " (:title card)) + {:paid/msg (s/strcat "forfeits " (:title card)) :paid/type :forfeit-self :paid/value 1 :paid/targets [card]}))) @@ -308,7 +309,7 @@ ;; Gain tag (defmethod value :gain-tag [cost] (:cost/amount cost)) -(defmethod label :gain-tag [cost] (str "take " (quantify (value cost) "tag"))) +(defmethod label :gain-tag [cost] (s/strcat "take " (quantify (value cost) "tag"))) (defmethod payable? :gain-tag ;; TODO - shouldn't actually be true if we're forced to avoid tags ;; QuianjuPT, Jesminder, dorm-computer can do this -nbkelly, Jan '24 @@ -317,26 +318,26 @@ (defmethod handler :gain-tag [cost state side eid card] (wait-for (gain-tags state side (value cost)) - (complete-with-result state side eid {:paid/msg (str "takes " (quantify (value cost) "tag")) + (complete-with-result state side eid {:paid/msg (s/strcat "takes " (quantify (value cost) "tag")) :paid/type :gain-tag :paid/value (value cost)}))) ;; Tag (defmethod value :tag [cost] (:cost/amount cost)) -(defmethod label :tag [cost] (str "remove " (quantify (value cost) "tag"))) +(defmethod label :tag [cost] (s/strcat "remove " (quantify (value cost) "tag"))) (defmethod payable? :tag [cost state side eid card] (<= 0 (- (get-in @state [:runner :tag :base] 0) (value cost)))) (defmethod handler :tag [cost state side eid card] (wait-for (lose-tags state side (value cost)) - (complete-with-result state side eid {:paid/msg (str "removes " (quantify (value cost) "tag")) + (complete-with-result state side eid {:paid/msg (s/strcat "removes " (quantify (value cost) "tag")) :paid/type :tag :paid/value (value cost)}))) ;; Tag-or-bad-pub (defmethod value :tag-or-bad-pub [cost] (:cost/amount cost)) -(defmethod label :tag-or-bad-pub [cost] (str "remove " (quantify (value cost) "tag") " or take " (value cost) " bad publicity")) +(defmethod label :tag-or-bad-pub [cost] (s/strcat "remove " (quantify (value cost) "tag") " or take " (value cost) " bad publicity")) (defmethod payable? :tag-or-bad-pub [cost state side eid card] true) @@ -344,22 +345,22 @@ [cost state side eid card] (if-not (<= 0 (- (get-in @state [:runner :tag :base] 0) (value cost))) (wait-for (gain-bad-publicity state side (make-eid state eid) (value cost) nil) - (complete-with-result state side eid {:paid/msg (str "gains " (value cost) " bad publicity") + (complete-with-result state side eid {:paid/msg (s/strcat "gains " (value cost) " bad publicity") :paid/type :tag-or-bad-pub :paid/value (value cost)})) (continue-ability state side {:prompt "Choose one" - :choices [(str "Remove " (quantify (value cost) "tag")) - (str "Gain " (value cost) " bad publicity")] + :choices [(s/strcat "Remove " (quantify (value cost) "tag")) + (s/strcat "Gain " (value cost) " bad publicity")] :async true - :effect (req (if (= target (str "Gain " (value cost) " bad publicity")) + :effect (req (if (= target (s/strcat "Gain " (value cost) " bad publicity")) (wait-for (gain-bad-publicity state side (make-eid state eid) (value cost) nil) - (complete-with-result state side eid {:paid/msg (str "gains " (value cost) " bad publicity") + (complete-with-result state side eid {:paid/msg (s/strcat "gains " (value cost) " bad publicity") :paid/type :tag-or-bad-pub :paid/value (value cost)})) (wait-for (lose-tags state side (value cost)) - (complete-with-result state side eid {:paid/msg (str "removes " (quantify (value cost) "tag")) + (complete-with-result state side eid {:paid/msg (s/strcat "removes " (quantify (value cost) "tag")) :paid/type :tag-or-bad-pub :paid/value (value cost)}))))} card nil))) @@ -375,7 +376,7 @@ (move state side card :hand) (complete-with-result state side eid - {:paid/msg (str "returns " (:title card) + {:paid/msg (s/strcat "returns " (:title card) " to " (if (= :corp side) "HQ" "[their] grip")) :paid/type :return-to-hand :paid/value 1 @@ -392,7 +393,7 @@ (move state side card :rfg) (complete-with-result state side eid - {:paid/msg (str "removes " (:title card) " from the game") + {:paid/msg (s/strcat "removes " (:title card) " from the game") :paid/type :remove-from-game :paid/value 1 :paid/targets [card]})) @@ -400,7 +401,7 @@ ;; RfgProgram (defmethod value :rfg-program [cost] (:cost/amount cost)) (defmethod label :rfg-program [cost] - (str "remove " (quantify (value cost) "installed program") + (s/strcat "remove " (quantify (value cost) "installed program") " from the game")) (defmethod payable? :rfg-program [cost state side eid card] @@ -409,7 +410,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "program") + {:prompt (s/strcat "Choose " (quantify (value cost) "program") " to remove from the game") :choices {:all true :max (value cost) @@ -419,7 +420,7 @@ (move state side (assoc-in t [:persistent :from-cid] (:cid card)) :rfg)) (complete-with-result state side eid - {:paid/msg (str "removes " (quantify (value cost) "installed program") + {:paid/msg (s/strcat "removes " (quantify (value cost) "installed program") " from the game" " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :rfg-program @@ -430,7 +431,7 @@ ;; TrashOtherInstalledCard - this may NOT target the source card (itself), use :trash-installed instead (defmethod value :trash-other-installed [cost] (:cost/amount cost)) (defmethod label :trash-other-installed [cost] - (str "trash " (quantify (value cost) "installed card"))) + (s/strcat "trash " (quantify (value cost) "installed card"))) (defmethod payable? :trash-other-installed [cost state side eid card] (<= 0 (- (count (filter #(not (same-card? card %)) (all-installed state side))) (value cost)))) @@ -438,7 +439,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed card") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed card") " to trash") :choices {:all true :max (value cost) :card #(and (installed? %) @@ -451,7 +452,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed card") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed card") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :trash-other-installed :paid/value (count async-result) @@ -461,7 +462,7 @@ ;; TrashInstalledCard - this may target the source card (itself) (defmethod value :trash-installed [cost] (:cost/amount cost)) (defmethod label :trash-installed [cost] - (str "trash " (quantify (value cost) "installed card"))) + (s/strcat "trash " (quantify (value cost) "installed card"))) (defmethod payable? :trash-installed [cost state side eid card] (<= 0 (- (count (all-installed state side)) (value cost)))) @@ -469,7 +470,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed card") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed card") " to trash") :choices {:all true :max (value cost) :card #(and (installed? %) @@ -481,7 +482,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed card") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed card") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :trash-installed :paid/value (count async-result) @@ -491,7 +492,7 @@ ;; TrashInstalledHardware (defmethod value :hardware [cost] (:cost/amount cost)) (defmethod label :hardware [cost] - (str "trash " (quantify (value cost) "installed piece") " of hardware")) + (s/strcat "trash " (quantify (value cost) "installed piece") " of hardware")) (defmethod payable? :hardware [cost state side eid card] (<= 0 (- (count (all-installed-runner-type state :hardware)) (value cost)))) @@ -499,7 +500,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed piece") " of hardware to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed piece") " of hardware to trash") :choices {:all true :max (value cost) :card (every-pred installed? hardware? (complement facedown?))} @@ -508,7 +509,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed piece") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed piece") " of hardware" " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :hardware @@ -519,7 +520,7 @@ ;; DerezOtherHarmonic - this may NOT target the source card (itself) (defmethod value :derez-other-harmonic [cost] (:cost/amount cost)) (defmethod label :derez-other-harmonic [cost] - (str "derez " (value cost) " Harmonic ice")) + (s/strcat "derez " (value cost) " Harmonic ice")) (defmethod payable? :derez-other-harmonic [cost state side eid card] (<= 0 (- (count (filter #(and (rezzed? %) @@ -530,7 +531,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (value cost) " Harmonic ice to derez") + {:prompt (s/strcat "Choose " (value cost) " Harmonic ice to derez") :choices {:all true :max (value cost) :card #(and (rezzed? %) @@ -541,7 +542,7 @@ (derez state side harmonic)) (complete-with-result state side eid - {:paid/msg (str "derezzes " (count targets) + {:paid/msg (s/strcat "derezzes " (count targets) " Harmonic ice (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :derez :paid/value (count targets) @@ -551,7 +552,7 @@ ;; TrashInstalledProgram (defmethod value :program [cost] (:cost/amount cost)) (defmethod label :program [cost] - (str "trash " (quantify (value cost) "installed program"))) + (s/strcat "trash " (quantify (value cost) "installed program"))) (defmethod payable? :program [cost state side eid card] (<= 0 (- (count (all-installed-runner-type state :program)) (value cost)))) @@ -559,7 +560,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed program") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed program") " to trash") :choices {:all true :max (value cost) :card (every-pred installed? program? (complement facedown?))} @@ -568,7 +569,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed program") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed program") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :program :paid/value (count async-result) @@ -578,7 +579,7 @@ ;; TrashInstalledResource (defmethod value :resource [cost] (:cost/amount cost)) (defmethod label :resource [cost] - (str "trash " (quantify (value cost) "installed resource"))) + (s/strcat "trash " (quantify (value cost) "installed resource"))) (defmethod payable? :resource [cost state side eid card] (<= 0 (- (count (all-installed-runner-type state :resource)) (value cost)))) @@ -586,7 +587,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed resource") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed resource") " to trash") :choices {:all true :max (value cost) :card (every-pred installed? resource? (complement facedown?))} @@ -595,7 +596,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed resource") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed resource") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :resource :paid/value (count async-result) @@ -605,7 +606,7 @@ ;; TrashInstalledConnection (defmethod value :connection [cost] (:cost/amount cost)) (defmethod label :connection [cost] - (str "trash " (str "trash " (quantify (value cost) "installed connection resource")))) + (s/strcat "trash " (s/strcat "trash " (quantify (value cost) "installed connection resource")))) (defmethod payable? :connection [cost state side eid card] (<= 0 (- (count (filter #(has-subtype? % "Connection") (all-active-installed state :runner))) (value cost)))) @@ -613,7 +614,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed connection resource") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed connection resource") " to trash") :choices {:all true :max (value cost) :card (every-pred installed? @@ -625,7 +626,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed connection resource") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed connection resource") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :connection :paid/value (count async-result) @@ -635,7 +636,7 @@ ;; TrashRezzedIce (defmethod value :ice [cost] (:cost/amount cost)) (defmethod label :ice [cost] - (str "trash " (str "trash " (quantify (value cost) "installed rezzed ice" "")))) + (s/strcat "trash " (s/strcat "trash " (quantify (value cost) "installed rezzed ice" "")))) (defmethod payable? :ice [cost state side eid card] (<= 0 (- (count (filter (every-pred installed? rezzed? ice?) (all-installed state :corp))) (value cost)))) @@ -643,7 +644,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed rezzed ice" "") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed rezzed ice" "") " to trash") :choices {:all true :max (value cost) :card (every-pred installed? rezzed? ice?)} @@ -652,7 +653,7 @@ :unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "installed rezzed ice" "") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "installed rezzed ice" "") " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :ice :paid/value (count async-result) @@ -662,7 +663,7 @@ ;; TrashFromDeck (defmethod value :trash-from-deck [cost] (:cost/amount cost)) (defmethod label :trash-from-deck [cost] - (str "trash " (quantify (value cost) "card") " from the top of your deck")) + (s/strcat "trash " (quantify (value cost) "card") " from the top of your deck")) (defmethod payable? :trash-from-deck [cost state side eid card] (<= 0 (- (count (get-in @state [side :deck])) (value cost)))) @@ -671,7 +672,7 @@ (wait-for (mill state side side (value cost)) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "card") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "card") " from the top of " (if (= :corp side) "R&D" "the stack")) :paid/type :trash-from-deck @@ -681,7 +682,7 @@ ;; TrashFromHand (defmethod value :trash-from-hand [cost] (:cost/amount cost)) (defmethod label :trash-from-hand [cost] - (str "trash " (quantify (value cost) "card") " from your hand")) + (s/strcat "trash " (quantify (value cost) "card") " from your hand")) (defmethod payable? :trash-from-hand [cost state side eid card] (<= 0 (- (count (get-in @state [side :hand])) (value cost)))) @@ -692,7 +693,7 @@ hand (if (= :corp side) "HQ" "the grip")] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "card") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "card") " to trash") :choices {:all true :max (value cost) :card select-fn} @@ -700,10 +701,10 @@ :effect (req (wait-for (trash-cards state side targets {:unpreventable true :seen false}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "card") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "card") (when (and (= :runner side) (pos? (count async-result))) - (str " (" (enumerate-str (map #(card-str state %) targets)) ")")) + (s/strcat " (" (enumerate-str (map #(card-str state %) targets)) ")")) " from " hand) :paid/type :trash-from-hand :paid/value (count async-result) @@ -713,7 +714,7 @@ ;; RandomlyTrashFromHand (defmethod value :randomly-trash-from-hand [cost] (:cost/amount cost)) (defmethod label :randomly-trash-from-hand [cost] - (str "trash " (quantify (value cost) "card") " randomly from your hand")) + (s/strcat "trash " (quantify (value cost) "card") " randomly from your hand")) (defmethod payable? :randomly-trash-from-hand [cost state side eid card] (<= 0 (- (count (get-in @state [side :hand])) (value cost)))) @@ -722,7 +723,7 @@ (wait-for (discard-from-hand state side side (value cost)) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "card") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "card") " randomly from " (if (= :corp side) "HQ" "the grip")) :paid/type :randomly-trash-from-hand @@ -740,11 +741,11 @@ (wait-for (trash-cards state side cards {:unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes all (" (count async-result) ") cards in " + {:paid/msg (s/strcat "trashes all (" (count async-result) ") cards in " (if (= :runner side) "[their] grip" "HQ") (when (and (= :runner side) (pos? (count async-result))) - (str " (" (enumerate-str (map :title async-result)) ")"))) + (s/strcat " (" (enumerate-str (map :title async-result)) ")"))) :paid/type :trash-entire-hand :paid/value (count async-result) :paid/targets async-result})))) @@ -752,7 +753,7 @@ ;; TrashHardwareFromHand (defmethod value :trash-hardware-from-hand [cost] (:cost/amount cost)) (defmethod label :trash-hardware-from-hand [cost] - (str "trash " (quantify (value cost) "piece") " of hardware in the grip")) + (s/strcat "trash " (quantify (value cost) "piece") " of hardware in the grip")) (defmethod payable? :trash-hardware-from-hand [cost state side eid card] (<= 0 (- (count (filter hardware? (get-in @state [:runner :hand]))) (value cost)))) @@ -760,7 +761,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "piece") " of hardware to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "piece") " of hardware to trash") :async true :choices {:all true :max (value cost) @@ -768,7 +769,7 @@ :effect (req (wait-for (trash-cards state side targets {:unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "piece") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "piece") " of hardware" " (" (enumerate-str (map :title targets)) ")" " from [their] grip") @@ -780,7 +781,7 @@ ;; TrashProgramFromHand (defmethod value :trash-program-from-hand [cost] (:cost/amount cost)) (defmethod label :trash-program-from-hand [cost] - (str "trash " (quantify (value cost) "program") " in the grip")) + (s/strcat "trash " (quantify (value cost) "program") " in the grip")) (defmethod payable? :trash-program-from-hand [cost state side eid card] (<= 0 (- (count (filter program? (get-in @state [:runner :hand]))) (value cost)))) @@ -788,7 +789,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "program") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "program") " to trash") :async true :choices {:all true :max (value cost) @@ -796,7 +797,7 @@ :effect (req (wait-for (trash-cards state side targets {:unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "program") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "program") " (" (enumerate-str (map :title targets)) ")" " from the grip") :paid/type :trash-program-from-hand @@ -807,7 +808,7 @@ ;; TrashResourceFromHand (defmethod value :trash-resource-from-hand [cost] (:cost/amount cost)) (defmethod label :trash-resource-from-hand [cost] - (str "trash " (quantify (value cost) "resource") " in the grip")) + (s/strcat "trash " (quantify (value cost) "resource") " in the grip")) (defmethod payable? :trash-resource-from-hand [cost state side eid card] (<= 0 (- (count (filter resource? (get-in @state [:runner :hand]))) (value cost)))) @@ -815,7 +816,7 @@ [cost state side eid card] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "resource") " to trash") + {:prompt (s/strcat "Choose " (quantify (value cost) "resource") " to trash") :async true :choices {:all true :max (value cost) @@ -823,7 +824,7 @@ :effect (req (wait-for (trash-cards state side targets {:unpreventable true}) (complete-with-result state side eid - {:paid/msg (str "trashes " (quantify (count async-result) "resource") + {:paid/msg (s/strcat "trashes " (quantify (count async-result) "resource") " (" (enumerate-str (map :title targets)) ")" " from the grip") :paid/type :trash-resource-from-hand @@ -833,7 +834,7 @@ ;; NetDamage (defmethod value :net [cost] (:cost/amount cost)) -(defmethod label :net [cost] (str "suffer " (value cost) " net damage")) +(defmethod label :net [cost] (s/strcat "suffer " (value cost) " net damage")) (defmethod payable? :net [cost state side eid card] (<= (value cost) (count (get-in @state [:runner :hand])))) @@ -842,14 +843,14 @@ (wait-for (damage state side :net (value cost) {:unpreventable true :card card}) (complete-with-result state side eid - {:paid/msg (str "suffers " (count async-result) " net damage") + {:paid/msg (s/strcat "suffers " (count async-result) " net damage") :paid/type :net :paid/value (count async-result) :paid/targets async-result}))) ;; MeatDamage (defmethod value :meat [cost] (:cost/amount cost)) -(defmethod label :meat [cost] (str "suffer " (value cost) " meat damage")) +(defmethod label :meat [cost] (s/strcat "suffer " (value cost) " meat damage")) (defmethod payable? :meat [cost state side eid card] (<= (value cost) (count (get-in @state [:runner :hand])))) @@ -858,14 +859,14 @@ (wait-for (damage state side :meat (value cost) {:unpreventable true :card card}) (complete-with-result state side eid - {:paid/msg (str "suffers " (count async-result) " meat damage") + {:paid/msg (s/strcat "suffers " (count async-result) " meat damage") :paid/type :meat :paid/value (count async-result) :paid/targets async-result}))) ;; BrainDamage (defmethod value :brain [cost] (:cost/amount cost)) -(defmethod label :brain [cost] (str "suffer " (value cost) " core damage")) +(defmethod label :brain [cost] (s/strcat "suffer " (value cost) " core damage")) (defmethod payable? :brain [cost state side eid card] (<= (value cost) (count (get-in @state [:runner :hand])))) @@ -874,7 +875,7 @@ (wait-for (damage state side :brain (value cost) {:unpreventable true :card card}) (complete-with-result state side eid - {:paid/msg (str "suffers " (count async-result) " core damage") + {:paid/msg (s/strcat "suffers " (count async-result) " core damage") :paid/type :brain :paid/value (count async-result) :paid/targets async-result}))) @@ -882,7 +883,7 @@ ;; ShuffleInstalledToDeck (defmethod value :shuffle-installed-to-stack [cost] (:cost/amount cost)) (defmethod label :shuffle-installed-to-stack [cost] - (str "shuffle " (quantify (value cost) "installed card") " into your deck")) + (s/strcat "shuffle " (quantify (value cost) "installed card") " into your deck")) (defmethod payable? :shuffle-installed-to-stack [cost state side eid card] (<= 0 (- (count (all-installed state side)) (value cost)))) @@ -890,7 +891,7 @@ [cost state side eid card] (continue-ability state :runner - {:prompt (str "Choose " (quantify (value cost) "installed card") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed card") " to shuffle into " (if (= :corp side) "R&D" "the stack")) :choices {:max (value cost) :all true @@ -900,7 +901,7 @@ (shuffle! state side :deck) (complete-with-result state side eid - {:paid/msg (str "shuffles " (quantify (count cards) "card") + {:paid/msg (s/strcat "shuffles " (quantify (count cards) "card") " (" (enumerate-str (map :title cards)) ")" " into " (if (= :corp side) "R&D" "the stack")) :paid/type :shuffle-installed-to-stack @@ -911,7 +912,7 @@ ;; AddInstalledToBottomOfDeck (defmethod value :add-installed-to-bottom-of-deck [cost] (:cost/amount cost)) (defmethod label :add-installed-to-bottom-of-deck [cost] - (str "add " (quantify (value cost) "installed card") " to the bottom of your deck")) + (s/strcat "add " (quantify (value cost) "installed card") " to the bottom of your deck")) (defmethod payable? :add-installed-to-bottom-of-deck [cost state side eid card] (<= 0 (- (count (all-installed state side)) (value cost)))) @@ -920,7 +921,7 @@ (let [deck (if (= :corp side) "R&D" "the stack")] (continue-ability state side - {:prompt (str "Choose " (quantify (value cost) "installed card") + {:prompt (s/strcat "Choose " (quantify (value cost) "installed card") " to move to the bottom of " deck) :choices {:max (value cost) :all true @@ -929,7 +930,7 @@ :effect (req (let [cards (keep #(move state side % :deck) targets)] (complete-with-result state side eid - {:paid/msg (str "adds " (quantify (count cards) "installed card") + {:paid/msg (s/strcat "adds " (quantify (count cards) "installed card") " to the bottom of " deck " (" (enumerate-str (map #(card-str state %) targets)) ")") :paid/type :add-installed-to-bottom-of-deck @@ -940,7 +941,7 @@ ;; AddRandomToBottom (defmethod value :add-random-from-hand-to-bottom-of-deck [cost] (:cost/amount cost)) (defmethod label :add-random-from-hand-to-bottom-of-deck [cost] - (str "add " (quantify (value cost) "random card") " to the bottom of your deck")) + (s/strcat "add " (quantify (value cost) "random card") " to the bottom of your deck")) (defmethod payable? :add-random-from-hand-to-bottom-of-deck [cost state side eid card] (<= (value cost) (count (get-in @state [side :hand])))) @@ -953,7 +954,7 @@ (move state side c :deck)) (complete-with-result state side eid - {:paid/msg (str "adds " (quantify (value cost) "random card") + {:paid/msg (s/strcat "adds " (quantify (value cost) "random card") " to the bottom of " deck) :paid/type :add-random-from-hand-to-bottom-of-deck :paid/value (value cost) @@ -978,8 +979,8 @@ (wait-for (trigger-event-sync state side :agenda-counter-spent target) (complete-with-result state side eid - {:paid/msg (str "spends " - (quantify (value cost) (str "hosted agenda counter")) + {:paid/msg (s/strcat "spends " + (quantify (value cost) (s/strcat "hosted agenda counter")) " from on " title) :paid/type :any-agenda-counter :paid/value (value cost) @@ -989,7 +990,7 @@ ;; AnyVirusCounter (defmethod value :any-virus-counter [cost] (:cost/amount cost)) (defmethod label :any-virus-counter [cost] - (str "any " (quantify (value cost) "virus counter"))) + (s/strcat "any " (quantify (value cost) "virus counter"))) (defmethod payable? :any-virus-counter [cost state side eid card] (<= 0 (- (number-of-virus-counters state) (value cost)))) @@ -998,7 +999,7 @@ (wait-for (resolve-ability state side (pick-virus-counters-to-spend (value cost)) card nil) (complete-with-result state side eid - {:paid/msg (str "spends " (:msg async-result)) + {:paid/msg (s/strcat "spends " (:msg async-result)) :paid/type :any-virus-counter :paid/value (:number async-result) :paid/targets (:targets async-result)}))) @@ -1019,8 +1020,8 @@ (wait-for (trigger-event-sync state side :counter-added card) (complete-with-result state side eid - {:paid/msg (str "spends " - (quantify (value cost) (str "hosted advancement counter")) + {:paid/msg (s/strcat "spends " + (quantify (value cost) (s/strcat "hosted advancement counter")) " from on " title) :paid/type :advancement :paid/value (value cost)})))) @@ -1041,7 +1042,7 @@ (wait-for (trigger-event-sync state side :agenda-counter-spent card) (complete-with-result state side eid - {:paid/msg (str "spends " + {:paid/msg (s/strcat "spends " (quantify (value cost) "hosted agenda counter") " from on " title) :paid/type :agenda @@ -1063,7 +1064,7 @@ (wait-for (trigger-event-sync state side :counter-added card) (complete-with-result state side eid - {:paid/msg (str "spends " + {:paid/msg (s/strcat "spends " (quantify (value cost) "hosted power counter") " from on " title) :paid/type :power @@ -1089,7 +1090,7 @@ (wait-for (trigger-event-sync state side :counter-added card) (complete-with-result state side eid - {:paid/msg (str "spends " + {:paid/msg (s/strcat "spends " (quantify cost "hosted power counter") " from on " title) :paid/type :x-power @@ -1119,7 +1120,7 @@ (wait-for (resolve-ability state side (pick-virus-counters-to-spend card (value cost)) card nil) (complete-with-result state side eid - {:paid/msg (str "spends " (:msg async-result)) + {:paid/msg (s/strcat "spends " (:msg async-result)) :paid/type :virus :paid/value (:number async-result) :paid/targets (:targets async-result)})) @@ -1128,8 +1129,8 @@ (wait-for (trigger-event-sync state side :counter-added card) (complete-with-result state side eid - {:paid/msg (str "spends " - (quantify (value cost) (str "hosted virus counter")) + {:paid/msg (s/strcat "spends " + (quantify (value cost) "hosted virus counter") " from on " title) :paid/type :virus :paid/value (value cost)}))))) diff --git a/src/clj/game/core/damage.clj b/src/clj/game/core/damage.clj index f10760f5c2..cff1c94b23 100644 --- a/src/clj/game/core/damage.clj +++ b/src/clj/game/core/damage.clj @@ -11,7 +11,8 @@ [game.core.winning :refer [flatline]] [game.macros :refer [wait-for]] [game.utils :refer [dissoc-in enumerate-str side-str]] - [jinteki.utils :refer [str->int]])) + [jinteki.utils :refer [str->int]] + [stringer.core :as s])) (defn damage-bonus "Registers a bonus of n damage to the next damage application of the given type." @@ -28,7 +29,7 @@ (defn prevention-prompt-msg [damage-amount damage-type prevented] - (str "Prevent " + (s/strcat "Prevent " (when (< 1 damage-amount) "any of the ") damage-amount " " (damage-name damage-type) " damage?" @@ -122,7 +123,7 @@ (when (= dmg-type :brain) (swap! state update-in [:runner :brain-damage] #(+ % n))) (when-let [trashed-msg (enumerate-str (map get-title cards-trashed))] - (system-msg state :runner (str "trashes " trashed-msg " due to " (damage-name dmg-type) " damage"))) + (system-msg state :runner (s/strcat "trashes " trashed-msg " due to " (damage-name dmg-type) " damage"))) (swap! state update-in [:stats :corp :damage :all] (fnil + 0) n) (swap! state update-in [:stats :corp :damage dmg-type] (fnil + 0) n) (if (< (count hand) n) @@ -160,17 +161,17 @@ (> n already-prevented)) ;; player can prevent damage (do (system-msg state player "has the option to prevent damage") - (show-wait-prompt state other-player (str (side-str player) " to prevent damage")) + (show-wait-prompt state other-player (s/strcat (side-str player) " to prevent damage")) (swap! state assoc-in [:prevent :current] type) (show-prompt state player nil - (str "Prevent " (when (< 1 (- n already-prevented)) "any of the ") (- n already-prevented) " " (damage-name type) " damage?") + (s/strcat "Prevent " (when (< 1 (- n already-prevented)) "any of the ") (- n already-prevented) " " (damage-name type) " damage?") ["Done"] (fn [_] (let [prevent (get-in @state [:damage :damage-prevent type]) damage-prevented (if prevent (- prevent already-prevented) false)] (system-msg state player (if damage-prevented - (str "prevents " + (s/strcat "prevents " (if (= damage-prevented Integer/MAX_VALUE) "all" damage-prevented) " " (damage-name type) " damage") "will not prevent damage")) diff --git a/src/clj/game/core/def_helpers.clj b/src/clj/game/core/def_helpers.clj index 3fca71831e..c52229debd 100644 --- a/src/clj/game/core/def_helpers.clj +++ b/src/clj/game/core/def_helpers.clj @@ -1,6 +1,5 @@ (ns game.core.def-helpers (:require - [clojure.string :as str] [game.core.access :refer [access-bonus]] [game.core.board :refer [all-installed]] [game.core.card :refer [active? can-be-advanced? corp? faceup? get-card get-counters has-subtype? in-discard?]] @@ -21,12 +20,13 @@ [game.core.toasts :refer [toast]] [game.macros :refer [continue-ability effect msg req wait-for]] [game.utils :refer [enumerate-str remove-once same-card? server-card to-keyword]] - [jinteki.utils :refer [other-side]])) + [jinteki.utils :refer [other-side]] + [stringer.core :as s])) (defn combine-abilities "Combines two or more abilities to a single one. Labels are joined together with a period between parts." ([ab-x ab-y] - {:label (str (:label ab-x) ". " (:label ab-y)) + {:label (s/strcat (:label ab-x) ". " (:label ab-y)) :async true :effect (req (wait-for (resolve-ability state side ab-x card nil) (continue-ability state side ab-y card nil)))}) @@ -54,7 +54,7 @@ ([reorder-side wait-side remaining chosen n original] (reorder-choice reorder-side wait-side remaining chosen n original nil)) ([reorder-side wait-side remaining chosen n original dest] (when (not-empty remaining) - {:prompt (str "Choose a card to move next " + {:prompt (s/strcat "Choose a card to move next " (if (= dest "bottom") "under " "onto ") (if (= reorder-side :corp) "R&D" "the stack")) :choices remaining @@ -77,9 +77,9 @@ ([reorder-side wait-side chosen original] (reorder-final reorder-side wait-side chosen original nil)) ([reorder-side wait-side chosen original dest] {:prompt (if (= dest "bottom") - (str "The bottom cards of " (if (= reorder-side :corp) "R&D" "the stack") + (s/strcat "The bottom cards of " (if (= reorder-side :corp) "R&D" "the stack") " will be " (enumerate-str (map :title (reverse chosen))) ".") - (str "The top cards of " (if (= reorder-side :corp) "R&D" "the stack") + (s/strcat "The top cards of " (if (= reorder-side :corp) "R&D" "the stack") " will be " (enumerate-str (map :title chosen)) ".")) :choices ["Done" "Start over"] :async true @@ -123,25 +123,25 @@ (defn do-net-damage "Do specified amount of net-damage." [dmg] - {:label (str "Do " dmg " net damage") + {:label (s/strcat "Do " dmg " net damage") :async true - :msg (str "do " dmg " net damage") + :msg (s/strcat "do " dmg " net damage") :effect (effect (damage eid :net dmg {:card card}))}) (defn do-meat-damage "Do specified amount of meat damage." [dmg] - {:label (str "Do " dmg " meat damage") + {:label (s/strcat "Do " dmg " meat damage") :async true - :msg (str "do " dmg " meat damage") + :msg (s/strcat "do " dmg " meat damage") :effect (effect (damage eid :meat dmg {:card card}))}) (defn do-brain-damage "Do specified amount of core damage." [dmg] - {:label (str "Do " dmg " core damage") + {:label (s/strcat "Do " dmg " core damage") :async true - :msg (str "do " dmg " core damage") + :msg (s/strcat "do " dmg " core damage") :effect (effect (damage eid :brain dmg {:card card}))}) (defn rfg-on-empty @@ -150,7 +150,7 @@ {:event :counter-added :req (req (and (same-card? card target) (not (pos? (get-counters card counter-type))))) - :effect (effect (system-msg (str "removes " (:title card) " from the game")) + :effect (effect (system-msg (s/strcat "removes " (:title card) " from the game")) (move card :rfg))}) (defn trash-on-empty @@ -160,7 +160,7 @@ :req (req (and (same-card? card target) (not (pos? (get-counters card counter-type))))) :async true - :effect (effect (system-msg (str "trashes " (:title card))) + :effect (effect (system-msg (s/strcat "trashes " (:title card))) (trash eid card {:unpreventable true :source-card card}))}) (defn make-recurring-ability @@ -181,9 +181,9 @@ (let [side (to-keyword (:side card)) title (:title card)] (if (:rfg-instead-of-trashing card) - (do (system-say state side (str title " is removed from the game.")) + (do (system-say state side (s/strcat title " is removed from the game.")) (async-rfg state side eid card)) - (do (system-say state side (str title " is trashed.")) + (do (system-say state side (s/strcat title " is trashed.")) (trash state side eid card {:unpreventable true :game-trash true}))))) (defn offer-jack-out @@ -200,9 +200,9 @@ :prompt "Jack out?" :waiting-prompt true :yes-ability {:async true - :effect (effect (system-msg :runner (str "uses " (:title card) " to jack out")) + :effect (effect (system-msg :runner (s/strcat "uses " (:title card) " to jack out")) (jack-out eid))} - :no-ability {:effect (effect (system-msg :runner (str "uses " (:title card) " to continue the run")))}}})) + :no-ability {:effect (effect (system-msg :runner (s/strcat "uses " (:title card) " to continue the run")))}}})) (defn get-x-fn [] (fn get-x-fn-inner @@ -287,7 +287,7 @@ (if-not (:cost x) (:option x) (let [cs (build-cost-string (:cost x))] - (if-not (:option x) cs (str cs ": " (:option x)))))) + (if-not (:option x) cs (s/strcat cs ": " (:option x)))))) ;; converts options to choices choices-fn (fn [x state side eid card targets] (when (payable? x state side eid card targets) @@ -325,9 +325,9 @@ base-map {:choices (req (into [] (map #(choices-fn % state side eid card targets) xs))) :waiting-prompt (not no-wait-msg) - :prompt (str (or (:prompt args) "Choose one") + :prompt (s/strcat (or (:prompt args) "Choose one") ;; if we are resolving multiple - (when (and count (pos? count)) (str " (" count " remaining)"))) + (when (and count (pos? count)) (s/strcat " (" count " remaining)"))) :req (or meaningful-req? (:req args)) ;; resolve-choices demands async :async true diff --git a/src/clj/game/core/drawing.clj b/src/clj/game/core/drawing.clj index 5283d32ab0..9d546eab81 100644 --- a/src/clj/game/core/drawing.clj +++ b/src/clj/game/core/drawing.clj @@ -11,7 +11,8 @@ [game.core.winning :refer [win-decked]] [game.macros :refer [continue-ability msg req wait-for]] [game.utils :refer [quantify safe-zero?]] - [jinteki.utils :refer [other-side]])) + [jinteki.utils :refer [other-side]] + [stringer.core :as s])) (defn max-draw "Put an upper limit on the number of cards that can be drawn in this turn." @@ -44,7 +45,7 @@ (defn first-time-draw-bonus [side n] - (let [event (keyword (str "pre-" (name side) "-draw"))] + (let [event (keyword (s/strcat "pre-" (name side) "-draw"))] {:event event :msg "draw 1 additional card" ;; The req catches draw events that happened before the card was installed @@ -72,7 +73,7 @@ (when (< draws-after-prevent draws-wanted) (let [prevented (- draws-wanted draws-after-prevent)] (system-msg state (other-side side) - (str "prevents " (quantify prevented "card") " from being drawn")))) + (s/strcat "prevents " (quantify prevented "card") " from being drawn")))) (if (or (and (= side active-player) (get-in @state [side :register :cannot-draw])) (not (pos? draws-after-prevent)) @@ -113,11 +114,11 @@ (draw state side eid n args) (continue-ability state side - {:optional {:prompt (str "Draw " (quantify n "card") "?") + {:optional {:prompt (s/strcat "Draw " (quantify n "card") "?") :yes-ability {:async true :msg (msg "draw " (quantify n " card")) :effect (req (draw state side eid n))} - :no-ability {:effect (req (system-msg state side (str "declines to use " (get-title card) " to draw cards")))}}} + :no-ability {:effect (req (system-msg state side (s/strcat "declines to use " (get-title card) " to draw cards")))}}} card nil)))) (defn draw-up-to @@ -127,7 +128,7 @@ (draw state side eid 0 args) (continue-ability state side - {:prompt (str "Draw how many cards?" (when-not allow-zero-draws " (minimum 1)")) + {:prompt (s/strcat "Draw how many cards?" (when-not allow-zero-draws " (minimum 1)")) :choices {:number (req n) :max (req n) :default (req n)} diff --git a/src/clj/game/core/engine.clj b/src/clj/game/core/engine.clj index 068d34a716..ab59259586 100644 --- a/src/clj/game/core/engine.clj +++ b/src/clj/game/core/engine.clj @@ -21,7 +21,8 @@ [game.utils :refer [dissoc-in distinct-by enumerate-str in-coll? remove-once same-card? server-cards side-str to-keyword]] [jinteki.utils :refer [other-side]] [game.core.memory :refer [update-mu]] - [game.core.to-string :refer [card-str]])) + [game.core.to-string :refer [card-str]] + [stringer.core :as s])) ;; resolve-ability docs @@ -285,7 +286,7 @@ :else (.println *err* (with-out-str (print-stack-trace - (Exception. (str "Ability is nil????" ability card targets)) + (Exception. (s/strcat "Ability is nil????" ability card targets)) 2500))))) ;;; Checking functions for resolve-ability @@ -312,9 +313,9 @@ disp-side (or (:display-side ability) (to-keyword (:side card)))] (cond (= :cost desc) - (system-msg state disp-side (str payment-str " to satisfy " (get-title card))) + (system-msg state disp-side (s/strcat payment-str " to satisfy " (get-title card))) desc - (system-msg state disp-side (str cost-spend-msg (get-title card) (str " to " desc))))))) + (system-msg state disp-side (s/strcat cost-spend-msg (get-title card) (s/strcat " to " desc))))))) (defn register-once "Register ability as having happened if :once specified" @@ -325,7 +326,7 @@ (defn do-nothing "Does nothing (loudly)" [state side eid card] - (system-msg state side (str "uses " (:title card) " to do nothing")) + (system-msg state side (s/strcat "uses " (:title card) " to do nothing")) (effect-completed state side eid)) (defn- change-in-game-state? @@ -392,9 +393,9 @@ {:eid (select-keys eid [:eid]) :card card :prompt-type :waiting - :msg (str "Waiting for " + :msg (s/strcat "Waiting for " (if (true? waiting-prompt) - (str (side-str side) " to make a decision") + (s/strcat (side-str side) " to make a decision") waiting-prompt))})) (if (seq cost) ;; Ensure that any costs can be paid @@ -815,7 +816,7 @@ [event] (if (keyword? event) (name event) - (str event))) + (s/strcat event))) (defn trigger-event-simult "Triggers the given event by showing a prompt of all handlers for the event, allowing manual resolution of @@ -854,14 +855,14 @@ opponent-events (get-handlers opponent)] (wait-for (resolve-ability state side (make-eid state eid) first-ability nil nil) (show-wait-prompt state opponent - (str (side-str active-player) " to resolve " (event-title event) " triggers")) + (s/strcat (side-str active-player) " to resolve " (event-title event) " triggers")) ; let active player activate their events first (wait-for (trigger-event-simult-player state side (make-eid state eid) active-player-events cancel-fn targets) (when after-active-player (resolve-ability state side eid after-active-player nil nil)) (clear-wait-prompt state opponent) (show-wait-prompt state active-player - (str (side-str opponent) " to resolve " (event-title event) " triggers")) + (s/strcat (side-str opponent) " to resolve " (event-title event) " triggers")) (wait-for (trigger-event-simult-player state opponent (make-eid state eid) opponent-events cancel-fn targets) (clear-wait-prompt state active-player) (effect-completed state side eid)))))))) @@ -1014,10 +1015,10 @@ opponent (other-side active-player) active-player-handlers (filter-handlers handlers active-player) opponent-handlers (filter-handlers handlers opponent)] - (show-wait-prompt state opponent (str (side-str active-player) " to resolve pending triggers")) + (show-wait-prompt state opponent (s/strcat (side-str active-player) " to resolve pending triggers")) (wait-for (trigger-queued-event-player state active-player (make-eid state eid) active-player-handlers args) (clear-wait-prompt state opponent) - (show-wait-prompt state active-player (str (side-str opponent) " to resolve pending triggers")) + (show-wait-prompt state active-player (s/strcat (side-str opponent) " to resolve pending triggers")) (wait-for (trigger-queued-event-player state opponent (make-eid state eid) opponent-handlers args) (clear-wait-prompt state active-player) (effect-completed state nil eid)))) @@ -1095,7 +1096,7 @@ :unpreventable true}) (doseq [card cards-to-trash] (system-say state (to-keyword (:side card)) - (str (card-str state card) " is trashed."))) + (s/strcat (card-str state card) " is trashed."))) (effect-completed state nil eid)) (effect-completed state nil eid)))) @@ -1110,7 +1111,7 @@ {:unpreventable true}) (doseq [card trash-when-tagged] (system-say state (to-keyword (:side card)) - (str "trashes " (card-str state card) " for being tagged"))) + (s/strcat "trashes " (card-str state card) " for being tagged"))) (effect-completed state nil eid)) (effect-completed state nil eid)))) diff --git a/src/clj/game/core/expose.clj b/src/clj/game/core/expose.clj index 838695f87a..c70a14ec21 100644 --- a/src/clj/game/core/expose.clj +++ b/src/clj/game/core/expose.clj @@ -8,7 +8,8 @@ [game.core.prompts :refer [clear-wait-prompt show-prompt show-wait-prompt]] [game.core.say :refer [system-msg]] [game.core.to-string :refer [card-str]] - [game.macros :refer [wait-for]])) + [game.macros :refer [wait-for]] + [stringer.core :as s])) (defn expose-prevent [state _ n] @@ -16,7 +17,7 @@ (defn- resolve-expose [state side eid target] - (system-msg state side (str "exposes " (card-str state target {:visible true}))) + (system-msg state side (s/strcat "exposes " (card-str state target {:visible true}))) (if-let [ability (:on-expose (card-def target))] (wait-for (resolve-ability state side ability target nil) (trigger-event-sync state side (make-result eid target) :expose target)) @@ -38,7 +39,7 @@ (do (system-msg state :corp "has the option to prevent a card from being exposed") (show-wait-prompt state :runner "Corp to prevent the expose") (show-prompt state :corp nil - (str "Prevent " (:title target) " from being exposed?") ["Done"] + (s/strcat "Prevent " (:title target) " from being exposed?") ["Done"] (fn [_] (clear-wait-prompt state :runner) (if (get-in @state [:expose :expose-prevent]) diff --git a/src/clj/game/core/flags.clj b/src/clj/game/core/flags.clj index e6e31cb692..73ed261db8 100644 --- a/src/clj/game/core/flags.clj +++ b/src/clj/game/core/flags.clj @@ -8,7 +8,8 @@ [game.core.servers :refer [zone->name]] [game.core.to-string :refer [card-str]] [game.core.toasts :refer [toast]] - [game.utils :refer [enumerate-str same-card? same-side?]])) + [game.utils :refer [enumerate-str same-card? same-side?]] + [stringer.core :as s])) (defn card-flag? "Checks the card to see if it has a :flags entry of the given flag-key, and with the given value if provided" @@ -225,10 +226,10 @@ :persistent-flag false ;; Uniqueness :unique (or ignore-unique - (reason-toast (str "Cannot rez a second copy of " title " since it is unique. Please trash the other" + (reason-toast (s/strcat "Cannot rez a second copy of " title " since it is unique. Please trash the other" " copy first"))) ;; Rez requirement - :req (reason-toast (str "Rez requirements for " title " are not fulfilled")))))) + :req (reason-toast (s/strcat "Rez requirements for " title " are not fulfilled")))))) (defn can-steal? "Checks if the runner can steal agendas" @@ -250,7 +251,7 @@ (let [cards (->> @state :stack :current-turn :can-run (map :card))] (if (empty? cards) true - (do (when-not silent (toast state side (str "Cannot run due to " (enumerate-str (map :title cards)))) + (do (when-not silent (toast state side (s/strcat "Cannot run due to " (enumerate-str (map :title cards)))) false)))))) (defn can-access? @@ -264,7 +265,7 @@ (let [cards (get-preventing-cards state side card :can-access [:current-run :current-turn :persistent])] (if (empty? cards) true - (do (toast state side (str "Cannot access " (card-str state card) " because of " (enumerate-str (map :title cards))) "info") + (do (toast state side (s/strcat "Cannot access " (card-str state card) " because of " (enumerate-str (map :title cards))) "info") false)))) (defn can-advance? diff --git a/src/clj/game/core/ice.clj b/src/clj/game/core/ice.clj index e579dc2d22..a8cfdf8506 100644 --- a/src/clj/game/core/ice.clj +++ b/src/clj/game/core/ice.clj @@ -15,7 +15,8 @@ [jinteki.utils :refer [make-label]] [clojure.string :as string] [clojure.set :as set] - [medley.core :refer [find-first]])) + [medley.core :refer [find-first]] + [stringer.core :as s])) ;; These should be in runs.clj, but `req` needs get-current-ice and ;; moving.clj needs set-current-ice @@ -309,7 +310,7 @@ ([state side eid ice] (if-let [subroutines (seq (remove #(or (:broken %) (= false (:resolve %))) (:subroutines ice)))] (wait-for (resolve-next-unbroken-sub state side (make-eid state eid) ice subroutines) - (system-msg state :corp (str "resolves " (quantify (count async-result) "unbroken subroutine") + (system-msg state :corp (s/strcat "resolves " (quantify (count async-result) "unbroken subroutine") " on " (:title ice) " (\"[subroutine] " (string/join "\" and \"[subroutine] " @@ -486,9 +487,9 @@ ([ice target-count broken-subs] (break-subroutines-impl ice target-count broken-subs nil)) ([ice target-count broken-subs args] {:async true - :prompt (str "Break a subroutine" + :prompt (s/strcat "Break a subroutine" (when (and target-count (< 1 target-count)) - (str " (" (count broken-subs) + (s/strcat " (" (count broken-subs) " of " target-count ")"))) :choices (req (concat (breakable-subroutines-choice state side eid card ice) (when-not (and (:all args) @@ -519,14 +520,14 @@ (defn break-subroutines-msg ([ice broken-subs breaker] (break-subroutines-msg ice broken-subs breaker nil)) ([ice broken-subs breaker args] - (str "use " (:title breaker) + (s/strcat "use " (:title breaker) " to break " (quantify (count broken-subs) - (str (when-let [subtypes (:subtype args)] + (s/strcat (when-let [subtypes (:subtype args)] (when-not (= #{"All"} subtypes) (-> subtypes (set/intersection (set (:subtypes ice))) (first) - (str " ")))) + (s/strcat " ")))) "subroutine")) " on " (:title ice) " (\"[subroutine] " @@ -567,7 +568,7 @@ (wait-for (pay state side card total-cost) (if-let [payment-str (:msg async-result)] (do (when (not (string/blank? message)) - (system-msg state :runner (str payment-str " to " message))) + (system-msg state :runner (s/strcat payment-str " to " message))) (doseq [sub broken-subs] (break-subroutine! state (get-card state ice) sub breaker) (resolve-ability state side (make-eid state {:source card @@ -598,7 +599,7 @@ (when-let [cost (find-first #(= :credit (:cost/type %)) (flatten [cost]))] (let [stealth (stealth-value cost)] (when (pos? stealth) - (str " (using at least " stealth " stealth [Credits])"))))) + (s/strcat " (using at least " stealth " stealth [Credits])"))))) (defn break-sub "Creates a break subroutine ability. @@ -646,12 +647,12 @@ :auto-break-sort (:auto-break-sort args) :break-cost-bonus (:break-cost-bonus args) :additional-ability (:additional-ability args) - :label (str (or (:label args) - (str "break " + :label (s/strcat (or (:label args) + (s/strcat "break " (when (< 1 n) "up to ") (if (pos? n) n "any number of") (when-not (= #{"All"} subtypes) - (str " " (string/join " or " (sort subtypes)))) + (s/strcat " " (string/join " or " (sort subtypes)))) (pluralize " subroutine" n) (add-stealth-to-label cost)))) :effect (effect (continue-ability @@ -679,8 +680,8 @@ " for the remainder of the run" (= duration :end-of-turn) " for the remainder of the turn")] - {:label (str (or (:label args) - (str "add " strength " strength" + {:label (s/strcat (or (:label args) + (s/strcat "add " strength " strength" duration-string (add-stealth-to-label cost)))) :req (req (if-let [str-req (:req args)] @@ -771,7 +772,7 @@ [{:dynamic :auto-pump-and-break :cost total-cost :cost-label (build-cost-label total-cost) - :label (str (if (and pump-ability (pos? times-pump)) + :label (s/strcat (if (and pump-ability (pos? times-pump)) "Match strength and fully break " "Fully break ") (:title current-ice))}]) @@ -781,7 +782,7 @@ [{:dynamic :auto-pump :cost total-pump-cost :cost-label (build-cost-label total-pump-cost) - :label (str "Match strength of " (:title current-ice))}]))) + :label (s/strcat "Match strength of " (:title current-ice))}]))) abs)))))}) ;; Takes a a card definition, and returns a new card definition that diff --git a/src/clj/game/core/initializing.clj b/src/clj/game/core/initializing.clj index 0959785c03..60f940cc2f 100644 --- a/src/clj/game/core/initializing.clj +++ b/src/clj/game/core/initializing.clj @@ -16,7 +16,8 @@ [game.core.update :refer [update!]] [game.macros :refer [req]] [game.utils :refer [make-cid server-card to-keyword]] - [jinteki.utils :refer [make-label]])) + [jinteki.utils :refer [make-label]] + [stringer.core :as s])) (defn subroutines-init "Initialised the subroutines associated with the card, these work as abilities" @@ -110,7 +111,7 @@ (cond (fn? recurring) (recurring state side eid c nil) (number? recurring) recurring - :else (throw (Exception. (str (:title card) " - Recurring isn't number or fn"))))})) + :else (throw (Exception. (s/strcat (:title card) " - Recurring isn't number or fn"))))})) _ (when recurring (update! state side (assoc-in c [:counter :recurring] 0))) _ (doseq [[c-type c-num] data] (add-counter state side (get-card state c) c-type c-num {:placed true})) @@ -176,7 +177,7 @@ (when-let [cdef (card-def card)] ;; Card is defined - hence implemented (if-let [impl (:implementation cdef)] - (if (:recurring cdef) (str impl ". Recurring credits usage not restricted") impl) + (if (:recurring cdef) (s/strcat impl ". Recurring credits usage not restricted") impl) (if (:recurring cdef) "Recurring credits usage not restricted" :full)))) (defn make-card diff --git a/src/clj/game/core/installing.clj b/src/clj/game/core/installing.clj index d4e0bd8a7e..bc4940220d 100644 --- a/src/clj/game/core/installing.clj +++ b/src/clj/game/core/installing.clj @@ -28,12 +28,13 @@ [game.core.update :refer [update!]] [game.macros :refer [continue-ability effect req wait-for]] [game.utils :refer [dissoc-in in-coll? same-card? to-keyword quantify]] - [medley.core :refer [find-first]])) + [medley.core :refer [find-first]] + [stringer.core :as s])) (defn install-locked? "Checks if installing is locked" [state side] - (let [kw (keyword (str (name side) "-lock-install"))] + (let [kw (keyword (s/strcat (name side) "-lock-install"))] (or (seq (get-in @state [:stack :current-run kw])) (seq (get-in @state [:stack :current-turn kw])) (seq (get-in @state [:stack :persistent kw]))))) @@ -79,16 +80,16 @@ (case reason ;; failed install lock check :lock-install - (reason-toast (str "Unable to install " title ", installing is currently locked")) + (reason-toast (s/strcat "Unable to install " title ", installing is currently locked")) ;; failed ice check :ice - (reason-toast (str "Unable to install " title ": can only install 1 piece of ice per turn")) + (reason-toast (s/strcat "Unable to install " title ": can only install 1 piece of ice per turn")) ;; Earth station cannot have more than one remote server :earth-station - (reason-toast (str "Unable to install " title " in new remote: Earth Station limit")) + (reason-toast (s/strcat "Unable to install " title " in new remote: Earth Station limit")) ;; A Teia can only have two remotes :a-teia - (reason-toast (str "Unable to install " title " in new remote: A Teia limit")) + (reason-toast (s/strcat "Unable to install " title " in new remote: A Teia limit")) ;; else true))) @@ -97,10 +98,10 @@ [state side eid prev-card server] (continue-ability state side - {:prompt (str "The " (:title prev-card) " in " server " will now be trashed.") + {:prompt (s/strcat "The " (:title prev-card) " in " server " will now be trashed.") :choices ["OK"] :async true - :effect (req (system-msg state :corp (str "trashes " (card-str state prev-card))) + :effect (req (system-msg state :corp (s/strcat "trashes " (card-str state prev-card))) (if (get-card state prev-card) ; make sure they didn't trash the card themselves (trash state :corp eid prev-card {:keep-server-alive true}) (effect-completed state :corp eid)))} @@ -137,7 +138,7 @@ [{:keys [advance-counter] :as counters}] ;; TODO - rewrite this if/when we support more counter types through installs (if advance-counter - (str ", and place " (quantify advance-counter "Advancement counter") " on it") + (s/strcat ", and place " (quantify advance-counter "Advancement counter") " on it") "")) (defn- corp-install-message @@ -154,17 +155,17 @@ (:title card) (if (ice? card) "ice" "a card")) server-name (if (= server "New remote") - (str (remote-num->name (dec (:rid @state))) " (new remote)") + (s/strcat (remote-num->name (dec (:rid @state))) " (new remote)") server) origin (if display-origin - (str " from " - (when origin-index (str " position " (inc origin-index) " of ")) + (s/strcat " from " + (when origin-index (s/strcat " position " (inc origin-index) " of ")) (name-zone :corp (:zone card))) "") lhs (if install-source - (str (build-spend-msg cost-str "use") (:title install-source) " to install ") + (s/strcat (build-spend-msg cost-str "use") (:title install-source) " to install ") (build-spend-msg cost-str "install"))] - (system-msg state side (str lhs card-name origin + (system-msg state side (s/strcat lhs card-name origin (if (ice? card) " protecting " " in ") server-name (format-counters-msg counters))) (when (and (= :face-up install-state) @@ -175,7 +176,7 @@ (defn corp-install-msg "Gets a message describing where a card has been installed from. Example: Interns." [card] - (str "install " (if (:seen card) (:title card) "an unseen card") " from " (name-zone :corp (:zone card)))) + (s/strcat "install " (if (:seen card) (:title card) "an unseen card") " from " (name-zone :corp (:zone card)))) (defn reveal-if-unrezzed "Used to reveal a card if it cannot be rezzed when an instruction says to rez it @@ -188,7 +189,7 @@ (wait-for (checkpoint state nil) (complete-with-result state side eid (get-card state moved-card))) (wait-for (reveal state :corp rezzed-card) - (system-msg state :corp (str "reveals " (card-str state rezzed-card {:visible true}))) + (system-msg state :corp (s/strcat "reveals " (card-str state rezzed-card {:visible true}))) (wait-for (checkpoint state nil) (complete-with-result state side eid (get-card state moved-card))))))) @@ -344,7 +345,7 @@ ;; No server selected; show prompt to select an install site (Interns, Lateral Growth, etc.) (not server) (continue-ability state side - {:prompt (str "Choose a location to install " (:title card)) + {:prompt (s/strcat "Choose a location to install " (:title card)) :choices (installable-servers state card) :async true :effect (effect (corp-install eid card target args))} @@ -388,11 +389,11 @@ title (:title card)] (case reason :lock-install - (reason-toast (str "Unable to install " title " since installing is currently locked")) + (reason-toast (s/strcat "Unable to install " title " since installing is currently locked")) :req - (reason-toast (str "Installation requirements are not fulfilled for " title)) + (reason-toast (s/strcat "Installation requirements are not fulfilled for " title)) :locked-zone - (reason-toast (str "Unable to install " title " because it is currently in a locked zone")) + (reason-toast (s/strcat "Unable to install " title " because it is currently in a locked zone")) ;; else true)))) @@ -407,41 +408,41 @@ discount-str (cond ignore-all-cost " (ignoring all costs)" ignore-install-cost " (ignoring it's install cost)" - (and cost-bonus (pos? cost-bonus)) (str " (paying " cost-bonus " [Credits] more)") - (and cost-bonus (neg? cost-bonus)) (str " (paying " (* -1 cost-bonus) " [Credits] less)") + (and cost-bonus (pos? cost-bonus)) (s/strcat " (paying " cost-bonus " [Credits] more)") + (and cost-bonus (neg? cost-bonus)) (s/strcat " (paying " (* -1 cost-bonus) " [Credits] less)") :else nil) card-name (if facedown (if known - (str (:title card) " as a facedown card") + (s/strcat (:title card) " as a facedown card") "a card facedown") (:title card)) origin (if (and display-origin (not= (:previous-zone card) [:onhost])) - (str " from " - (when origin-index (str " position " (inc origin-index) " of ")) + (s/strcat " from " + (when origin-index (s/strcat " position " (inc origin-index) " of ")) (cond (= (:previous-zone card) [:set-aside]) "among the set-aside cards" :else - (str "the " (name-zone :runner (:previous-zone card))))) + (s/strcat "the " (name-zone :runner (:previous-zone card))))) "") pre-lhs (when (every? (complement string/blank?) [cost-str prepend-cost-str]) - (str prepend-cost-str ", and then ")) + (s/strcat prepend-cost-str ", and then ")) from-host? (when (and display-origin (= (:previous-zone card) [:onhost])) "hosted ") modified-cost-str (if (string/blank? cost-str) prepend-cost-str (if (string/blank? pre-lhs) cost-str - (str cost-str ","))) + (s/strcat cost-str ","))) lhs (if install-source - (str (build-spend-msg modified-cost-str "use") (:title install-source) " to install ") + (s/strcat (build-spend-msg modified-cost-str "use") (:title install-source) " to install ") (build-spend-msg modified-cost-str "install"))] (when (:display-message args true) (if custom-message (system-msg state side (custom-message cost-str)) (system-msg state side - (str pre-lhs lhs from-host? card-name origin discount-str - (when host-card (str " on " (card-str state host-card))) + (s/strcat pre-lhs lhs from-host? card-name origin discount-str + (when host-card (s/strcat " on " (card-str state host-card))) (when no-cost " at no cost"))))))) (defn runner-install-continue @@ -575,7 +576,7 @@ (if (pos? to-eliminate) (continue-ability state side - {:prompt (str (:title potential-host) " can only handle " max-mu " MU of programs - trash programs on " (:title card) " worth at least " to-eliminate " MU") + {:prompt (s/strcat (:title potential-host) " can only handle " max-mu " MU of programs - trash programs on " (:title card) " worth at least " to-eliminate " MU") :choices {:req (req (and (program? target) (some #(same-card? % target) relevant-cards))) :max (count relevant-cards) @@ -607,7 +608,7 @@ (if (pos? to-destroy) (continue-ability state side - {:prompt (str "Insufficient Space - Choose at least " (quantify to-destroy "card") " on " (:title potential-host) " to trash") + {:prompt (s/strcat "Insufficient Space - Choose at least " (quantify to-destroy "card") " on " (:title potential-host) " to trash") :choices {:req (req (some #(same-card? % target) relevant-cards)) :min to-destroy :max (count relevant-cards)} @@ -626,7 +627,7 @@ (continue-ability state side {:choices (conj potential-hosts "The Rig") - :prompt (str "Choose a destination for " (:title card)) + :prompt (s/strcat "Choose a destination for " (:title card)) :async true :effect (req (if (= target "The Rig") (runner-install-pay state side eid card args) @@ -655,7 +656,7 @@ (continue-ability state side {:choices hosting - :prompt (str "Choose a card to host " (:title card) " on") + :prompt (s/strcat "Choose a card to host " (:title card) " on") :async true :effect (effect (runner-install-pay eid card (assoc args :host-card target)))} card nil) diff --git a/src/clj/game/core/mark.clj b/src/clj/game/core/mark.clj index 1690f88990..da82f76c30 100644 --- a/src/clj/game/core/mark.clj +++ b/src/clj/game/core/mark.clj @@ -4,7 +4,8 @@ [game.core.say :refer [system-msg]] [game.core.servers :refer [central->name]] [game.core.update :refer [update!]] - [game.macros :refer [req]])) + [game.macros :refer [req]] + [stringer.core :as s])) (defn set-mark [state new-mark] @@ -19,7 +20,7 @@ [state] (let [new-mark (rand-nth [:hq :rd :archives])] (set-mark state new-mark) - (system-msg state :runner (str "identifies [their] mark to be " (central->name new-mark))))) + (system-msg state :runner (s/strcat "identifies [their] mark to be " (central->name new-mark))))) (def identify-mark-ability {:effect (req (when (nil? (:mark @state)) (identify-mark state)))}) diff --git a/src/clj/game/core/memory.clj b/src/clj/game/core/memory.clj index 689e47e7ec..87dd72aaf2 100644 --- a/src/clj/game/core/memory.clj +++ b/src/clj/game/core/memory.clj @@ -5,7 +5,8 @@ [game.core.card-defs :refer [card-def]] [game.core.eid :refer [make-eid]] [game.core.effects :refer [get-effect-maps get-effect-value get-effects is-disabled-reg? register-lingering-effect]] - [game.core.toasts :refer [toast]])) + [game.core.toasts :refer [toast]] + [stringer.core :as s])) (defn mu+ "For use in :static-abilities and register-lingering-effect. @@ -19,7 +20,7 @@ :value (cond+ [(or (vector? value) (fn? value)) value] [(number? value) [:regular value]] - [:else (throw (Exception. (str "mu+ needs a vector, number, or function: " value)))])})) + [:else (throw (Exception. (s/strcat "mu+ needs a vector, number, or function: " value)))])})) (defn virus-mu+ "For use in :static-abilities and register-lingering-effect. @@ -30,7 +31,7 @@ ([req value] (mu+ req (cond+ [(or (vector? value) (fn? value)) value] [(number? value) [:virus value]] - [:else (throw (Exception. (str "virus-mu+ needs a vector, number, or function: " value)))])))) + [:else (throw (Exception. (s/strcat "virus-mu+ needs a vector, number, or function: " value)))])))) (defn caissa-mu+ "For use in :static-abilities and register-lingering-effect. @@ -41,7 +42,7 @@ ([req value] (mu+ req (cond+ [(or (vector? value) (fn? value)) value] [(number? value) [:caissa value]] - [:else (throw (Exception. (str "caissa-mu+ needs a vector, number, or function: " value)))])))) + [:else (throw (Exception. (s/strcat "caissa-mu+ needs a vector, number, or function: " value)))])))) (defn available-mu "Returns the available MU the runner has" diff --git a/src/clj/game/core/moving.clj b/src/clj/game/core/moving.clj index 8662f271a8..3cd4bee5f5 100644 --- a/src/clj/game/core/moving.clj +++ b/src/clj/game/core/moving.clj @@ -21,7 +21,8 @@ [game.core.winning :refer [check-win-by-agenda]] [game.macros :refer [wait-for when-let*]] [game.utils :refer [dissoc-in make-cid remove-once same-card? same-side? to-keyword]] - [medley.core :refer [insert-nth]])) + [medley.core :refer [insert-nth]] + [stringer.core :as s])) ;; Helpers for move (defn- remove-old-card @@ -285,7 +286,7 @@ (when (and (not unpreventable) (not= cause :ability-cost)) (swap! state update-in [:trash :trash-prevent] dissoc ktype)) - (let [type (->> ktype name (str "trash-") keyword) + (let [type (->> ktype name (s/strcat "trash-") keyword) prevent (get-prevent-list state :runner type)] ;; Check for prevention effects (if (and (not unpreventable) @@ -294,14 +295,14 @@ (do (system-msg state :runner "has the option to prevent trash effects") (show-wait-prompt state :corp "Runner to prevent trash effects") (show-prompt state :runner nil - (str "Prevent the trashing of " (:title card) "?") ["Done"] + (s/strcat "Prevent the trashing of " (:title card) "?") ["Done"] (fn [_] (clear-wait-prompt state :corp) (if-let [_ (get-in @state [:trash :trash-prevent ktype])] - (do (system-msg state :runner (str "prevents the trashing of " (:title card))) + (do (system-msg state :runner (s/strcat "prevents the trashing of " (:title card))) (swap! state update-in [:trash :trash-prevent] dissoc ktype) (effect-completed state side eid)) - (do (system-msg state :runner (str "will not prevent the trashing of " (:title card))) + (do (system-msg state :runner (s/strcat "will not prevent the trashing of " (:title card))) (complete-with-result state side eid card)))) {:prompt-type :prevent})) ;; No prevention effects: add the card to the trash-list @@ -643,7 +644,7 @@ :unpreventable true}) (let [card (get-card state card)] (when msg - (system-msg state side (str "forfeits " (get-title card)))) + (system-msg state side (s/strcat "forfeits " (get-title card)))) (move state (to-keyword (:side card)) card :rfg) (update-all-agenda-points state side) (check-win-by-agenda state side) diff --git a/src/clj/game/core/optional.clj b/src/clj/game/core/optional.clj index 4b9f3263f9..3deb7fac68 100644 --- a/src/clj/game/core/optional.clj +++ b/src/clj/game/core/optional.clj @@ -8,7 +8,8 @@ [game.core.toasts :refer [toast]] [game.core.update :refer [update!]] [game.macros :refer [effect req wait-for]] - [clojure.string :as string])) + [clojure.string :as string] + [stringer.core :as s])) (defn optional-ability "Shows a 'Yes/No' prompt and resolves the given ability's :yes-ability if Yes is chosen, and :no-ability otherwise. @@ -39,7 +40,7 @@ "Yes" (prompt-fn {:value "Yes"}) "No" (prompt-fn {:value "No"}) (do (when autoresolve-fn - (toast state side (str "This prompt can be skipped by clicking " + (toast state side (s/strcat "This prompt can be skipped by clicking " (:title card) " and toggling autoresolve"))) (show-prompt state side eid card message choices prompt-fn (assoc ability :targets targets)))))))) @@ -69,11 +70,11 @@ "Makes a card ability which lets the user toggle auto-resolve on an ability. Setting is stored under [:special toggle-kw]." [toggle-kw ability-name] {:autoresolve true - :label (str "Toggle auto-resolve on " ability-name) - :prompt (str "Set auto-resolve on " ability-name " to:") + :label (s/strcat "Toggle auto-resolve on " ability-name) + :prompt (s/strcat "Set auto-resolve on " ability-name " to:") :choices ["Always" "Never" "Ask"] :effect (effect (update! (assoc-in card [:special toggle-kw] (keyword (string/lower-case target)))) - (toast (str "From now on, " ability-name " will " + (toast (s/strcat "From now on, " ability-name " will " ({:always "always" :never "never" :ask "ask whether it should"} (get-in (get-card state card) [:special toggle-kw])) " resolve.") "info"))}) diff --git a/src/clj/game/core/payment.clj b/src/clj/game/core/payment.clj index 535061c2ef..e5e83ce4e5 100644 --- a/src/clj/game/core/payment.clj +++ b/src/clj/game/core/payment.clj @@ -6,7 +6,8 @@ [game.core.eid :refer [make-eid]] [game.core.effects :refer [any-effects]] [game.core.toasts :refer [toast]] - [jinteki.utils :refer [capitalize]])) + [jinteki.utils :refer [capitalize]] + [stringer.core :as s])) (defn ->c ([type] (->c type 1)) @@ -100,7 +101,7 @@ (defn- any-effect-stops-pay? "Checks installed cards to see if payment type is being prevented by an active card" [state side cost] - (let [kw-cost (keyword (str "cannot-pay-" (name (:cost/type cost))))] + (let [kw-cost (keyword (s/strcat "cannot-pay-" (name (:cost/type cost))))] (any-effects state side kw-cost true? {:amount (:cost/amount cost)}))) (defn can-pay? @@ -116,7 +117,7 @@ (payable? % state side eid card)) costs) costs - (do (when title (toast state side (str "Unable to pay for " title "."))) + (do (when title (toast state side (s/strcat "Unable to pay for " title "."))) nil))))) (defn cost-targets @@ -167,8 +168,8 @@ (let [cost-type (:cost/type cost) cost-string (label cost)] (cond - (#{:click :lose-click} cost-type) (str "spend " cost-string) - (= :credit cost-type) (str "pay " cost-string) + (#{:click :lose-click} cost-type) (s/strcat "spend " cost-string) + (= :credit cost-type) (s/strcat "pay " cost-string) :else cost-string))) (try (cost->string (first cost)) (catch Throwable t @@ -192,5 +193,5 @@ ([cost-str verb] (build-spend-msg cost-str verb nil)) ([cost-str verb verb2] (if (string/blank? cost-str) - (str (or verb2 (str verb "s")) " ") - (str cost-str " to " verb " ")))) + (s/strcat (or verb2 (s/strcat verb "s")) " ") + (s/strcat cost-str " to " verb " ")))) diff --git a/src/clj/game/core/pick_counters.clj b/src/clj/game/core/pick_counters.clj index 061da9506c..ff78a12060 100644 --- a/src/clj/game/core/pick_counters.clj +++ b/src/clj/game/core/pick_counters.clj @@ -8,7 +8,8 @@ [game.core.props :refer [add-counter]] [game.core.update :refer [update!]] [game.macros :refer [continue-ability req wait-for]] - [game.utils :refer [enumerate-str in-coll? quantify same-card?]])) + [game.utils :refer [enumerate-str in-coll? quantify same-card?]] + [stringer.core :as s])) (defn- pick-counter-triggers [state side eid current-cards selected-cards counter-count message] @@ -31,8 +32,8 @@ ([specific-card target-count] (pick-virus-counters-to-spend specific-card target-count (hash-map) 0)) ([specific-card target-count selected-cards counter-count] {:async true - :prompt (str "Choose a card with virus counters (" - counter-count (str " of " target-count) + :prompt (s/strcat "Choose a card with virus counters (" + counter-count (s/strcat " of " target-count) " virus counters)") :choices {:card #(and (if specific-card (or (same-card? % specific-card) @@ -54,7 +55,7 @@ card nil) (let [message (enumerate-str (map #(let [{:keys [card number]} % title (:title card)] - (str (quantify number "virus counter") " from " title)) + (s/strcat (quantify number "virus counter") " from " title)) (vals selected-cards)))] (pick-counter-triggers state side eid selected-cards selected-cards counter-count message))))) :cancel-effect (if target-count @@ -63,7 +64,7 @@ (complete-with-result state side eid :cancel)) (req (let [message (enumerate-str (map #(let [{:keys [card number]} % title (:title card)] - (str (quantify number "virus counter") " from " title)) + (s/strcat (quantify number "virus counter") " from " title)) (vals selected-cards)))] (complete-with-result state side eid {:number counter-count :msg message}))))})) @@ -97,13 +98,13 @@ (<= stealth-target stealth-count)) (let [remainder (max 0 (- target-count counter-count)) remainder-str (when (pos? remainder) - (str remainder " [Credits]")) + (s/strcat remainder " [Credits]")) card-strs (when (pos? (count selected-cards)) - (str (enumerate-str (map #(let [{:keys [card number]} % + (s/strcat (enumerate-str (map #(let [{:keys [card number]} % title (:title card)] - (str number " [Credits] from " title)) + (s/strcat number " [Credits] from " title)) (vals selected-cards))))) - message (str card-strs + message (s/strcat card-strs (when (and card-strs remainder-str) " and ") remainder-str @@ -126,12 +127,12 @@ {:async true :effect pay-rest} {:async true - :prompt (str "Choose a credit providing card (" + :prompt (s/strcat "Choose a credit providing card (" counter-count (when (and target-count (pos? target-count)) - (str " of " target-count)) + (s/strcat " of " target-count)) " [Credits]" (if (pos? stealth-target) - (str ", " (min stealth-count stealth-target) " of " stealth-target " stealth") + (s/strcat ", " (min stealth-count stealth-target) " of " stealth-target " stealth") "") ")") :choices {:card #(in-coll? (map :cid provider-cards) (:cid %))} diff --git a/src/clj/game/core/play_instants.clj b/src/clj/game/core/play_instants.clj index 11f4b22133..d9f9cd6f4f 100644 --- a/src/clj/game/core/play_instants.clj +++ b/src/clj/game/core/play_instants.clj @@ -14,7 +14,8 @@ [game.core.say :refer [play-sfx system-msg implementation-msg]] [game.core.update :refer [update!]] [game.macros :refer [wait-for]] - [game.utils :refer [same-card? to-keyword]])) + [game.utils :refer [same-card? to-keyword]] + [stringer.core :as s])) (defn async-rfg ([state side eid card] (async-rfg state side eid card nil)) @@ -35,7 +36,7 @@ (let [play-msg (if ignore-cost "play " (build-spend-msg payment-str "play"))] - (system-msg state side (str play-msg title (when ignore-cost " at no cost"))) + (system-msg state side (s/strcat play-msg title (when ignore-cost " at no cost"))) (implementation-msg state card) (if-let [sfx (:play-sound (card-def card))] (play-sfx state side sfx) @@ -67,7 +68,7 @@ (unregister-static-abilities state side card) (when (= zone :rfg) (system-msg state side - (str "removes " (:title c) " from the game instead of trashing it"))) + (s/strcat "removes " (:title c) " from the game instead of trashing it"))) (when (has-subtype? card "Terminal") (lose state side :click (-> @state side :click)) (swap! state assoc-in [:corp :register :terminal] true)) diff --git a/src/clj/game/core/process_actions.clj b/src/clj/game/core/process_actions.clj index 0d21116952..c699372337 100644 --- a/src/clj/game/core/process_actions.clj +++ b/src/clj/game/core/process_actions.clj @@ -21,7 +21,8 @@ [game.core.shuffling :refer [shuffle-deck]] [game.core.toasts :refer [ack-toast]] [game.core.turns :refer [end-phase-12 end-turn start-turn]] - [game.core.winning :refer [concede]])) + [game.core.winning :refer [concede]] + [stringer.core :as s])) (defn checkpoint+clean-up [state] @@ -39,7 +40,7 @@ (if-let [command (parse-command state text)] (when (and (not= side nil) (not= side :spectator)) (command state side) - (system-say state side (str "[!]" (:username author) " uses a command: " text))) + (system-say state side (s/strcat "[!]" (:username author) " uses a command: " text))) (say state side args)))) (def commands diff --git a/src/clj/game/core/prompts.clj b/src/clj/game/core/prompts.clj index 4f55a47072..d9acb54a8a 100644 --- a/src/clj/game/core/prompts.clj +++ b/src/clj/game/core/prompts.clj @@ -6,7 +6,8 @@ [game.core.toasts :refer [toast]] [game.macros :refer [when-let*]] [game.utils :refer [pluralize side-str]] - [medley.core :refer [find-first]])) + [medley.core :refer [find-first]] + [stringer.core :as s])) (defn choice-parser [choices] @@ -48,9 +49,9 @@ {:eid (select-keys eid [:eid]) :card card :prompt-type :waiting - :msg (str "Waiting for " + :msg (s/strcat "Waiting for " (if (true? waiting-prompt) - (str (side-str side) " to make a decision") + (s/strcat (side-str side) " to make a decision") waiting-prompt))})) (add-to-prompt-queue state side newitem))))) @@ -67,7 +68,7 @@ #(if (not= (:value %) dice-msg) (f %) (show-prompt state side card - (str message " (Dice result: " (inc (rand-int 6)) ")") + (s/strcat message " (Dice result: " (inc (rand-int 6)) ")") other-choices f args)) args)))) @@ -147,16 +148,16 @@ (str "Choose" (when min-choices - (str " at least " min-choices)) + (s/strcat " at least " min-choices)) (when (and min-choices max-choices) " and") (when max-choices - (str (if all "" " up to") + (s/strcat (if all "" " up to") " " max-choices)) (if max-choices - (str " " (pluralize "target" max-choices)) + (s/strcat " " (pluralize "target" max-choices)) (if min-choices - (str " " (pluralize "target" min-choices)) + (s/strcat " " (pluralize "target" min-choices)) " a target")) " for " (:title card))) (if all ["Hide"] ["Done"]) @@ -164,7 +165,7 @@ (fn [_] ; "Hide" was selected. Show toast and reapply select prompt. This allows players to access ; prompts that lie "beneath" the current select prompt. - (toast state side (str "You must choose " max-choices " " (pluralize "card" max-choices))) + (toast state side (s/strcat "You must choose " max-choices " " (pluralize "card" max-choices))) (show-select state side card ability update! resolve-ability args)) (fn [_] (let [selected (get-in @state [side :selected 0] []) @@ -172,7 +173,7 @@ ; check for :min. If not enough cards are selected, show toast and stay in select prompt (if (and min-choices (< (count cards) min-choices)) (do - (toast state side (str "You must choose at least " min-choices " " (pluralize "card" min-choices))) + (toast state side (s/strcat "You must choose at least " min-choices " " (pluralize "card" min-choices))) (show-select state side card ability update! resolve-ability args)) (resolve-select state side card (select-keys (wrap-function args :cancel-effect) [:cancel-effect]) @@ -187,7 +188,7 @@ The prompt cannot be closed except by a later call to clear-wait-prompt." ([state side message] (show-wait-prompt state side message nil)) ([state side message {:keys [card]}] - (show-prompt state side card (str "Waiting for " message) nil nil + (show-prompt state side card (s/strcat "Waiting for " message) nil nil {:prompt-type :waiting}))) (defn clear-wait-prompt @@ -200,8 +201,8 @@ "Adds a dummy prompt to both side's prompt queues. The prompt cannot be closed except by a later call to clear-run-prompts." [state msg card] - (show-prompt state :runner card (str "You are " msg) nil nil {:prompt-type :run}) - (show-prompt state :corp card (str "The Runner is " msg) nil nil {:prompt-type :run})) + (show-prompt state :runner card (s/strcat "You are " msg) nil nil {:prompt-type :run}) + (show-prompt state :corp card (s/strcat "The Runner is " msg) nil nil {:prompt-type :run})) (defn clear-run-prompts [state] diff --git a/src/clj/game/core/psi.clj b/src/clj/game/core/psi.clj index e8102aaee7..d63564ad07 100644 --- a/src/clj/game/core/psi.clj +++ b/src/clj/game/core/psi.clj @@ -10,11 +10,12 @@ [game.macros :refer [continue-ability effect wait-for]] [jinteki.utils :refer [str->int]] [clojure.string :as string] - [game.core.payment :refer [->c]])) + [game.core.payment :refer [->c]] + [stringer.core :as s])) (defn- bet-to-keyword [bet] - (keyword (str "bet-" bet))) + (keyword (s/strcat "bet-" bet))) (defn- resolve-psi "Resolves a psi game by charging credits to both sides and invoking the appropriate @@ -41,7 +42,7 @@ (swap! state update-in [:stats (if (= card-side :corp) :runner :corp) :psi-game :wins] (fnil + 0) 1) (effect-completed state side eid))))))) (show-wait-prompt - state side (str (string/capitalize (name opponent)) " to choose psi game credits"))))) + state side (s/strcat (string/capitalize (name opponent)) " to choose psi game credits"))))) (defn psi-game "Starts a psi game by showing the psi prompt to both players. psi is a map containing @@ -56,8 +57,8 @@ valid-amounts (remove #(or (any-flag-fn? state :corp :prevent-secretly-spend %) (any-flag-fn? state :runner :prevent-secretly-spend %)) all-amounts)] - (show-prompt-with-dice state s card (str "Choose an amount to spend for " (:title card)) - (map #(str % " [Credits]") valid-amounts) + (show-prompt-with-dice state s card (s/strcat "Choose an amount to spend for " (:title card)) + (map #(s/strcat % " [Credits]") valid-amounts) #(resolve-psi state s eid card psi (str->int (first (string/split (:value %) #" "))) targets) {:prompt-type :psi})))))) diff --git a/src/clj/game/core/rezzing.clj b/src/clj/game/core/rezzing.clj index 05df142fa8..47086ed303 100644 --- a/src/clj/game/core/rezzing.clj +++ b/src/clj/game/core/rezzing.clj @@ -17,7 +17,8 @@ [game.core.to-string :refer [card-str]] [game.core.update :refer [update!]] [game.macros :refer [continue-ability effect wait-for]] - [game.utils :refer [enumerate-str to-keyword]])) + [game.utils :refer [enumerate-str to-keyword]] + [stringer.core :as s])) (defn get-rez-cost [state side card {:keys [ignore-cost alternative-cost cost-bonus]}] @@ -40,7 +41,7 @@ (effect-completed state side eid) (wait-for (trash-cards state side hosted-cards {:unpreventable true :game-trash true}) (when (pos? (count hosted-cards)) - (system-msg state side (str "trashes " (enumerate-str (map #(card-str state %) hosted-cards)) + (system-msg state side (s/strcat "trashes " (enumerate-str (map #(card-str state %) hosted-cards)) " because " (:title card) " cannot host cards"))) (effect-completed state side eid))))) @@ -66,7 +67,7 @@ (update-in [:host :zone] #(map to-keyword %))))) (when-not no-msg (system-msg state side - (str (build-spend-msg msg "rez" "rezzes") + (s/strcat (build-spend-msg msg "rez" "rezzes") (:title card) (cond alternative-cost " by paying its alternative cost" @@ -136,8 +137,8 @@ ([state side card {:keys [source-card no-msg] :as args}] (let [card (get-card state card)] (when-not no-msg - (system-msg state side (str (if source-card - (str "uses " (:title source-card) " to derez ") + (system-msg state side (s/strcat (if source-card + (s/strcat "uses " (:title source-card) " to derez ") "derezzes ") (:title card)))) (unregister-events state side card) diff --git a/src/clj/game/core/runs.clj b/src/clj/game/core/runs.clj index 29db4fccb4..23ec8bbaba 100644 --- a/src/clj/game/core/runs.clj +++ b/src/clj/game/core/runs.clj @@ -22,7 +22,8 @@ [game.utils :refer [dissoc-in same-card?]] [jinteki.utils :refer [count-bad-pub other-side]] [clojure.stacktrace :refer [print-stack-trace]] - [clojure.string :as string])) + [clojure.string :as string] + [stringer.core :as s])) (declare handle-end-run jack-out forced-encounter-cleanup run-cleanup gain-run-credits pass-ice successful-run) @@ -134,7 +135,7 @@ ices (get-in @state (concat [:corp :servers] s [:ices])) n (count ices)] (when (not-empty payment-str) - (system-msg state :runner (str (build-spend-msg payment-str "make a run on" "makes a run on") + (system-msg state :runner (s/strcat (build-spend-msg payment-str "make a run on" "makes a run on") (zone->name (unknown->kw server)) (when ignore-costs ", ignoring all costs")))) ;; s is a keyword for the server, like :hq or :remote1 @@ -153,7 +154,7 @@ :source-card (select-keys card [:code :cid :zone :title :side :type :art :implementation])}) (when card (update! state side (assoc-in card [:special :run-id] run-id)))) - (show-run-prompts state (str "running on " (zone->name (unknown->kw server))) card) + (show-run-prompts state (s/strcat "running on " (zone->name (unknown->kw server))) card) (wait-for (gain-run-credits state side (make-eid state eid) @@ -209,7 +210,7 @@ (update-current-encounter state :ending true) (when (:bypass encounter) (queue-event state :bypassed-ice ice) - (system-msg state :runner (str "bypasses " (:title ice)))) + (system-msg state :runner (s/strcat "bypasses " (:title ice)))) (wait-for (end-of-phase-checkpoint state nil (make-eid state eid) :end-of-encounter {:ice ice}) @@ -258,7 +259,7 @@ (let [eid (make-phase-eid state eid) ice (get-current-ice state) on-approach (:on-approach (card-def ice))] - (system-msg state :runner (str "approaches " (card-str state ice))) + (system-msg state :runner (s/strcat "approaches " (card-str state ice))) (when on-approach (register-pending-event state :approach-ice ice on-approach)) (queue-event state :approach-ice {:ice ice}) @@ -324,7 +325,7 @@ [abi ice] {:async true :interactive (req true) - :ability-name (or (:ability-name abi) (str (:title ice) " Ability")) + :ability-name (or (:ability-name abi) (s/strcat (:title ice) " Ability")) :effect (req (swap! state assoc-in [:run :prevent-encounter-ability] nil) (wait-for (trigger-event-simult state :runner :prevent-encounter-ability nil {:ability-name (:ability-name abi)}) (if (get-in @state [:run :prevent-encounter-ability]) @@ -341,7 +342,7 @@ (let [on-encounter (:on-encounter (card-def ice)) applied-encounters (get-effects state nil :gain-encounter-ability ice) all-encounters (map #(preventable-encounter-abi % ice) (remove nil? (conj applied-encounters on-encounter)))] - (system-msg state :runner (str "encounters " (card-str state ice {:visible (active-ice? state ice)}))) + (system-msg state :runner (s/strcat "encounters " (card-str state ice {:visible (active-ice? state ice)}))) (doseq [on-encounter all-encounters] (register-pending-event state :encounter-ice ice on-encounter)) (queue-event state :encounter-ice {:ice ice}) @@ -364,7 +365,7 @@ ([state side eid ice new-state] ;; clears the broken subs out of the prompt, otherwise they can get stuck with some cards (reset-all-subs! state (get-card state ice)) - (show-run-prompts state (str "encountering " (:title ice)) ice) + (show-run-prompts state (s/strcat "encountering " (:title ice)) ice) ;; do we need to mess with the run state (let [old-state (get-in @state [:run :phase])] (when new-state @@ -408,7 +409,7 @@ (set-phase state :movement) (swap! state assoc-in [:run :no-action] false) (when pass-ice? - (system-msg state :runner (str "passes " (card-str state ice))) + (system-msg state :runner (s/strcat "passes " (card-str state ice))) (queue-event state :pass-ice {:ice (get-card state ice)})) (swap! state assoc-in [:run :position] new-position) (when passed-all-ice @@ -441,7 +442,7 @@ (defn approach-server [state side eid] (set-current-ice state nil) - (system-msg state :runner (str "approaches " (zone->name (:server (:run @state))))) + (system-msg state :runner (s/strcat "approaches " (zone->name (:server (:run @state))))) (queue-event state :approach-server) (wait-for (checkpoint state side (make-eid state) @@ -500,7 +501,7 @@ (.println *err* (with-out-str (print-stack-trace (Exception. - (str "Continue clicked at the wrong time, run phase: " (:phase (:run @state)))) + (s/strcat "Continue clicked at the wrong time, run phase: " (:phase (:run @state)))) 2500)))) (defn redirect-run @@ -584,7 +585,7 @@ (let [chosen (first handlers) ability (:ability chosen) card (:card chosen)] - (system-msg state :runner (str "uses the replacement effect from " (:title card))) + (system-msg state :runner (s/strcat "uses the replacement effect from " (:title card))) (wait-for (resolve-ability state :runner ability card [(select-keys (:run @state) [:server :run-id])]) (handle-end-run state :runner eid))) ;; there are multiple handlers @@ -592,15 +593,15 @@ (resolve-ability state :runner {:prompt "Choose a breach replacement ability" - :choices (if mandatory titles (conj titles (str "Breach " (zone->name (:server (:run @state)))))) + :choices (if mandatory titles (conj titles (s/strcat "Breach " (zone->name (:server (:run @state)))))) :effect (req (let [chosen (some #(when (= target (get-in % [:card :title])) %) handlers) ability (:ability chosen) card (:card chosen)] (if chosen - (do (system-msg state :runner (str "uses the replacement effect from " (:title card))) + (do (system-msg state :runner (s/strcat "uses the replacement effect from " (:title card))) (wait-for (resolve-ability state :runner ability card [(select-keys (:run @state) [:server :run-id])]) (handle-end-run state :runner eid))) - (do (system-msg state :runner (str "chooses to breach " (zone->name (:server (:run @state))) " instead of use a replacement effect")) + (do (system-msg state :runner (s/strcat "chooses to breach " (zone->name (:server (:run @state))) " instead of use a replacement effect")) (wait-for (breach-server state :runner (make-eid state eid) (get-in @state [:run :server])) (handle-end-run state :runner eid))))))} nil nil) @@ -628,9 +629,9 @@ (:prevent-access the-run) (resolve-ability state :runner eid - {:prompt (str "You are prevented from breaching " (zone->name server) " this run.") + {:prompt (s/strcat "You are prevented from breaching " (zone->name server) " this run.") :choices ["OK"] - :effect (effect (system-msg :runner (str "is prevented from breaching " (zone->name server) " this run.")) + :effect (effect (system-msg :runner (s/strcat "is prevented from breaching " (zone->name server) " this run.")) (handle-end-run eid))} nil nil) @@ -710,7 +711,7 @@ (do (system-msg state :runner "has the option to prevent the run from ending") (show-wait-prompt state :corp "Runner to prevent the run from ending") (show-prompt state :runner nil - (str "Prevent the run from ending?") ["Done"] + (s/strcat "Prevent the run from ending?") ["Done"] (fn [_] (clear-wait-prompt state :corp) (if-let [_ (get-in @state [:end-run :end-run-prevent])] @@ -742,11 +743,11 @@ (if-let [payment-str (:msg async-result)] (let [prevent (get-prevent-list state :corp :jack-out)] (if (cards-can-prevent? state :corp prevent :jack-out) - (do (system-msg state :runner (str (build-spend-msg payment-str "attempt to" "attempts to") "jack out")) + (do (system-msg state :runner (s/strcat (build-spend-msg payment-str "attempt to" "attempts to") "jack out")) (system-msg state :corp "has the option to prevent the Runner from jacking out") (show-wait-prompt state :runner "Corp to prevent the jack out") (show-prompt state :corp nil - (str "Prevent the Runner from jacking out?") ["Done"] + (s/strcat "Prevent the Runner from jacking out?") ["Done"] (fn [_] (clear-wait-prompt state :runner) (if-let [_ (get-in @state [:jack-out :jack-out-prevent])] @@ -755,10 +756,10 @@ (resolve-jack-out state side eid)))) {:prompt-type :prevent})) (do (when-not (string/blank? payment-str) - (system-msg state :runner (str payment-str " to jack out"))) + (system-msg state :runner (s/strcat payment-str " to jack out"))) (resolve-jack-out state side eid)))) (complete-with-result state side eid false))) - (do (system-msg state :runner (str "attempts to jack out but can't pay (" (build-cost-string cost) ")")) + (do (system-msg state :runner (s/strcat "attempts to jack out but can't pay (" (build-cost-string cost) ")")) (complete-with-result state side eid false)))))) (defn- run-end-fx diff --git a/src/clj/game/core/sabotage.clj b/src/clj/game/core/sabotage.clj index 4d1116416c..7555ab109a 100644 --- a/src/clj/game/core/sabotage.clj +++ b/src/clj/game/core/sabotage.clj @@ -1,22 +1,22 @@ (ns game.core.sabotage (:require - [clojure.string :as string] [game.core.card :refer [corp? in-hand?]] [game.core.eid :refer [effect-completed]] [game.core.engine :refer [resolve-ability]] [game.core.moving :refer [trash-cards]] [game.core.say :refer [system-msg]] [game.macros :refer [req msg continue-ability]] - [game.utils :refer [pluralize]])) + [game.utils :refer [pluralize]] + [stringer.core :as s])) (defn choosing-prompt-req [n] (req (let [cards-rd (count (get-in @state [:corp :deck])) forced-hq (- n cards-rd)] - (str "Choose" + (s/strcat "Choose" (when (pos? forced-hq) - (str " at least " forced-hq " " (pluralize "card" forced-hq) " and")) + (s/strcat " at least " forced-hq " " (pluralize "card" forced-hq) " and")) " up to " n " " (pluralize "card" n) " to trash from HQ. Remainder will be trashed from top of R&D.")))) @@ -32,11 +32,11 @@ (str "trashes" (when (pos? selected-hq) - (str " " selected-hq " " (pluralize "card" selected-hq) " from HQ")) + (s/strcat " " selected-hq " " (pluralize "card" selected-hq) " from HQ")) (when (and (pos? selected-hq) (pos? selected-rd)) " and") (when (pos? selected-rd) - (str " " selected-rd " " (pluralize "card" selected-rd) " from the top of R&D")))) + (s/strcat " " selected-rd " " (pluralize "card" selected-rd) " from the top of R&D")))) (trash-cards state side eid to-trash {:unpreventable true})))) (defn sabotage-ability diff --git a/src/clj/game/core/say.clj b/src/clj/game/core/say.clj index eadf92a191..72264cb9b7 100644 --- a/src/clj/game/core/say.clj +++ b/src/clj/game/core/say.clj @@ -1,5 +1,6 @@ (ns game.core.say (:require + [stringer.core :as s] [cljc.java-time.instant :as inst] [clojure.string :as str] [game.core.toasts :refer [toast]])) @@ -54,7 +55,7 @@ "Prints a system message to log (`say` from user __system__)" ([state side text] (system-say state side text nil)) ([state side text {:keys [hr]}] - (say state side (make-system-message (str text (when hr "[hr]")))))) + (say state side (make-system-message (s/strcat text (when hr "[hr]")))))) (defn unsafe-say "Prints a reagent hiccup directly to the log. Do not use for any user-generated content!" @@ -67,23 +68,23 @@ ([state side text] (system-msg state side text nil)) ([state side text args] (let [username (get-in @state [side :user :username])] - (system-say state side (str username " " text ".") args)))) + (system-say state side (s/strcat username " " text ".") args)))) (defn enforce-msg "Prints a message related to a rules enforcement on a given card. Example: 'Architect cannot be trashed while installed.'" [state card text] - (system-say state nil (str (:title card) " " text "."))) + (system-say state nil (s/strcat (:title card) " " text "."))) (defn implementation-msg [state card] (when (not= :full (:implementation card)) - (system-say state nil (str "[!] " (:title card) " - " (:implementation card))))) + (system-say state nil (s/strcat "[!] " (:title card) " - " (:implementation card))))) (defn indicate-action [state side _] (system-say state side - (str "[!] Please pause, " (if (= side :corp) "Corp" "Runner") " is acting.")) + (s/strcat "[!] Please pause, " (if (= side :corp) "Corp" "Runner") " is acting.")) (toast state side "You have indicated action to your opponent" "info" diff --git a/src/clj/game/core/servers.clj b/src/clj/game/core/servers.clj index bc92280ca5..2597acf680 100644 --- a/src/clj/game/core/servers.clj +++ b/src/clj/game/core/servers.clj @@ -3,7 +3,8 @@ (:require [game.core.card :refer [get-zone]] [game.utils :refer [safe-split string->num]] - [clojure.string :as string])) + [clojure.string :as string] + [stringer.core :as s])) (defn target-server "Returns the server keyword corresponding to the target of a run." @@ -12,13 +13,13 @@ (defn remote-num->name [num] - (str "Server " num)) + (s/strcat "Server " num)) (defn remote->name "Converts a remote zone to a string" [zone] (let [kw (if (keyword? zone) zone (last zone)) - s (str kw)] + s (s/strcat kw)] (when (string/starts-with? s ":remote") (let [num (last (string/split s #":remote"))] (remote-num->name num))))) @@ -63,7 +64,7 @@ :rd -2 :hq -1 (string->num - (last (safe-split (str zone) #":remote"))))) + (last (safe-split (s/strcat zone) #":remote"))))) (defn zones->sorted-names [zones] @@ -156,7 +157,7 @@ "R&D" :rd "Archives" :archives ;; assume "Server N" - (->> (string/split name-or-kw-or-zone #" ") last (str "remote") keyword)) + (->> (string/split name-or-kw-or-zone #" ") last (s/strcat "remote") keyword)) :else (second name-or-kw-or-zone))) diff --git a/src/clj/game/core/shuffling.clj b/src/clj/game/core/shuffling.clj index 69d7358e10..5520e53f77 100644 --- a/src/clj/game/core/shuffling.clj +++ b/src/clj/game/core/shuffling.clj @@ -6,7 +6,8 @@ [game.core.moving :refer [move move-zone]] [game.core.say :refer [system-msg]] [game.macros :refer [continue-ability msg req]] - [game.utils :refer [enumerate-str quantify]])) + [game.utils :refer [enumerate-str quantify]] + [stringer.core :as s])) (defn shuffle! "Shuffles the vector in @state [side kw]." @@ -40,9 +41,9 @@ :msg (msg "shuffle " (let [seen (filter :seen targets) m (count (filter #(not (:seen %)) targets))] - (str (enumerate-str (map :title seen)) + (s/strcat (enumerate-str (map :title seen)) (when (pos? m) - (str (when-not (empty? seen) " and ") + (s/strcat (when-not (empty? seen) " and ") (quantify m "unseen card"))))) " into R&D") :waiting-prompt true @@ -50,7 +51,7 @@ (move state side c :deck)) (shuffle! state side :deck)) :cancel-effect (req - (system-msg state side (str " uses " (:title card) " to shuffle R&D")) + (system-msg state side (s/strcat " uses " (:title card) " to shuffle R&D")) (shuffle! state side :deck) (effect-completed state side eid))} card nil))) diff --git a/src/clj/game/core/tags.clj b/src/clj/game/core/tags.clj index 51c2278fbf..7be2ab3fb1 100644 --- a/src/clj/game/core/tags.clj +++ b/src/clj/game/core/tags.clj @@ -9,7 +9,8 @@ [game.core.say :refer [system-msg]] [game.core.toasts :refer [toast]] [game.macros :refer [wait-for]] - [game.utils :refer [pluralize quantify]])) + [game.utils :refer [pluralize quantify]] + [stringer.core :as s])) (defn sum-tag-effects [state] @@ -56,7 +57,7 @@ [state side eid n] (if (pos? n) (do (gain state :runner :tag {:base n}) - (toast state :runner (str "Took " (quantify n "tag") "!") "info") + (toast state :runner (s/strcat "Took " (quantify n "tag") "!") "info") (update-tag-status state) (trigger-event-simult state side eid :runner-gain-tag nil {:amount n})) (effect-completed state side eid))) @@ -77,11 +78,11 @@ (swap! state assoc-in [:prevent :current] :tag) (show-prompt state :runner nil - (str "Avoid " (when (< 1 n) "any of the ") (quantify n "tag") "?") ["Done"] + (s/strcat "Avoid " (when (< 1 n) "any of the ") (quantify n "tag") "?") ["Done"] (fn [_] (let [prevent (get-in @state [:tag :tag-prevent]) prevent-msg (if prevent - (str "avoids " + (s/strcat "avoids " (if (= prevent Integer/MAX_VALUE) "all" prevent) (pluralize prevent "tag")) "will not avoid tags")] diff --git a/src/clj/game/core/to_string.clj b/src/clj/game/core/to_string.clj index 0ff156e995..ab9477e131 100644 --- a/src/clj/game/core/to_string.clj +++ b/src/clj/game/core/to_string.clj @@ -1,31 +1,32 @@ (ns game.core.to-string (:require [game.core.card :refer [get-card rezzed? ice? installed? corp? card-index get-title]] - [game.core.servers :refer [is-root? zone->name]])) + [game.core.servers :refer [is-root? zone->name]] + [stringer.core :as s])) (defn card-str "Gets a string description of an installed card, reflecting whether it is rezzed, in/protecting a server, facedown, or hosted." ([state card] (card-str state card nil)) ([state {:keys [zone host facedown] :as card} {:keys [visible]}] - (str (if (corp? card) + (s/strcat (if (corp? card) (let [installed-ice (and (ice? card) (installed? card))] ; Corp card messages - (str (if (or (rezzed? card) + (s/strcat (if (or (rezzed? card) visible) (get-title card) (if installed-ice "ice" "a card")) ; Hosted cards do not need "in server 1" messages, host has them (when-not host - (str (cond + (s/strcat (cond installed-ice " protecting " (is-root? zone) " in the root of " :else " in ") - ;TODO add naming of scoring area of corp/runner + ;;TODO add naming of scoring area of corp/runner (zone->name (or (second zone) zone)) ;; handles [:hand] as well as [:servers :hq] (when installed-ice - (str " at position " (card-index state card))))))) + (s/strcat " at position " (card-index state card))))))) ; Runner card messages (if (or facedown visible) "a facedown card" (get-title card))) - (when host (str " hosted on " (card-str state (get-card state host))))))) + (when host (s/strcat " hosted on " (card-str state (get-card state host))))))) diff --git a/src/clj/game/core/toasts.clj b/src/clj/game/core/toasts.clj index ca6a9bb437..0606d77aae 100644 --- a/src/clj/game/core/toasts.clj +++ b/src/clj/game/core/toasts.clj @@ -26,8 +26,6 @@ [state side] (when state (toast state side - (str "Your last action caused a game error on the server. You can keep playing, but there " - "may be errors in the game's current state. Please click the button below to submit a report " - "to our GitHub issues page.

Use /error to see this message again.") + "Your last action caused a game error on the server. You can keep playing, but there may be errors in the game's current state. Please click the button below to submit a report to our GitHub issues page.

Use /error to see this message again." "exception" {:time-out 0 :close-button true}))) diff --git a/src/clj/game/core/trace.clj b/src/clj/game/core/trace.clj index 7512431fb4..d986eac4c7 100644 --- a/src/clj/game/core/trace.clj +++ b/src/clj/game/core/trace.clj @@ -8,7 +8,8 @@ [game.core.prompts :refer [clear-wait-prompt show-trace-prompt show-wait-prompt]] [game.core.say :refer [system-msg system-say]] [game.macros :refer [continue-ability effect wait-for]] - [game.core.payment :refer [->c]])) + [game.core.payment :refer [->c]] + [stringer.core :as s])) (defn- determine-initiator [state {:keys [player]}] @@ -34,7 +35,7 @@ trigger-trace (select-keys trace [:player :other :base :bonus :link :ability :strength])] (wait-for (pay state other (make-eid state eid) card [(->c :credit boost)]) (let [payment-str (:msg async-result)] - (system-msg state other (str payment-str + (system-msg state other (s/strcat payment-str " to increase " (if (corp-start? trace) "link" "trace") " strength to " (if (corp-start? trace) runner-strength @@ -45,7 +46,7 @@ (:successful trace) (:unsuccessful trace)) :eid (make-eid state))] - (system-say state player (str "The trace was " (when-not successful "un") "successful.")) + (system-say state player (s/strcat "The trace was " (when-not successful "un") "successful.")) (wait-for (trigger-event-simult state :corp (if successful :successful-trace :unsuccessful-trace) nil ;; No special functions (assoc trigger-trace @@ -88,15 +89,15 @@ trace (assoc trace :strength strength :beat-trace (beat-trace-amount player corp-credits runner-credits link base strength eid))] (wait-for (pay state player (make-eid state eid) card [(->c :credit boost)]) (let [payment-str (:msg async-result)] - (system-msg state player (str payment-str + (system-msg state player (s/strcat payment-str " to increase " (if (corp-start? trace) "trace" "link") " strength to " strength))) (clear-wait-prompt state other) (show-wait-prompt state player - (str (if (corp-start? trace) "Runner" "Corp") + (s/strcat (if (corp-start? trace) "Runner" "Corp") " to boost " other-type " strength")) (show-trace-prompt state other (make-eid state eid) card - (str "Boost " other-type " strength?") + (s/strcat "Boost " other-type " strength?") #(resolve-trace state side eid card trace %) trace)))) @@ -104,17 +105,17 @@ "Starts the trace process by showing the boost prompt to the first player (normally corp)." [state side eid card {:keys [player other base bonus label] :as trace}] (let [this-type (if (corp-start? trace) "trace" "link")] - (system-msg state player (str "uses " (:title card) + (system-msg state player (s/strcat "uses " (:title card) " to initiate a trace with strength " ((fnil + 0 0) base bonus) (when (pos? bonus) - (str " (" base " + " bonus ")")) + (s/strcat " (" base " + " bonus ")")) (when label - (str " (" label ")")))) + (s/strcat " (" label ")")))) (show-wait-prompt state other - (str (if (corp-start? trace) "Corp" "Runner") + (s/strcat (if (corp-start? trace) "Corp" "Runner") " to boost " this-type " strength")) (show-trace-prompt state player (make-eid state eid) card - (str "Boost " this-type " strength?") + (s/strcat "Boost " this-type " strength?") #(trace-reply state side eid card trace %) trace))) diff --git a/src/clj/game/core/turns.clj b/src/clj/game/core/turns.clj index c166d49510..9e3b65638f 100644 --- a/src/clj/game/core/turns.clj +++ b/src/clj/game/core/turns.clj @@ -18,7 +18,7 @@ [game.core.winning :refer [flatline]] [game.macros :refer [continue-ability req wait-for]] [game.utils :refer [dissoc-in enumerate-str quantify]] - [clojure.string :as string])) + [stringer.core :as s])) (defn- turn-message "Prints a message for the start or end of a turn, summarizing credits and cards in hand." @@ -27,7 +27,7 @@ hand (if (= side :runner) "[their] Grip" "HQ") cards (count (get-in @state [side :hand])) credits (get-in @state [side :credit]) - text (str pre " [their] turn " (:turn @state) " with " credits " [Credit] and " (quantify cards "card") " in " hand)] + text (s/strcat pre " [their] turn " (:turn @state) " with " credits " [Credit] and " (quantify cards "card") " in " hand)] (system-msg state side text {:hr (not start-of-turn)}))) (defn end-phase-12 @@ -89,7 +89,7 @@ (trigger-event state side phase nil) (if (not-empty start-cards) (toast state side - (str "You may use " (enumerate-str (map :title start-cards)) + (s/strcat "You may use " (enumerate-str (map :title start-cards)) (if (= side :corp) " between the start of your turn and your mandatory draw." " before taking your first click.")) @@ -105,17 +105,17 @@ (effect-completed state side eid)) (any-effects state side :skip-discard) (do - (system-msg state side (str "skips [their] discard step this turn")) + (system-msg state side (s/strcat "skips [their] discard step this turn")) (effect-completed state side eid)) (> cur-hand-size max-hand-size) (continue-ability state side - {:prompt (str "Discard down to " (quantify max-hand-size "card")) + {:prompt (s/strcat "Discard down to " (quantify max-hand-size "card")) :choices {:card in-hand? :max (- cur-hand-size (max (hand-size state side) 0)) :all true} :effect (req (system-msg state side - (str "discards " + (s/strcat "discards " (if (= :runner side) (enumerate-str (map :title targets)) (quantify (count targets) "card")) @@ -169,5 +169,5 @@ (when (pos? extra-turns) (start-turn state side nil) (swap! state update-in [side :extra-turns] dec) - (system-msg state side (string/join ["will have " (quantify extra-turns "extra turn") " remaining."])))) + (system-msg state side (s/strcat "will have " (quantify extra-turns "extra turn") " remaining.")))) (effect-completed state side eid))))) diff --git a/src/clj/game/macros.clj b/src/clj/game/macros.clj index cf5056b5da..f3cf1c62af 100644 --- a/src/clj/game/macros.clj +++ b/src/clj/game/macros.clj @@ -1,6 +1,7 @@ (ns game.macros (:require [clojure.tools.analyzer.jvm :as a.j] - [clojure.tools.analyzer.ast :as ast])) + [clojure.tools.analyzer.ast :as ast] + [stringer.core :as s])) (def forms (->> @@ -86,7 +87,7 @@ nls (emit-only needed-locals)] `(fn ~['state 'side 'eid 'card 'targets] (assert (or (nil? (:source ~'eid)) (:cid (:source ~'eid))) - (str ":source should be a card, received: " (:source ~'eid))) + (s/strcat ":source should be a card, received: " (:source ~'eid))) (let [~@nls] ~@expr)))) @@ -94,7 +95,7 @@ `(req ~@(effect-state-handler expr))) (defmacro msg [& expr] - `(req (str ~@expr))) + `(req (s/strcat ~@expr))) (defmacro wait-for [& body] diff --git a/src/clj/game/main.clj b/src/clj/game/main.clj index bf2b950414..d3cd089f99 100644 --- a/src/clj/game/main.clj +++ b/src/clj/game/main.clj @@ -1,5 +1,6 @@ (ns game.main - (:require [cheshire.generate :refer [add-encoder encode-str]] + (:require [stringer.core :as s] + [cheshire.generate :refer [add-encoder encode-str]] [game.core :as core] [game.core.toasts :refer [toast]])) @@ -49,4 +50,4 @@ (= _id (get-in @state [:runner :user :_id])) :runner :else nil)] (swap! state assoc-in [side :user] user) - (handle-notification state (str username " rejoined the game.")))) + (handle-notification state (s/strcat username " rejoined the game.")))) diff --git a/src/clj/web/game.clj b/src/clj/web/game.clj index 6096434cbc..52b3a67dd6 100644 --- a/src/clj/web/game.clj +++ b/src/clj/web/game.clj @@ -16,7 +16,8 @@ [web.app-state :as app-state] [web.lobby :as lobby] [web.stats :as stats] - [web.ws :as ws])) + [web.ws :as ws] + [stringer.core :as s])) (defn game-diff-json "Converts the appropriate diff to json" @@ -198,7 +199,7 @@ ; The game will not exist if this is the last player to leave. (when-let [lobby? (lobby/leave-lobby! db user uid nil lobby)] (handle-message-and-send-diffs! - lobby? nil nil (str (:username user) " has left the game."))) + lobby? nil nil (s/strcat (:username user) " has left the game."))) (lobby/send-lobby-list uid) (lobby/broadcast-lobby-list) (when ?reply-fn (?reply-fn true))))) @@ -264,7 +265,7 @@ :args args})))) (catch Exception e (ws/chsk-send! uid [:game/error]) - (println (str "Caught exception" + (println (s/strcat "Caught exception" "\nException Data: " (or (ex-data e) (.getMessage e)) "\nStacktrace: " (with-out-str (stacktrace/print-stack-trace e 100))))))) @@ -276,7 +277,7 @@ (when (and lobby (lobby/in-lobby? uid lobby)) (if-let [state (:state lobby)] (send-state-to-uid! uid :game/resync lobby (diffs/public-states state)) - (println (str "resync request unknown state" + (println (s/strcat "resync request unknown state" "\nGameID:" gameid "\nGameID by ClientID:" gameid "\nClientID:" uid @@ -292,7 +293,7 @@ (let [lobby (app-state/get-lobby gameid)] (when (and lobby (lobby/allowed-in-lobby user lobby)) (let [correct-password? (lobby/check-password lobby user password) - watch-str (str (:username user) " joined the game as a spectator" (when request-side (str " (" request-side " perspective)")) ".") + watch-str (s/strcat (:username user) " joined the game as a spectator" (when request-side (s/strcat " (" request-side " perspective)")) ".") watch-message (make-system-message watch-str) new-app-state (swap! app-state/app-state update :lobbies @@ -325,7 +326,7 @@ {:keys [state mute-spectators] :as lobby?} (get-in new-app-state [:lobbies gameid]) message (if mute-spectators "muted" "unmuted")] (when (and lobby? state (lobby/player? uid lobby?)) - (handle-message-and-send-diffs! lobby? nil nil (str (:username user) " " message " spectators.")) + (handle-message-and-send-diffs! lobby? nil nil (s/strcat (:username user) " " message " spectators.")) ;; needed to update the status bar (lobby/send-lobby-state lobby?)))) @@ -362,7 +363,7 @@ ; The game will not exist if this is the last player to leave. (when-let [lobby? (lobby/leave-lobby! db user uid nil lobby)] (handle-message-and-send-diffs! - lobby? nil nil (str (:username user) " has left the game."))))) + lobby? nil nil (s/strcat (:username user) " has left the game."))))) (lobby/send-lobby-list uid) (lobby/broadcast-lobby-list) (app-state/deregister-user! uid) diff --git a/src/clj/web/lobby.clj b/src/clj/web/lobby.clj index c49969f114..afdf538e96 100644 --- a/src/clj/web/lobby.clj +++ b/src/clj/web/lobby.clj @@ -15,7 +15,8 @@ [web.app-state :as app-state] [web.mongodb :as mongodb] [web.stats :as stats] - [web.ws :as ws])) + [web.ws :as ws] + [stringer.core :as s])) (read-write/print-time-literals-clj!) @@ -25,7 +26,7 @@ precon (and target (keyword (str/lower-case target)))] (when (or (and (= format "system-gateway") (contains? #{:beginner :intermediate} precon)) - (and (= (str format) "preconstructed") + (and (= (s/strcat format) "preconstructed") (contains? all-matchups precon))) precon))) @@ -96,7 +97,7 @@ (if (:started lobby) [:name :date :identity] [:name :date])) - (assoc :_id (str _id) :status status))] + (assoc :_id (s/strcat _id) :status status))] (assoc player :deck deck)) player)) @@ -215,7 +216,7 @@ users (map #(get user-cache %) uids)] (broadcast-lobby-list users))) ([users] - (assert (or (sequential? users) (nil? users)) (str "Users must be a sequence: " (pr-str users))) + (assert (or (sequential? users) (nil? users)) (s/strcat "Users must be a sequence: " (pr-str users))) (let [lobbies (app-state/get-lobbies)] (doseq [[uid ev] (prepare-lobby-list lobbies users)] (when uid @@ -250,7 +251,7 @@ ?data :?data}] (let [lobby (-> (create-new-lobby {:uid uid :user user :options ?data}) (send-message - (core/make-system-message (str (:username user) " has created the game.")))) + (core/make-system-message (s/strcat (:username user) " has created the game.")))) new-app-state (swap! app-state/app-state update :lobbies register-lobby lobby uid) lobby? (get-in new-app-state [:lobbies (:gameid lobby)])] @@ -336,7 +337,7 @@ (on-close lobby)))) (defn leave-lobby! [db user uid ?reply-fn lobby] - (let [leave-message (core/make-system-message (str (:username user) " left the game.")) + (let [leave-message (core/make-system-message (s/strcat (:username user) " left the game.")) new-app-state (swap! app-state/app-state update :lobbies #(-> % (handle-leave-lobby uid leave-message) @@ -498,7 +499,7 @@ (defn join-lobby! [user uid ?data ?reply-fn lobby] (let [correct-password? (check-password lobby user (:password ?data)) - join-message (core/make-system-message (str (:username user) " joined the game.")) + join-message (core/make-system-message (s/strcat (:username user) " joined the game.")) new-app-state (swap! app-state/app-state update :lobbies #(-> % (handle-join-lobby ?data uid user correct-password? join-message) @@ -562,12 +563,12 @@ (let [[player1 player2] (mapv swap-side players) player1-username (-> player1 :user :username) player2-username (-> player2 :user :username)] - (str player1-username " has swapped sides. " + (s/strcat player1-username " has swapped sides. " (if (= current-side "Any Side") "Waiting for opponent." - (str player1-username " is now " (:side player1) ". ")) + (s/strcat player1-username " is now " (:side player1) ". ")) (when player2 - (str player2-username " is now " (:side player2) "."))))) + (s/strcat player2-username " is now " (:side player2) "."))))) (defmethod ws/-msg-handler :lobby/swap @@ -596,7 +597,7 @@ (when (superuser? user) (let [player-name (-> lobby :original-players first :user :username) bad-name (:title lobby) - new-app-state (swap! app-state/app-state assoc-in [:lobbies gameid :title] (str player-name "'s game"))] + new-app-state (swap! app-state/app-state assoc-in [:lobbies gameid :title] (s/strcat player-name "'s game"))] (send-lobby-state (get-in new-app-state [:lobbies (:gameid lobby)])) (broadcast-lobby-list) (mc/insert db :moderator_actions @@ -678,7 +679,7 @@ (let [lobby (app-state/get-lobby gameid)] (when (and lobby (allowed-in-lobby user lobby)) (let [correct-password? (check-password lobby user password) - watch-message (core/make-system-message (str (:username user) " joined the game as a spectator" (when request-side (str " (" request-side " perspective)")) ".")) + watch-message (core/make-system-message (s/strcat (:username user) " joined the game as a spectator" (when request-side (s/strcat " (" request-side " perspective)")) ".")) new-app-state (swap! app-state/app-state update :lobbies #(-> % (handle-watch-lobby gameid uid user correct-password? watch-message request-side) diff --git a/src/clj/web/pages.clj b/src/clj/web/pages.clj index 4cd29e2905..10d7804ea4 100644 --- a/src/clj/web/pages.clj +++ b/src/clj/web/pages.clj @@ -7,7 +7,8 @@ [monger.operators :refer :all] [ring.middleware.anti-forgery :as anti-forgery] [web.utils :refer [response html-response]] - [web.versions :refer [frontend-version]])) + [web.versions :refer [frontend-version]] + [stringer.core :as s])) (defn index-page ([request] (index-page request nil nil)) @@ -30,7 +31,7 @@ (hiccup/include-css "/lib/css/toastr.min.css") (if (= "dev" server-mode) (hiccup/include-css "/css/netrunner.css") - (hiccup/include-css (str "/css/netrunner.css?v=" @frontend-version)))] + (hiccup/include-css (s/strcat "/css/netrunner.css?v=" @frontend-version)))] [:body [:div#sente-csrf-token {:style {:display "hidden"} @@ -48,11 +49,11 @@ (hiccup/include-js "https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js") (hiccup/include-js "/lib/js/toastr.min.js") [:script {:type "text/javascript"} - (str "var user=" (json/generate-string user) ";")] + (s/strcat "var user=" (json/generate-string user) ";")] (if (= "dev" server-mode) (list (hiccup/include-js "/js/cljs-runtime/goog.base.js") (hiccup/include-js "/js/main.js")) - (list (hiccup/include-js (str "/js/main.js?v=" @frontend-version))))])))) + (list (hiccup/include-js (s/strcat "/js/main.js?v=" @frontend-version))))])))) (defn reset-password-page [{db :system/db diff --git a/src/clj/web/stats.clj b/src/clj/web/stats.clj index 5154e01d62..73020ce06f 100644 --- a/src/clj/web/stats.clj +++ b/src/clj/web/stats.clj @@ -15,7 +15,8 @@ [web.pages :as pages] [web.user :refer [active-user?]] [web.utils :refer [json-response response mongo-time-to-utc-string]] - [web.ws :as ws])) + [web.ws :as ws] + [stringer.core :as s])) (defn clear-userstats-handler "Clear any statistics for a given user-id contained in a request" @@ -48,7 +49,7 @@ (defn build-stats-kw "Take a stats prefix and add a side to it" [prefix side] - (keyword (str prefix (lower-case (or side "Corp"))))) + (keyword (s/strcat prefix (lower-case (or side "Corp"))))) (defn inc-deck-stats "Update deck stats for a given counter" @@ -127,14 +128,14 @@ userstats (:stats (stats-for-user db user-id)) deckstats (:stats (stats-for-deck db deck-id))] (ws/chsk-send! (:uid player) [:stats/update {:userstats userstats - :deck-id (str deck-id) + :deck-id (s/strcat deck-id) :deckstats deckstats}])))) (defn game-started [db {:keys [gameid date start-date title room players format]}] (let [corp (some #(when (= "Corp" (:side %)) %) players) runner (some #(when (= "Runner" (:side %)) %) players)] - (mc/insert db :game-logs {:gameid (str gameid) + (mc/insert db :game-logs {:gameid (s/strcat gameid) :title title :room room :creation-date date @@ -186,7 +187,7 @@ should-share-replay (:bug-reported @state)] (try (mc/update db :game-logs - {:gameid (str gameid)} + {:gameid (s/strcat gameid)} {$set {:winner (:winner @state) :reason (:reason @state) :end-date (inst/now) @@ -253,7 +254,7 @@ (response 401 {:message "Unauthorized"}))) (defn fetch-elapsed [db gameid] - (let [stats (mc/find-one-as-map db :game-logs {:gameid (str gameid)} ["stats"])] + (let [stats (mc/find-one-as-map db :game-logs {:gameid (s/strcat gameid)} ["stats"])] (-> stats :stats :time :elapsed))) (defn check-annotations-size [annotations] @@ -284,7 +285,7 @@ :runner (get-in body [:turns :runner])} :clicks (:clicks body)})] (mc/update db :game-logs - {:gameid (str gameid)} + {:gameid (s/strcat gameid)} {$set {:annotations new-annotations}}) (response 200 {:message "Annotations published"})) (response 413 {:message "File too large"}))) @@ -298,7 +299,7 @@ (mc/find-one-as-map db :game-logs {:gameid gameid} ["corp" "runner" "replay" "replay-shared" "annotations"]) replay (or replay {}) annotations (or annotations []) - [ind anno] (first (filter #(= date (str (:date (second %)))) (map-indexed vector annotations)))] + [ind anno] (first (filter #(= date (s/strcat (:date (second %)))) (map-indexed vector annotations)))] (if (or (= username (:username anno)) (= username (get-in runner [:player :username])) (= username (get-in corp [:player :username]))) @@ -309,7 +310,7 @@ (vec (concat (subvec annotations 0 ind) (subvec annotations (inc ind))))] (mc/update db :game-logs - {:gameid (str gameid)} + {:gameid (s/strcat gameid)} {$set {:annotations new-annotations}}) (response 200 {:message "Annotations deleted"})) (response 404 {:message "Annotations not found"}))) @@ -338,7 +339,7 @@ (if username (try (mc/update db :game-logs - {$and [{:gameid (str gameid)} + {$and [{:gameid (s/strcat gameid)} {$or [{:corp.player.username username} {:runner.player.username username}]}]} {$set {:replay-shared true}}) @@ -350,12 +351,12 @@ (defn- get-winner-card [winner corp runner host] - (let [default-img (str host "/img/icons/jinteki_167.png")] + (let [default-img (s/strcat host "/img/icons/jinteki_167.png")] (if winner (let [win-id (:identity ((keyword winner) {:corp corp :runner runner})) win-card-img (get-in (@all-cards win-id) [:images :en :default :stock])] (if win-card-img - (str host win-card-img) + (s/strcat host win-card-img) default-img)) default-img))) @@ -369,22 +370,22 @@ (let [{:keys [replay winner corp runner title]} (mc/find-one-as-map db :game-logs {:gameid (or gameid bugid)}) replay (or replay {}) gameid-str (cond ; different string for replays and bug-reports - gameid (if (and n d) (str gameid "?n=" n "&d=" d) gameid) - bugid (str bugid "?bug-report" (when b (str "&b=" b))))] + gameid (if (and n d) (s/strcat gameid "?n=" n "&d=" d) gameid) + bugid (s/strcat bugid "?bug-report" (when b (s/strcat "&b=" b))))] (if (empty? replay) (response 404 {:message "Replay not found"}) (let [corp-user (get-in corp [:player :username] "Unknown") corp-id (:identity corp) runner-user (get-in runner [:player :username] "Unknown") runner-id (:identity runner) - host (str (name scheme) "://" (get headers "host")) + host (s/strcat (name scheme) "://" (get headers "host")) og {:type "website" :url (request-url req) :image (get-winner-card winner corp runner host) - :title (str (cond + :title (s/strcat (cond gameid "REPLAY: " bugid "BUG-REPORT: ") title) :site_name "jinteki.net" - :description (str corp-user " (" corp-id ") vs. " runner-user " (" runner-id ")")}] + :description (s/strcat corp-user " (" corp-id ") vs. " runner-user " (" runner-id ")")}] (pages/index-page req og gameid-str))))) diff --git a/src/clj/web/system.clj b/src/clj/web/system.clj index 0536b6fced..62112b8012 100644 --- a/src/clj/web/system.clj +++ b/src/clj/web/system.clj @@ -32,7 +32,8 @@ [web.telemetry] [web.utils :refer [tick]] [web.versions :refer [banned-msg frontend-version]] - [web.ws :refer [ch-chsk event-msg-handler]])) + [web.ws :refer [ch-chsk event-msg-handler]] + [stringer.core :as s])) (read-write/print-time-literals-clj!) @@ -52,7 +53,7 @@ (defmethod ig/init-key :mongodb/connection [_ opts] (let [{:keys [address port name connection-string]} opts - connection (or connection-string (str "mongodb://" address ":" port "/" name))] + connection (or connection-string (s/strcat "mongodb://" address ":" port "/" name))] (mg/connect-via-uri connection))) (defmethod ig/halt-key! :mongodb/connection [_ {:keys [conn]}]