diff --git a/src/clj/game/cards/agendas.clj b/src/clj/game/cards/agendas.clj index 8c6cf84283..b7a8386d06 100644 --- a/src/clj/game/cards/agendas.clj +++ b/src/clj/game/cards/agendas.clj @@ -804,6 +804,7 @@ (defcard "Escalate Vitriol" {:abilities [{:action true :label "Gain 1 [Credit] for each Runner tag" + :change-in-game-state {:req (req tagged)} :cost [(->c :click 1)] :once :per-turn :msg (msg "gain " (count-tags state) " [Credits]") @@ -833,7 +834,7 @@ :effect (effect (gain-credits :corp eid 5))}}}}) (defcard "False Lead" - {:abilities [{:req (req (<= 2 (:click runner))) + {:abilities [{:change-in-game-state {:req (req (<= 2 (:click runner)))} :label "runner loses [Click][Click]" :msg "force the Runner to lose [Click][Click]" :cost [(->c :forfeit-self)] @@ -933,8 +934,8 @@ (defcard "Glenn Station" {:abilities [{:action true :label "Host a card from HQ" - :req (req (and (not-empty (:hand corp)) - (empty? (filter corp? (:hosted card))))) + :change-in-game-state {:req (req (and (not-empty (:hand corp)) + (empty? (filter corp? (:hosted card)))))} :cost [(->c :click 1)] :msg "host a card from HQ" :prompt "Choose a card to host" @@ -942,7 +943,7 @@ :effect (effect (host card target {:facedown true}))} {:action true :label "Add a hosted card to HQ" - :req (req (not-empty (filter corp? (:hosted card)))) + :change-in-game-state {:req (req (not-empty (filter corp? (:hosted card))))} :cost [(->c :click 1)] :msg "add a hosted card to HQ" :prompt "Choose a hosted card" @@ -994,19 +995,24 @@ :effect (effect (continue-ability (graft 1) card nil))}})) (defcard "Hades Fragment" - {:flags {:corp-phase-12 (req (and (not-empty (get-in @state [:corp :discard])) - (is-scored? state :corp card)))} - :abilities [{:prompt "Choose a card to add to the bottom of R&D" - :label "add card to bottom of R&D" - :show-discard true - :choices {:card #(and (corp? %) - (in-discard? %))} - :effect (effect (move target :deck)) - :msg (msg "add " - (if (:seen target) - (:title target) - "a card") - " to the bottom of R&D")}]}) + (let [abi {:prompt "Choose a card to add to the bottom of R&D" + :label "add card to bottom of R&D" + :show-discard true + :event :corp-turn-begins + :once :per-turn + :choices {:card #(and (corp? %) + (in-discard? %))} + :effect (effect (move target :deck)) + :msg (msg "add " + (if (:seen target) + (:title target) + "a card") + " to the bottom of R&D")}] + {:flags {:corp-phase-12 (req (and (seq (:discard corp)) + (is-scored? state :corp card)))} + :abilities [abi] + :events [(assoc abi + :change-in-game-state {:req (req (seq (:discard corp))) :silent (req true)})]})) (defcard "Helium-3 Deposit" {:on-score @@ -1029,6 +1035,7 @@ :silent (req true)} :abilities [{:action true :cost [(->c :click 1) (->c :agenda 1)] + :change-in-game-state {:req (req (pos? (:credit runner)))} :label "gain credits" :msg (msg "gain " (:credit runner) " [Credits]") :async true @@ -1203,7 +1210,7 @@ :effect (effect (add-counter eid card :power 2 nil))} :interactions {:prevent [{:type #{:jack-out} :req (req (pos? (get-counters card :power)))}]} - :abilities [{:req (req (:run @state)) + :abilities [{:change-in-game-state {:req (req (:run @state))} :cost [(->c :power 1)] :msg "prevent the Runner from jacking out" :effect (effect (jack-out-prevent))}]}) @@ -1452,7 +1459,7 @@ {:on-score {:silent (req true) :async true :effect (effect (add-counter eid card :agenda 1 nil))} - :abilities [{:req (req (:run @state)) + :abilities [{:change-in-game-state {:req (req (:run @state))} :cost [(->c :agenda 1)] :msg "end the run" :async true @@ -1644,6 +1651,8 @@ :choices {:card #(and (ice? %) (rezzed? %))} :cost [(->c :agenda 1)] + :change-in-game-state {:req (req (and run (some (every-pred ice? rezzed?) + (all-installed state :corp))))} :keep-menu-open :while-agenda-tokens-left :msg (str "make a piece of ice gain \"[Subroutine] Do 1 net damage\" " "after all its other subroutines for the remainder of the run") @@ -2312,6 +2321,7 @@ :async true :effect (effect (add-counter eid card :agenda 2 nil))} :abilities [{:cost [(->c :agenda 1)] + :once :per-turn :req (req run) :msg "prevent this run from becoming successful" :effect (effect (register-lingering-effect diff --git a/src/clj/game/cards/assets.clj b/src/clj/game/cards/assets.clj index ff920fb6a2..01b8c3827a 100644 --- a/src/clj/game/cards/assets.clj +++ b/src/clj/game/cards/assets.clj @@ -132,6 +132,7 @@ :abilities [{:label "Install a non-agenda card from HQ" :async true :prompt "Choose a non-agenda card to install from HQ" + :change-in-game-state {:req (req (seq (:hand corp)))} :req (req (not (:run @state))) :choices {:card #(and (corp-installable-type? %) (not (agenda? %)) @@ -312,8 +313,8 @@ :effect (req (wait-for (gain-credits state side 1) (lose-credits state :runner eid 1)))}]}) -(defcard "B-1001" - {:abilities [{:req (req (not this-server)) +(defcard "B-1001" ;; note -> run restriction added by rules as errata + {:abilities [{:req (req (and run (not this-server))) :async true :cost [(->c :tag 1)] :msg "end the run" @@ -395,6 +396,7 @@ {:implementation "Timing restriction of ability use not enforced" :abilities [{:label "Install 1 card, paying all costs" :req (req (= (:active-player @state) :corp)) + :change-in-game-state {:req (req (seq (:hand corp)))} :prompt "Choose a card in HQ to install" :choices {:card #(and (not (operation? %)) (in-hand? %) @@ -818,7 +820,7 @@ :effect (effect (add-counter :corp eid card :credit 2 nil))}] :abilities [{:label "Take all hosted credits" :cost [(->c :trash-can)] - :req (req (pos? (get-counters card :credit))) + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :msg (msg "gain " (get-counters card :credit) " [Credits]") :async true :effect (effect (gain-credits eid (get-counters card :credit)))} @@ -1033,6 +1035,7 @@ :effect (effect (add-counter eid card :power 1 nil))}] :abilities [{:label "Draw 1 card and gain 2 [Credits] for each hosted power counter" :cost [(->c :trash-can)] + :change-in-game-state {:req (req (pos? (get-counters card :power)))} :async true :effect (req (let [counters (get-counters card :power) credits (* 2 counters)] @@ -1376,6 +1379,7 @@ :effect (effect (trash eid target {:cause-card card})) :msg (msg "trash " (:title target) " from the grip")})) choose-ability {:label "Trash 1 card in the grip of a named type" + :change-in-game-state {:req (req (seq (:hand runner))) :silent true} :once :per-turn :req (req (seq (:hand runner))) :prompt "Choose a card type" @@ -1518,6 +1522,7 @@ {:derezzed-events [corp-rez-toast] :flags {:corp-phase-12 (req true)} :abilities [{:msg "look at the top card of the stack" + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :effect (effect (continue-ability {:prompt (req (->> runner :deck first :title (str "The top card of the stack is "))) diff --git a/src/clj/game/cards/events.clj b/src/clj/game/cards/events.clj index f8c3803ad6..4b1e0ce0f4 100644 --- a/src/clj/game/cards/events.clj +++ b/src/clj/game/cards/events.clj @@ -79,7 +79,7 @@ {:makes-run true :on-play {:async true :prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :effect (effect (make-run eid target card))} :events [{:event :subroutines-broken @@ -97,7 +97,7 @@ (defcard "Account Siphon" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -270,7 +270,7 @@ {:makes-run true :on-play {:async true :prompt "Choose a server" - :change-in-game-state (req (seq (filter #(can-run-server? state %) remotes))) + :change-in-game-state {:req (req (seq (filter #(can-run-server? state %) remotes)))} :choices (req (cancellable (filter #(can-run-server? state %) remotes))) :effect (effect (make-run eid target card))} :events [(successful-run-replace-breach @@ -295,7 +295,7 @@ {:makes-run true :on-play {:req (req (has-bad-pub? state)) :prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :msg "prevent ice from being rezzed during this run" :async true @@ -311,7 +311,7 @@ (defcard "Blueberry!™ Diesel" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :prompt "Move a card to the bottom of the stack?" :not-distinct true :choices (req (conj (vec (take 2 (:deck runner))) "No")) @@ -333,7 +333,7 @@ (zones->sorted-names (get-runnable-zones state side eid card nil))))] {:makes-run true :on-play {:async true - :change-in-game-state (req (seq (iced-servers state side eid card))) + :change-in-game-state {:req (req (seq (iced-servers state side eid card)))} :prompt "Choose an iced server" :choices (req (iced-servers state side eid card)) :effect (effect (register-events @@ -463,7 +463,7 @@ card nil)))})] {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -503,8 +503,8 @@ {:on-play {:msg (msg "gain " (count (filter #(and (has-subtype? % "Connection") (resource? %)) (all-active-installed state :runner))) " [Credits]") - :change-in-game-state (req (some #(and (has-subtype? % "Connection") (resource? %)) - (all-active-installed state :runner))) + :change-in-game-state {:req (req (some #(and (has-subtype? % "Connection") (resource? %)) + (all-active-installed state :runner)))} :async true :effect (effect (gain-credits eid (count (filter #(and (has-subtype? % "Connection") (resource? %)) @@ -513,7 +513,7 @@ (defcard "Career Fair" {:on-play {:prompt "Choose a resource to install" - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :choices {:req (req (and (resource? target) (in-hand? target) (can-pay? state side (assoc eid :source card :source-type :runner-install) target nil @@ -589,7 +589,7 @@ card nil))})] {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -610,7 +610,7 @@ (defcard "Chastushka" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -648,7 +648,7 @@ (* -3 (count (get-in @state [:corp :servers :rd :ices]))))] {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [(successful-run-replace-breach {:target-server :rd @@ -675,7 +675,7 @@ :data {:counter {:credit 4}} :on-play {:async true :prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :effect (effect (make-run eid target card))} :interactions {:pay-credits {:req (req run) @@ -707,7 +707,7 @@ :on-play {:prompt "Choose a server" :msg "make a run and install a program on encounter with the first piece of ice" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (make-run eid target card))} :events [{:event :encounter-ice @@ -765,8 +765,8 @@ :choices {:req (req (and (installed? target) (runner? target) (zero? (get-virus-counters state target))))} - :change-in-game-state (req (some #(zero? (get-virus-counters state %)) - (all-installed state :runner))) + :change-in-game-state {:req (req (some #(zero? (get-virus-counters state %)) + (all-installed state :runner)))} :async true :effect (effect (add-counter :runner eid target :virus 3 nil))}}) @@ -796,7 +796,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (make-run eid target card))} :events [{:event :pre-access-card @@ -908,7 +908,7 @@ (defcard "Data Breach" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (wait-for (make-run state side :rd card) (let [card (get-card state card)] @@ -933,7 +933,7 @@ (defcard "Deep Data Mining" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [{:event :successful-run :req (req (and (= :rd (target-server context)) @@ -967,7 +967,7 @@ (some #{:rd} (:successful-run runner-reg)) (some #{:archives} (:successful-run runner-reg)))) :async true - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (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) @@ -1013,8 +1013,8 @@ (defcard "Déjà Vu" {:on-play - {:change-in-game-state (req (and (seq (:discard runner)) - (not (zone-locked? state :runner :discard)))) + {:change-in-game-state {:req (req (and (seq (:discard runner)) + (not (zone-locked? state :runner :discard))))} :prompt "Choose a card to add to Grip" :choices (req (cancellable (:discard runner) :sorted)) :msg (msg "add " (:title target) " to [their] Grip") @@ -1031,7 +1031,7 @@ (defcard "Demolition Run" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (or hq-runnable rd-runnable)) + :change-in-game-state {:req (req (or hq-runnable rd-runnable))} :choices (req [(when hq-runnable "HQ") (when rd-runnable "R&D")]) :async true @@ -1092,7 +1092,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :msg "make a run" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -1123,7 +1123,7 @@ (defcard "Diesel" {:on-play {:msg "draw 3 cards" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :effect (effect (draw eid 3))}}) @@ -1163,7 +1163,7 @@ :on-play {:async true :prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :effect (effect (make-run eid target card))} :events [{:event :run-ends :req (req (and (:successful target) @@ -1176,7 +1176,7 @@ (letfn [(five-or-all [corp] (min 5 (:credit corp)))] {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -1192,7 +1192,7 @@ (defcard "Divide and Conquer" {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :events [{:event :end-breach-server :async true @@ -1236,7 +1236,7 @@ (defcard "Embezzle" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -1267,7 +1267,7 @@ (defcard "Emergency Shutdown" {:on-play {:req (req (some #{:hq} (:successful-run runner-reg))) - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :choices {:card #(and (ice? %) (rezzed? %))} :effect (effect (derez target {:source-card card}))}}) @@ -1290,8 +1290,8 @@ target {:cost-bonus (- trash-cost)}))})] {:on-play {:prompt "Choose pieces of hardware and/or programs to trash" - :change-in-game-state (req (or (seq (:deck runner)) - (seq (:hand runner)))) + :change-in-game-state {:req (req (or (seq (:deck runner)) + (seq (:hand runner))))} :choices {:card #(and (or (hardware? %) (program? %)) (in-hand? %)) @@ -1321,7 +1321,7 @@ (filter (complement rezzed?)))))} :msg (msg "trash " (card-str state target)) :async true - :cancel-effect (req (do-nothing state side eid card)) + :cancel-effect (req (do-nothing state side eid nil card)) :effect (effect (trash eid target {:cause-card card}))}}) (defcard "Encore" @@ -1346,7 +1346,7 @@ (effect-completed state side eid))))})] {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -1360,7 +1360,7 @@ (defcard "Eureka!" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (req (let [topcard (first (:deck runner)) caninst (and (or (hardware? topcard) (program? topcard) @@ -1401,7 +1401,7 @@ (defcard "Executive Wiretaps" {:on-play {:msg (msg "reveal " (enumerate-str (sort (map :title (:hand corp)))) " from HQ") - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :async true :effect (effect (reveal eid (:hand corp)))}}) @@ -1411,7 +1411,7 @@ (some #{:rd} (:successful-run runner-reg)) (some #{:archives} (:successful-run runner-reg)))) :prompt "Choose up to 3 pieces of ice to derez" - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :choices {:max 3 :card #(and (rezzed? %) (ice? %))} @@ -1423,7 +1423,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (make-run eid target card))} :events [(successful-run-replace-breach @@ -1452,7 +1452,7 @@ (defcard "Express Delivery" {:on-play {:prompt "Choose a card to add to the grip" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (take 4 (:deck runner))) :msg "look at the top 4 cards of the stack and add 1 of them to the grip" :effect (effect (move target :hand) @@ -1461,7 +1461,7 @@ (defcard "Eye for an Eye" {:makes-run true :on-play {:req (req (not tagged)) - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :async true :effect (req (make-run state side eid :hq card))} :interactions {:access-ability @@ -1512,7 +1512,7 @@ (defcard "Fear the Masses" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -1544,7 +1544,7 @@ (defcard "Feint" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [{:event :encounter-ice :req (req (< (get-in card [:special :bypass-count] 0) 2)) @@ -1557,7 +1557,7 @@ (defcard "Finality" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :additional-cost [(->c :brain 1)] :effect (req (make-run state side eid :rd card))} :events [{:event :successful-run @@ -1570,8 +1570,8 @@ (defcard "Fisk Investment Seminar" {:on-play {:msg "make each player draw 3 cards" - :change-in-game-state (req (or (seq (:deck runner)) - (seq (:deck corp)))) + :change-in-game-state {:req (req (or (seq (:deck runner)) + (seq (:deck corp))))} :async true :effect (req (wait-for (draw state :runner 3) (draw state :corp eid 3)))}}) @@ -1580,7 +1580,7 @@ {:on-play {:choices {:card #(and (ice? %) (not (rezzed? %)))} - :change-in-game-state (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp)))} :async true :effect (req (let [ice target serv (zone->name (second (get-zone ice))) @@ -1607,7 +1607,7 @@ (defcard "Frame Job" {:on-play {:prompt "Choose an agenda to forfeit" - :change-in-game-state (req (:scored runner)) + :change-in-game-state {:req (req (:scored runner))} :choices (req (:scored runner)) :msg (msg "forfeit " (get-title card) " and give the Corp 1 bad publicity") :async true @@ -1618,7 +1618,7 @@ (defcard "Frantic Coding" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (effect (continue-ability @@ -1671,7 +1671,7 @@ {:choices {:max 5 :card #(and (program? %) (in-hand? %))} - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :msg (msg "trash " (enumerate-str (map :title targets)) " and gain " (* 2 (count targets)) " [Credits]") :async true @@ -1681,14 +1681,14 @@ (defcard "Game Day" {:on-play {:msg (msg "draw " (quantify (- (hand-size state :runner) (count (:hand runner))) "card")) - :change-in-game-state (req (pos? (- (hand-size state :runner) (count (:hand runner))))) + :change-in-game-state {:req (req (pos? (- (hand-size state :runner) (count (:hand runner)))))} :async true :effect (effect (draw eid (- (hand-size state :runner) (count (:hand runner)))))}}) (defcard "Glut Cipher" {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :events [(successful-run-replace-breach {:target-server :archives @@ -1800,7 +1800,7 @@ (defcard "Hostage" {:on-play {:prompt "Choose a Connection" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (cancellable (filter #(has-subtype? % "Connection") (:deck runner)) :sorted)) :msg (msg "add " (:title target) " from the stack to the grip and shuffle the stack") :async true @@ -1822,7 +1822,7 @@ (defcard "Hot Pursuit" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [{:event :successful-run :async true @@ -1834,7 +1834,7 @@ (defcard "I've Had Worse" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (effect (draw eid 3))} :on-trash {:when-inactive true :interactive (req true) @@ -1846,7 +1846,7 @@ (defcard "Immolation Script" {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :events [{:event :breach-server :async true @@ -1890,7 +1890,7 @@ (if (some #(and (not (facedown? %)) (has-subtype? % "Directive")) targets) 2 1)))] {:on-play {:prompt "Choose up to 5 installed cards to trash" - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:req (req (seq (all-installed state :runner)))} :choices {:max 5 :card #(and (installed? %) (runner? %))} @@ -1903,7 +1903,7 @@ (defcard "Indexing" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [(successful-run-replace-breach {:target-server :rd @@ -1978,7 +1978,7 @@ card nil))}] {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -1989,7 +1989,7 @@ (defcard "Inject" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (req (let [cards (take 4 (:deck runner)) programs (filter program? cards) others (remove program? cards)] @@ -2018,7 +2018,7 @@ :on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (continue-ability (let [server target] @@ -2034,7 +2034,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (make-run eid target card))} :events [{:event :encounter-ice @@ -2046,7 +2046,7 @@ {:on-play {:async true :player :corp - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :waiting-prompt true :effect (req (wait-for (resolve-ability state :corp (reorder-choice :corp (take 4 (:deck corp))) card targets) @@ -2118,7 +2118,7 @@ (effect-completed state side eid)))))})] {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (register-events @@ -2151,7 +2151,7 @@ (defcard "Jailbreak" {:makes-run true - :on-play {:change-in-game-state (req (or rd-runnable hq-runnable)) + :on-play {:change-in-game-state {:req (req (or rd-runnable hq-runnable))} :prompt "Choose a server" :choices (req [(when hq-runnable "HQ") (when rd-runnable "R&D")]) @@ -2169,7 +2169,7 @@ (defcard "Joy Ride" {:on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [{:event :successful-run :silent (req true) @@ -2183,7 +2183,7 @@ {:makes-run true :on-play {:async true :prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :effect (effect (make-run eid target card))} :events [{:event :successful-run @@ -2249,7 +2249,7 @@ (effect-completed state side eid))))))}] {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [(successful-run-replace-breach {:target-server :rd @@ -2264,7 +2264,7 @@ {:on-play {:req (req (:stole-agenda runner-reg)) :prompt "Choose a server" - :change-in-game-state (req (some ice? (all-installed state :corp))) + :change-in-game-state {:req (req (some ice? (all-installed state :corp)))} :choices (req servers) :msg (msg "force the Corp to trash a piece of ice protecting " target) :async true @@ -2284,9 +2284,9 @@ {:on-play {:rfg-instead-of-trashing true :async true - :change-in-game-state (req (or (seq (:deck runner)) - (and (seq (:discard runner)) - (not (zone-locked? state :runner :discard))))) + :change-in-game-state {:req (req (or (seq (:deck runner)) + (and (seq (:discard runner)) + (not (zone-locked? state :runner :discard)))))} :effect (req (let [mill-count (min 3 (count (:deck runner))) top-n-msg (seq (take mill-count (:deck runner)))] @@ -2323,7 +2323,7 @@ (defcard "Lawyer Up" {:on-play {:msg "remove 2 tags and draw 3 cards" - :change-in-game-state (req (or tagged (seq (:deck runner)))) + :change-in-game-state {:req (req (or tagged (seq (:deck runner))))} :async true :effect (req (wait-for (lose-tags state side 2) (draw state side eid 3)))}}) @@ -2332,7 +2332,7 @@ {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :msg (msg "make a run on " target (when (<= (count (filter program? (all-active-installed state :runner))) 3) @@ -2347,7 +2347,7 @@ :on-play {:prompt "Choose a server" :msg "make a run and derez all ice that is rezzed during this run" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (req (make-run state side eid target (get-card state card)))} :events [{:event :run-ends @@ -2364,7 +2364,7 @@ (defcard "Legwork" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [{:event :successful-run :silent (req true) @@ -2415,7 +2415,7 @@ (defcard "Mad Dash" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -2453,7 +2453,7 @@ card nil))))})] {:on-play {:msg "look at and trash or rearrange the top 6 cards of the stack" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :waiting-prompt true :effect (effect (continue-ability (entrance-trash (take 6 (:deck runner))) card nil))}})) @@ -2461,7 +2461,7 @@ (defcard "Marathon" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq (filter #(can-run-server? state %) remotes))) + :change-in-game-state {:req (req (seq (filter #(can-run-server? state %) remotes)))} :choices (req (filter #(can-run-server? state %) remotes)) :async true :effect (effect (make-run eid target card))} @@ -2508,7 +2508,7 @@ (continue-ability state side (mhelper (inc n)) card nil)))}))] {:on-play {:async true - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :effect (effect (continue-ability (mhelper 0) card nil))}})) (defcard "Meeting of Minds" @@ -2573,7 +2573,7 @@ (defcard "Möbius" {:on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (wait-for (make-run state side :rd card) (let [card (get-card state card)] (if (get-in card [:special :run-again]) @@ -2597,7 +2597,7 @@ (defcard "Modded" {:on-play {:prompt "Choose a program or piece of hardware to install" - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :choices {:req (req (and (or (hardware? target) (program? target)) (in-hand? target) @@ -2619,7 +2619,7 @@ (defcard "Mutual Favor" {:on-play {:prompt "Choose an Icebreaker" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (cancellable (filter #(has-subtype? % "Icebreaker") (:deck runner)) :sorted)) :msg (msg "add " (:title target) " from the stack to the grip and shuffle the stack") :async true @@ -2689,7 +2689,7 @@ {:on-play {:prompt "Choose a resource to host On the Lam on" :choices {:card #(and (resource? %) (installed? %))} - :change-in-game-state (req (some resource? (all-active-installed state :runner))) + :change-in-game-state {:req (req (some resource? (all-active-installed state :runner)))} :async true :effect (req (system-msg state side (str "hosts On the Lam on " (:title target))) (install-as-condition-counter state side eid card target))} @@ -2732,7 +2732,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect (make-run eid target card))} :events [{:event :runner-turn-begins @@ -2756,7 +2756,7 @@ :interactions {:pay-credits {:req (req run) :type :credit}} :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))}}) @@ -2764,7 +2764,7 @@ (defcard "Paper Tripping" {:on-play {:msg "remove all tags" - :change-in-game-state (req tagged) + :change-in-game-state {:req (req tagged)} :async true :effect (effect (lose-tags eid :all))}}) @@ -2780,7 +2780,7 @@ (defcard "Pinhole Threading" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -2818,7 +2818,7 @@ (defcard "Planned Assault" {:on-play {:prompt "Choose a Run event" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (sort-by :title (filter #(and (has-subtype? % "Run") (can-pay? state side (assoc eid :source card :source-type :play) % nil @@ -2833,7 +2833,7 @@ (defcard "Political Graffiti" {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :static-abilities [{:type :agenda-value :req (req (same-card? (:host card) target)) @@ -2887,7 +2887,7 @@ (defcard "Prey" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -2981,7 +2981,7 @@ {:makes-run true :on-play {:async true :req (req (not tagged)) - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :events [(successful-run-replace-breach {:target-server :archives @@ -3043,7 +3043,7 @@ (defcard "Pushing the Envelope" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :msg (msg (if (<= (count (:hand runner)) 2) "make a run, and give +2 strength to installed icebreakers" @@ -3056,7 +3056,7 @@ (defcard "Quality Time" {:on-play {:msg "draw 5 cards" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :effect (effect (draw eid 5))}}) @@ -3090,7 +3090,7 @@ {:req (req (and (some #{:hq} (:successful-run runner-reg)) (some #{:rd} (:successful-run runner-reg)) (some #{:archives} (:successful-run runner-reg)))) - :change-in-game-state (req (some (complement ice?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (complement ice?) (all-installed state :corp)))} :choices {:card installed?} :msg (msg "access " (:title target)) :async true @@ -3099,7 +3099,7 @@ (defcard "Raindrops Cut Stone" {:makes-run true :on-play {:async true - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :prompt "Choose a server" :choices (req runnable-servers) :effect (effect (make-run eid target card))} @@ -3171,7 +3171,7 @@ (effect-completed state side eid))))] {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :rfg-instead-of-trashing true :effect (req (make-run state side eid :archives card))} :events [(successful-run-replace-breach @@ -3191,7 +3191,7 @@ (defcard "Recon" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -3268,7 +3268,7 @@ (defcard "Retrieval Run" {:makes-run true :on-play {:async true - :change-in-game-state (req archives-runnable) + :change-in-game-state {:req (req archives-runnable)} :effect (req (make-run state side eid :archives card))} :events [(successful-run-replace-breach {:target-server :archives @@ -3337,7 +3337,7 @@ (in-hand? target) (can-pay? state side (assoc eid :source card :source-type :runner-install) target nil [(->c :credit (install-cost state side target {:cost-bonus -3}))])))} - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :async true :effect (req (wait-for (runner-install state side (make-eid state {:source card :source-type :runner-install}) target {:cost-bonus -3 :msg-keys {:install-source card @@ -3389,7 +3389,7 @@ {:makes-run true :on-play {:async true :rfg-instead-of-trashing true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [{:event :successful-run :silent (req true) @@ -3418,7 +3418,7 @@ ice)))] {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (update! (assoc-in card [:special :run-amok] (get-rezzed-cids (all-installed state :corp)))) @@ -3451,7 +3451,7 @@ (defcard "Running Interference" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (register-lingering-effect @@ -3469,10 +3469,10 @@ (map unknown->kw) (filter is-central?) (map central->name))) - :change-in-game-state (req (seq (->> runnable-servers - (map unknown->kw) - (filter is-central?) - (map central->name)))) + :change-in-game-state {:req (req (seq (->> runnable-servers + (map unknown->kw) + (filter is-central?) + (map central->name))))} :async true :effect (effect (make-run eid target card))} :events [{:event :encounter-ice @@ -3501,7 +3501,7 @@ (installed? %) (not (rezzed? %)))} :async true - :change-in-game-state (req (some (complement faceup?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (complement faceup?) (all-installed state :corp)))} :effect (req (if (pos? (count targets)) (wait-for (expose state side target) (if (= 2 (count targets)) @@ -3568,7 +3568,7 @@ (defcard "Showing Off" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [{:event :successful-run :req (req (and (= :rd (target-server context)) @@ -3583,7 +3583,7 @@ {:makes-run true :on-play {:prompt "Choose a server" :choices (req (filter #(can-run-server? state %) remotes)) - :change-in-game-state (req (some #(can-run-server? state %) remotes)) + :change-in-game-state {:req (req (some #(can-run-server? state %) remotes))} :async true :effect (effect (make-run eid target card))} :events [(successful-run-replace-breach @@ -3601,7 +3601,7 @@ :choices {:card #(and (not (rezzed? %)) (installed? %) (ice? %))} - :change-in-game-state (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp)))} :msg (msg "select " (card-str state target)) :effect (effect (register-events @@ -3659,13 +3659,13 @@ (spark-search-fn state side eid card rest-of-deck revealed-cards))) (continue-ability state side (shuffle-back revealed-cards) card nil)))] {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (effect (spark-search-fn eid card (:deck runner) []))}})) (defcard "Spear Phishing" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -3685,7 +3685,7 @@ (defcard "Special Order" {:on-play {:prompt "Choose an Icebreaker" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (cancellable (filter #(has-subtype? % "Icebreaker") (:deck runner)) :sorted)) :msg (msg "add " (:title target) " from the stack to the grip and shuffle the stack") :effect (effect (trigger-event :searched-stack) @@ -3717,7 +3717,7 @@ {:data {:counter {:power 3}} :makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (make-run eid target card))} @@ -3743,7 +3743,7 @@ (defcard "Steelskin Scarring" {:on-play {:async true :msg "draw 3 cards" - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (effect (draw eid 3))} :on-trash {:when-inactive true :interactive (req true) @@ -3763,7 +3763,7 @@ (defcard "Stimhack" {:makes-run true :on-play {:prompt "Choose a server" - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :choices (req runnable-servers) :async true :effect (effect (gain-next-run-credits 9) @@ -3905,7 +3905,7 @@ (defcard "The Maker's Eye" {:makes-run true :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} :events [{:event :successful-run :silent (req true) @@ -3917,8 +3917,8 @@ (defcard "The Noble Path" {:makes-run true :on-play {:async true - :change-in-game-state (req (or (seq (:hand runner)) - (seq runnable-servers))) + :change-in-game-state {:req (req (or (seq (:hand runner)) + (seq runnable-servers)))} :effect (req (wait-for (trash-cards state side (:hand runner) {:cause-card card}) (continue-ability @@ -3938,7 +3938,7 @@ (defcard "The Price" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (req (wait-for (mill state :runner (make-eid state eid) :runner 4) @@ -3992,7 +3992,7 @@ {:prompt "Choose a piece of ice" :choices {:card #(and (installed? %) (ice? %))} - :change-in-game-state (req (some ice? (all-installed state :corp))) + :change-in-game-state {:req (req (some ice? (all-installed state :corp)))} :msg (msg "make " (card-str state target) " gain Sentry, Code Gate, and Barrier until the end of the turn") :effect (req (register-lingering-effect state side card (let [ice target] @@ -4039,7 +4039,7 @@ {:on-play {:prompt "Choose a server" :choices (req runnable-servers) - :change-in-game-state (req (seq runnable-servers)) + :change-in-game-state {:req (req (seq runnable-servers))} :makes-run true :async true :effect (effect (register-lingering-effect @@ -4056,7 +4056,7 @@ :interactions {:pay-credits {:req (req run) :type :credit}} :on-play {:async true - :change-in-game-state (req rd-runnable) + :change-in-game-state {:req (req rd-runnable)} :effect (req (update! state side (assoc-in card [:special :run-eid] eid)) (make-run state side eid :rd card))} @@ -4087,9 +4087,9 @@ (defcard "Uninstall" {:on-play - {:change-in-game-state (req (some #(and (not (facedown? %)) - (or (hardware? %) (program? %))) - (all-installed state :runner))) + {:change-in-game-state {:req (req (some #(and (not (facedown? %)) + (or (hardware? %) (program? %))) + (all-installed state :runner)))} :choices {:card #(and (installed? %) (not (facedown? %)) (or (hardware? %) @@ -4112,7 +4112,7 @@ (defcard "Vamp" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -4130,8 +4130,8 @@ {:msg (msg "draw 4 cards" (when (pos? (:click runner)) " and lose [Click]")) - :change-in-game-state (req (or (seq (:deck runner)) - (pos? (:click runner)))) + :change-in-game-state {:req (req (or (seq (:deck runner)) + (pos? (:click runner))))} :async true :effect (req (when (pos? (:click runner)) (lose-clicks state :runner 1)) @@ -4140,7 +4140,7 @@ (defcard "Wanton Destruction" {:makes-run true :on-play {:async true - :change-in-game-state (req hq-runnable) + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state side eid :hq card))} :events [(successful-run-replace-breach {:target-server :hq @@ -4208,7 +4208,7 @@ (defcard "Windfall" {:on-play {:async true - :change-in-game-state (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (req (shuffle! state side :deck) (let [topcard (first (:deck (:runner @state))) cost (:cost topcard)] diff --git a/src/clj/game/cards/hardware.clj b/src/clj/game/cards/hardware.clj index 10312b8ad6..6194cc5c8e 100644 --- a/src/clj/game/cards/hardware.clj +++ b/src/clj/game/cards/hardware.clj @@ -376,7 +376,34 @@ :effect (effect (move (some #(when (= (:title card) (:title %)) %) (:discard runner)) :deck) - (shuffle! :deck))}}}])))}})]})) + (shuffle! :deck))}}}])))}}) + {:label "Break 0 subroutines" + :cost [(->c :trash-can)] + :msg "break 0 subroutines" + :req (req (if-let [boomerang-target (get-in card [:special :boomerang-target])] + (some #(same-card? boomerang-target (:ice %)) (:encounters @state)) + true)) + :effect (req (req (let [source (or card (first (get-in eid [:cost-paid :trash-can :paid/targets])))] + ;; special note: since the source is trashed, auto-pump-impl doesn't pass it on + ;; to the additional-abi in a nice way. This is a bit of a hack to fix that. + ;; If we ever rework costs, this might need to be adjusted -nbk, 2025 + (register-events + state side source + [{:event :run-ends + :duration :end-of-run + :unregister-once-resolved true + :optional + {:req (req (and (:successful target) + (not (zone-locked? state :runner :discard)) + (some #(= (:title card) (:title %)) (:discard runner)))) + :once :per-run + :prompt (msg "Shuffle a copy of " (:title card) " back into the Stack?") + :yes-ability + {:msg (msg "shuffle a copy of " (:title card) " back into the Stack") + :effect (effect (move (some #(when (= (:title card) (:title %)) %) + (:discard runner)) + :deck) + (shuffle! :deck))}}}]))))}]})) (defcard "Box-E" {:static-abilities [(mu+ 2) @@ -546,12 +573,12 @@ {:abilities [{:prompt "Choose a program to install" :label "Install program from the heap" :show-discard true - :req (req (some #(and (program? %) - (runner-can-pay-and-install? - state side - (assoc eid :source card :source-type :runner-install) % - {:no-toast true})) - (:discard runner))) + :change-in-game-state {:req (req (some #(and (program? %) + (runner-can-pay-and-install? + state side + (assoc eid :source card :source-type :runner-install) % + {:no-toast true})) + (:discard runner)))} :choices {:req (req (and (program? target) (in-discard? target) (can-pay? state side (assoc eid :source card :source-type :runner-install) target nil @@ -749,7 +776,7 @@ :data {:counter {:power 4}} :abilities [{:action true :cost [(->c :click 1) (->c :power 1)] - :req (req (not run)) + :change-in-game-state {:req (req (seq runnable-servers))} :prompt "Choose a server" :choices (req runnable-servers) :msg "make a run and avoid all tags for the remainder of the run" @@ -894,16 +921,16 @@ :cost [(->c :trash-can)] :effect (req (swap! state assoc-in [:trace :force-base] 0))}}}] :abilities [{:label "Jack out" - :req (req (and (or run - (get-current-encounter state)) - (= :runner (:active-player @state)))) + :change-in-game-state {:req (req (and (or run + (get-current-encounter state))))} + :req (req (= :runner (:active-player @state))) :msg "jack out" :cost [(->c :trash-can)] :async true :effect (effect (jack-out eid))} {:label "Remove 1 tag" - :req (req (and (pos? (count-real-tags state)) - (= :runner (:active-player @state)))) + :change-in-game-state {:req (req (pos? (count-real-tags state)))} + :req (req (= :runner (:active-player @state))) :msg "remove 1 tag" :cost [(->c :trash-can)] :async true @@ -920,6 +947,7 @@ :effect (effect (tag-prevent :runner eid 1))} {:msg "remove 1 tag" :label "Remove 1 tag" + :change-in-game-state {:req (req (pos? (count-real-tags state)))} :cost [(->c :trash-can)] :async true :effect (effect (lose-tags eid 1))}]}) @@ -1005,6 +1033,7 @@ (shuffle-next set-aside-cards target to-shuffle) card nil)))}))] {:abilities [{:label "Install a card from among the top 6 cards of the stack" + :change-in-game-state {:req (req (seq (:deck runner)))} :cost [(->c :trash-can)] :async true :waiting-prompt true @@ -1811,7 +1840,7 @@ {:label "Reveal and install top card of the stack" :once :per-turn :cost [(->c :credit 1)] - :req (req (pos? (count (:deck runner)))) + :change-in-game-state {:req (req (pos? (count (:deck runner))))} :msg (msg "reveal " (:title (first (:deck runner))) " from the top of the stack") :async true :effect @@ -2169,13 +2198,13 @@ :value [(->c :program 1)]}] :abilities [{:async true :label "Install a program from the heap" - :req (req (some #(and (program? %) - (runner-can-pay-and-install? - state side - (assoc eid :source card :source-type :runner-install) - % {:cost-bonus -3 - :no-toast true})) - (:discard runner))) + :change-in-game-state {:req (req (some #(and (program? %) + (runner-can-pay-and-install? + state side + (assoc eid :source card :source-type :runner-install) + % {:cost-bonus -3 + :no-toast true})) + (:discard runner)))} :cost [(->c :trash-can)] :effect (effect @@ -2248,6 +2277,7 @@ {:static-abilities [(link+ 1)] :abilities [{:label "Draw 3 cards" :msg "draw 3 cards" + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :cost [(->c :trash-can)] :effect (effect (draw :runner eid 3))}]}) @@ -2255,6 +2285,7 @@ (defcard "Spy Camera" {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :label "Look at the top X cards of the stack" :msg "look at the top X cards of the stack and rearrange them" @@ -2385,6 +2416,7 @@ card nil) (install-choice state side eid card rev-str first-card nil))))] {:abilities [{:cost [(->c :trash-can)] + :change-in-game-state {:req (req (seq (:deck runner)))} :label "Set aside cards from the top of the stack" :prompt "Choose a card type" :waiting-prompt true @@ -2568,6 +2600,7 @@ (defcard "Window" {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (seq (:deck runner)))} :keep-menu-open :while-clicks-left :msg "draw 1 card from the bottom of the stack" :effect (effect (move (last (:deck runner)) :hand))}]}) diff --git a/src/clj/game/cards/ice.clj b/src/clj/game/cards/ice.clj index 62d40188af..284c441812 100644 --- a/src/clj/game/cards/ice.clj +++ b/src/clj/game/cards/ice.clj @@ -152,13 +152,15 @@ (def end-the-run-if-tagged "ETR subroutine if tagged" {:label "End the run if the Runner is tagged" - :change-in-game-state (req tagged) + :change-in-game-state {:req (req tagged) :silent true} :msg "end the run" :async true :effect (effect (end-run :corp eid card))}) -;; helper for the faceup-archives-count cards -(defn- faceup-archives-types [corp] + +(defn- faceup-archives-types + "helper for the faceup-archives-count cards" + [corp] (count (distinct (map :type (filter faceup? (:discard corp)))))) (defn maybe-draw-sub @@ -251,6 +253,7 @@ "Places 1 power counter on a card." {:label "Place 1 power counter" :msg "place 1 power counter on itself" + :change-in-game-state {:silent (req true) :req (req (installed? card))} :async true :effect (req (add-counter state side eid card :power 1 {:placed true}))}) @@ -314,6 +317,7 @@ (def runner-loses-click ; Runner loses a click effect {:label "Force the Runner to lose [Click]" + :change-in-game-state {:silent (req true) :req (req (pos? (:click runner)))} :msg "force the Runner to lose [Click], if able" :effect (effect (lose-clicks :runner 1))}) @@ -322,13 +326,14 @@ [credits] {:label (str "Make the Runner lose " credits " [Credits]") :msg (str "force the Runner to lose " credits " [Credits]") + :change-in-game-state {:silent (req true) :req (req (pos? (:credit runner)))} :async true :effect (effect (lose-credits :runner eid credits))}) (def add-runner-card-to-grip "Add 1 installed Runner card to the grip" {:label "Add an installed Runner card to the grip" - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:silent true :req (req (seq (all-installed state :runner)))} :waiting-prompt true :prompt "Choose a card" :choices {:card #(and (installed? %) @@ -343,7 +348,7 @@ :label "Trash a program" :msg (msg "trash " (:title target)) :waiting-prompt true - :change-in-game-state (req (seq (filter program? (all-installed state :runner)))) + :change-in-game-state {:silent true :req (req (seq (filter program? (all-installed state :runner))))} :choices {:card #(and (installed? %) (program? %))} :async true @@ -356,7 +361,7 @@ :msg (msg "force the runner to trash " (:title target)) :display-side :corp :waiting-prompt true - :change-in-game-state (req (seq (filter program? (all-installed state :runner)))) + :change-in-game-state {:silent true :req (req (seq (filter program? (all-installed state :runner))))} :choices {:card #(and (installed? %) (program? %))} :async true @@ -370,7 +375,7 @@ :choices {:card #(and (installed? %) (hardware? %))} :waiting-prompt true - :change-in-game-state (req (seq (filter hardware? (all-installed state :runner)))) + :change-in-game-state {:silent true :req (req (seq (filter hardware? (all-installed state :runner))))} :async true :effect (effect (trash eid target {:cause :subroutine}))}) @@ -381,7 +386,7 @@ :choices {:card #(and (installed? %) (resource? %))} :waiting-prompt true - :change-in-game-state (req (seq (filter resource? (all-installed state :runner)))) + :change-in-game-state {:silent true :req (req (seq (filter resource? (all-installed state :runner))))} :async true :effect (effect (trash eid target {:cause :subroutine}))}) @@ -391,7 +396,7 @@ :label "Trash an installed Runner card" :msg (msg "trash " (:title target)) :waiting-prompt true - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:silent true :req (req (seq (all-installed state :runner)))} :choices {:card #(and (installed? %) (runner? %))} :effect (effect (trash eid target {:cause :subroutine}))}) @@ -479,6 +484,7 @@ :choices {:max 2 :card grail-in-hand} :async true + :change-in-game-state {:silent true :req (req (seq (:hand corp)))} :effect (effect (reveal eid targets)) :msg (let [sub-label #(:label (first (:subroutines (card-def %))))] (msg "reveal " (enumerate-str (map #(str (:title %) " (" (sub-label %) ")") targets))))}) @@ -590,9 +596,11 @@ ([pred label] (let [pred #(and (ice? %) (rezzed? %) + (>= (count (:subroutines %)) 1) (pred %))] {:async true :label label + :change-in-game-state {:silent (req true) :req (req (some pred (all-installed state :corp)))} :effect (effect (continue-ability @@ -608,7 +616,7 @@ :prompt "Choose the subroutine" :choices (req (unbroken-subroutines-choice ice)) :msg (msg "resolve the subroutine (\"[subroutine] " - target "\") from " (:title ice)) + target "\") from " (:title ice)) :effect (req (let [sub (first (filter #(= target (make-label (:sub-effect %))) (:subroutines ice)))] (continue-ability state side (:sub-effect sub) ice nil)))}) card nil))}) @@ -689,7 +697,7 @@ :duration :end-of-encounter}))}}})] {:on-encounter (encounter-ab) :subroutines [(corps-gains-and-runner-loses-credits 1 1) - runner-trash-installed-sub]})) + runner-trash-installed-sub]})) (defcard "Afshar" (let [breakable-fn (req (if (and (= :hq (second (get-zone card))) @@ -762,6 +770,7 @@ (effect-completed state side eid)))))} :no-ability {:effect (effect (system-msg :runner "does not draw 1 card"))}}}] {:subroutines [{:msg "rearrange the top 5 cards of R&D" + :change-in-game-state {:silent (req true) :req (req (seq (:deck corp)))} :async true :waiting-prompt true :effect (req (let [from (take 5 (:deck corp))] @@ -807,6 +816,7 @@ (defcard "Architect" {:flags {:untrashable-while-rezzed true} :subroutines [{:async true + :change-in-game-state {:silent (req true) :req (req (seq (:deck corp)))} :label "Look at the top 5 cards of R&D" :msg "look at the top 5 cards of R&D" :prompt (msg "The top cards of R&D are (top->bottom) " (enumerate-str (map :title (take 5 (:deck corp))))) @@ -842,9 +852,6 @@ (space-ice end-the-run)) (defcard "Attini" - ;; TODO - this should provide an aura that prevents the runner from paying credits - ;; for paid abilities during subroutine resolution - ;; we can figure out how to do that type of thing some time in the future (let [sub {:label "Do 1 net damage unless the Runner pays 2 [Credits]" :async true :effect (req (if (and (threat-level 3 state) @@ -995,6 +1002,7 @@ (defcard "Bloom" {:subroutines [{:label "Install a piece of ice from HQ protecting another server, ignoring all costs" + :change-in-game-state {:silent (req true) :req (req (seq (:hand corp)))} :prompt "Choose a piece of ice to install from HQ in another server" :async true :choices {:card #(and (ice? %) @@ -1010,6 +1018,7 @@ :display-origin true}}))} card nil)))} {:label "Install a piece of ice from HQ in the next innermost position, protecting this server, ignoring all costs" + :change-in-game-state {:silent (req true) :req (req (seq (:hand corp)))} :prompt "Choose a piece of ice to install from HQ in this server" :async true :choices {:card #(and (ice? %) @@ -1032,6 +1041,7 @@ {:abilities [{:label "End the run" :msg "end the run" :async true + :req (req this-server run) :cost [(->c :trash-can)] :effect (effect (end-run eid card))}] :subroutines [{:label "Gain 1 [Credits] for each ice protecting this server" @@ -1046,15 +1056,16 @@ (defcard "Boto" (let [discard-card-to-end-the-run-sub {:label "Trash 1 card from HQ to end the run" + :change-in-game-state {:silent (req true) :req (req (seq (:hand corp)))} :optional {:prompt "Trash 1 card from HQ to end the run?" :yes-ability {:cost [(->c :trash-from-hand 1)] :msg "end the run" :async true :effect (effect (end-run eid card))}}}] {:static-abilities [(ice-strength-bonus (req (if (threat-level 4 state) 2 0)))] - :subroutines [(do-net-damage 2) - discard-card-to-end-the-run-sub - discard-card-to-end-the-run-sub]})) + :subroutines [(do-net-damage 2) + discard-card-to-end-the-run-sub + discard-card-to-end-the-run-sub]})) (defcard "Brainstorm" {:on-encounter {:effect (effect (gain-variable-subs card (count (:hand runner)) (do-brain-damage 1)))} @@ -1105,6 +1116,7 @@ :player :corp :prompt "Choose a server" :choices (req servers) + :change-in-game-state {:silent true :req (req (installed? card))} :msg (msg "move itself to the outermost position of " target) :async true :effect (effect (move card (conj (server->zone state target) :ices)) @@ -1136,8 +1148,8 @@ {:static-abilities [(ice-strength-bonus (req (if (is-tagged? state) 2 0)))] :subroutines [{:label "Gain 1 [Credits] for each tag the Runner has" :async true + :change-in-game-state {:silent (req true) :req (req tagged)} :msg (msg "gain " (count-tags state) " [Credits]") - :req (req (pos? (count-tags state))) :effect (effect (gain-credits :corp eid (count-tags state)))} end-the-run]}) @@ -1302,6 +1314,11 @@ {:label "Trash 1 program (Trash 1 program and 1 resource)" :async true :msg (msg "trash 1 program" (when (wonder-sub card 3) " and 1 resource")) + :change-in-game-state {:silent (req true) + :req (req (or (some program? (all-installed state :runner)) + (and + (wonder-sub card 3) + (some resource? all-installed state :runner))))} :effect (req (wait-for (resolve-ability state side trash-program-sub card nil) (if (wonder-sub card 3) (continue-ability @@ -1339,12 +1356,16 @@ (defcard "Cortex Lock" {:subroutines [{:label "Do 1 net damage for each unused memory unit the Runner has" :msg (msg "do " (available-mu state) " net damage") + :change-in-game-state {:silent (req true) + :req (req (pos? (available-mu state)))} :async true :effect (effect (damage eid :net (available-mu state) {:card card}))}]}) (defcard "Crick" {:subroutines [{:label "install a card from Archives" :prompt "Choose a card to install from Archives" + :change-in-game-state {:silent (req true) + :req (req (seq (:discard corp)))} :show-discard true :async true :choices {:card #(and (corp-installable-type? %) @@ -1425,8 +1446,8 @@ {:subroutines [{:msg "do 1 net damage and trash itself" :async true :effect (req (wait-for (damage state :runner :net 1 {:card card}) - (trash state :corp (make-eid state eid) card {:cause :subroutine}) - (encounter-ends state side eid)))}]}) + (wait-for (trash state :corp card {:cause :subroutine}) + (encounter-ends state side eid))))}]}) (defcard "Data Raven" {:abilities [(power-counter-ability (give-tags 1))] @@ -1448,7 +1469,7 @@ :msg (msg "force the runner to " (decapitalize target) " on encountering it") :prompt "Choose one" :waiting-prompt true - :choices (req [(when (can-pay? state :runner eid card nil (->c :credit 3)) + :choices (req [(when (can-pay? state :runner eid card nil (->c :credit 3)) "Pay 3 [Credits]") "Take 1 tag"]) :async true @@ -1590,11 +1611,16 @@ (do-brain-damage 1) {:label "Trash a console" :prompt "Choose a console to trash" - :choices {:card #(has-subtype? % "Console")} + :change-in-game-state {:silent (req true) + :req (req (some #(has-subtype? % "Console") (all-installed state :runner)))} + :choices {:card #(and (has-subtype? % "Console") + (installed? %))} :msg (msg "trash " (:title target)) :async true :effect (effect (trash eid target {:cause :subroutine}))} {:msg "trash all virtual resources" + :change-in-game-state {:silent (req true) + :req (req (some #(and (has-subtype? % "Virtual") (resource? %)) (all-installed state :runner)))} :async true :effect (req (let [cards (filter #(has-subtype? % "Virtual") (all-active-installed state :runner))] (trash-cards state side eid cards {:cause :subroutine})))}] @@ -1603,6 +1629,8 @@ (defcard "Engram Flush" (let [sub {:async true :label "Reveal the grip" + :change-in-game-state {:silent (req true) + :req (req (:hand runner))} :msg (msg "reveal " (enumerate-str (map :title (:hand runner))) " from the grip") :effect (effect (reveal eid (:hand runner)))}] {:on-encounter {:prompt "Choose a card type" @@ -1656,6 +1684,7 @@ :req (req (same-card? card (:card context))) :effect subs-effect}] :subroutines [{:label "Trash this ice" + :change-in-game-state {:req (req (installed? card)) :silent true} :async true :msg (msg "trash " (:title card)) :effect (effect (trash eid card {:cause :subroutine}))}]})) @@ -1705,10 +1734,12 @@ :player :runner :prompt "Choose one" :waiting-prompt true + :change-in-game-state {:silent (req true) + :req (req (or (can-pay? state :runner eid card nil [(->c :credit 1)]) + (can-pay? state :runner eid card nil [(->c :trash-installed 1)])))} :choices (req [(when (can-pay? state :runner eid card nil [(->c :credit 1)]) "Pay 1 [Credits]") - (when (or (not (can-pay? state :runner eid card nil [(->c :credit 1)])) - (can-pay? state :runner eid card nil [(->c :trash-installed 1)])) + (when (can-pay? state :runner eid card nil [(->c :trash-installed 1)]) "Trash an installed card")]) :async true :effect (req (if (= target "Pay 1 [Credits]") @@ -1726,10 +1757,12 @@ :player :runner :prompt "Choose one" :waiting-prompt true + :change-in-game-state {:silent (req true) + :req (req (or (can-pay? state :runner eid card nil [(->c :credit 2)]) + (can-pay? state :runner eid card nil [(->c :trash-installed 1)])))} :choices (req [(when (can-pay? state :runner eid card nil [(->c :credit 2)]) "Pay 2 [Credits]") - (when (or (not (can-pay? state :runner eid card nil [(->c :credit 2)])) - (can-pay? state :runner eid card nil [(->c :trash-installed 1)])) + (when (can-pay? state :runner eid card nil [(->c :trash-installed 1)]) "Trash an installed card")]) :async true :effect (req (if (= target "Pay 2 [Credits]") @@ -1748,13 +1781,13 @@ :player :runner :prompt "Choose one" :waiting-prompt true + :change-in-game-state {:silent (req true) + :req (req (or (can-pay? state :runner eid card nil [(->c :credit 3)]) + (can-pay? state :runner eid card nil [(->c :trash-installed 1)])))} :choices (req [(when (can-pay? state :runner eid card nil [(->c :credit 3)]) "Pay 3 [Credits]") (when (can-pay? state :runner eid card nil [(->c :trash-installed 1)]) - "Trash an installed card") - (when (and (not (can-pay? state :runner eid card nil [(->c :trash-installed 1)])) - (not (can-pay? state :runner eid card nil [(->c :credit 3)]))) - "Done")]) + "Trash an installed card")]) :async true :effect (req (cond (= target "Pay 3 [Credits]") @@ -2031,6 +2064,8 @@ {:subroutines [{:label "Trash 1 program" :prompt "Choose a program that is not a decoder, fracter or killer" :msg (msg "trash " (:title target)) + :change-in-game-state {:silent (req true) + :req (req (some #(and (program? %) (not (has-any-subtype? % ["Decoder" "Fracter" "Killer"]))) (all-installed state :runner)))} :choices {:card #(and (installed? %) (program? %) (not (has-any-subtype? % ["Decoder" "Fracter" "Killer"])))} @@ -2043,7 +2078,9 @@ (defcard "Hailstorm" {:subroutines [{:label "Remove a card in the Heap from the game" - :req (req (not (zone-locked? state :runner :discard))) + :change-in-game-state {:silent true + :req (req (and (not (zone-locked? state :runner :discard)) + (seq (:discard runner))))} :prompt "Choose a card in the Heap" :choices (req (cancellable (:discard runner) :sorted)) :msg (msg "remove " (:title target) " from the game") @@ -2056,12 +2093,16 @@ {:label "Choose a resource or piece of hardware to trash" :msg (msg "trash " (:title target)) :prompt "Trash a resource or piece of hardware" + :change-in-game-state {:silent (req true) + :req (req (some #(or (hardware? %) (resource? %)) (all-installed state :runner)))} :choices {:req (req (and (installed? target) (or (hardware? target) (resource? target))))} :async true :effect (effect (trash eid target {:cause :subroutine}))} {:label "Choose a program to trash that is not a decoder, fracter or killer" + :change-in-game-state {:silent (req true) + :req (req (some #(and (program? %) (not (has-any-subtype? % ["Decoder" "Fracter" "Killer"]))) (all-installed state :runner)))} :prompt "Trash a program that is not a decoder, fracter or killer" :msg (msg "trash " (:title target)) :choices {:card #(and (installed? %) @@ -2218,6 +2259,8 @@ {:label "Trash an icebreaker" :prompt "Choose an icebreaker to trash" :msg (msg "trash " (:title target)) + :change-in-game-state {:silent (req true) + :req (req (some #(has-subtype? % "Icebreaker") (all-installed state :runner)))} :choices {:card #(and (installed? %) (has-subtype? % "Icebreaker"))} :async true @@ -2331,7 +2374,8 @@ (wall-ice [end-the-run])) (defcard "Ichi 1.0" - {:subroutines [trash-program-sub trash-program-sub + {:subroutines [trash-program-sub + trash-program-sub (trace-ability 1 {:label "Give the Runner 1 tag and do 1 core damage" :msg "give the Runner 1 tag and do 1 core damage" :async true @@ -2340,7 +2384,8 @@ :runner-abilities [(bioroid-break 1 1)]}) (defcard "Ichi 2.0" - {:subroutines [trash-program-sub trash-program-sub + {:subroutines [trash-program-sub + trash-program-sub (trace-ability 3 {:label "Give the Runner 1 tag and do 1 core damage" :msg "give the Runner 1 tag and do 1 core damage" :async true @@ -2351,6 +2396,7 @@ (defcard "Inazuma" {:subroutines [{:msg "prevent the Runner from breaking subroutines on the next piece of ice they encounter this run" + :change-in-game-state {:silent true :req (req run)} :effect (effect (register-events card @@ -2366,6 +2412,7 @@ :req (req (same-card? encountered-ice (:ice context))) :value true})))}]))} {:msg "prevent the Runner from jacking out until after the next piece of ice" + :change-in-game-state {:silent true :req (req run)} :effect (req (prevent-jack-out state side) (register-events @@ -2469,7 +2516,7 @@ card nil))} :subroutines [(give-tags 1) {:label "Do 1 core damage if the Runner is tagged" - :req (req tagged) + :change-in-game-state {:silent true :req (req tagged)} :msg "do 1 core damage" :async true :effect (req (damage state side eid :brain 1 {:card card}))}]}) @@ -2485,7 +2532,7 @@ {:on-encounter {:msg "prevent the Runner from installing cards for the rest of the turn" :effect (effect (register-turn-flag! card :runner-lock-install (constantly true)))} :subroutines [{:label "Choose 2 installed Runner cards, if able. The Runner must add 1 of those to the top of the Stack" - :req (req (>= (count (all-installed state :runner)) 2)) + :change-in-game-state {:silent (req true) :req (req (>= (count (all-installed state :runner)) 2))} :async true :prompt "Choose 2 installed Runner cards" :choices {:card #(and (runner? %) @@ -2786,7 +2833,10 @@ :effect (effect (derez :corp card {:source-card card}))}] :subroutines [{:label "(Code Gate) Force the Runner to lose [Click] and 1 [Credit]" :msg "force the Runner to lose [Click] and 1 [Credit]" - :req (req (has-subtype? card "Code Gate")) + :change-in-game-state {:silent true + :req (req (and (has-subtype? card "Code Gate") + (or (pos? (:credit runner)) + (pos? (:click runner)))))} :async true :effect (req (wait-for (lose-credits state :runner 1) @@ -2794,7 +2844,9 @@ (effect-completed state side eid)))} {:label "(Sentry) Trash a program" :prompt "Choose a program to trash" - :req (req (has-subtype? card "Sentry")) + :change-in-game-state {:silent true + :req (req (and (has-subtype? card "Sentry") + (some program? (all-installed state :runner))))} :msg (msg "trash " (:title target)) :choices {:card #(and (installed? %) (program? %))} @@ -2802,7 +2854,7 @@ :effect (effect (trash eid target {:cause :subroutine}))} {:label "(Barrier) Gain 1 [Credit] and end the run" :msg "gain 1 [Credit] and end the run" - :req (req (has-subtype? card "Barrier")) + :change-in-game-state {:silent true :req (req (has-subtype? card "Barrier"))} :async true :effect (req (wait-for (gain-credits state :corp 1) @@ -2890,7 +2942,7 @@ :subroutines [end-the-run]}) (defcard "Mamba" - {:abilities [(power-counter-ability (do-net-damage 1))] + {:abilities [(power-counter-ability (assoc (do-net-damage 1) :req (req run)))] :subroutines [(do-net-damage 1) (do-psi gain-power-counter)]}) @@ -3076,6 +3128,7 @@ :choices {:card #(and (ice? %) (in-hand? %))} :prompt "Choose a piece of ice to install from HQ" + :change-in-game-state {:req (req (seq (:hand corp))) :silent true} :label "install ice from HQ, ignoring all costs" :effect (effect (corp-install eid target (zone->name (target-server run)) {:ignore-all-cost true :msg-keys {:install-source card @@ -3228,6 +3281,8 @@ (do-brain-damage 1) {:prompt "Choose a card to trash" :label "Trash 1 installed Runner card" + :change-in-game-state {:silent true + :req (req (seq (all-installed state :runner)))} :msg (msg "trash " (:title target)) :choices {:card #(and (installed? %) (runner? %))} @@ -3254,7 +3309,8 @@ (defcard "NEXT Opal" (let [sub {:label "Install a card from HQ, paying all costs" :prompt "Choose a card in HQ to install" - :req (req (some #(corp-installable-type? %) (:hand corp))) + :change-in-game-state {:silent true + :req (req (seq (:hand corp)))} :choices {:card #(and (corp-installable-type? %) (in-hand? %))} :async true @@ -3374,6 +3430,8 @@ (defcard "Owl" {:subroutines [{:choices {:card #(and (installed? %) (program? %))} + :change-in-game-state {:silent true + :req (req (some program? (all-installed state :runner)))} :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}) @@ -3445,7 +3503,8 @@ (do-net-damage 1) (assoc end-the-run :label "End the run if there are more cards in HQ than in the grip" - :req (req (> (count (:hand corp)) (count (:hand runner)))))]}) + :change-in-game-state {:silent true + :req (req (> (count (:hand corp)) (count (:hand runner))))})]}) (defcard "Pop-up Window" {:on-encounter (gain-credits-sub 1) @@ -3515,10 +3574,7 @@ (defcard "Rime" {:implementation "Can be rezzed anytime already" :on-rez {:effect (effect (update-all-ice))} - :subroutines [{:label "Runner loses 1 [Credit]" - :msg "force the Runner to lose 1 [Credit]" - :async true - :effect (effect (lose-credits :runner eid 1))}] + :subroutines [(runner-loses-credits 1)] :static-abilities [{:type :ice-strength :req (req (protecting-same-server? card target)) :value 1}]}) @@ -3550,7 +3606,7 @@ :effect (effect (draw eid 1)) :msg "draw 1 card"}}}] {:subroutines [{:label "Look at the top 3 cards of R&D" - :req (req (not-empty (:deck corp))) + :change-in-game-state {:silent true :req (req (not-empty (:deck corp)))} :async true :effect (effect (continue-ability @@ -3643,6 +3699,7 @@ :prompt "Choose another server and redirect the run to its outermost position" :choices (req (remove #{(zone->name (:server (:run @state)))} (cancellable servers))) :msg (msg "move itself and the run on " target " and trash itself") + :change-in-game-state {:silent true :req (req (installed? card))} :effect (req (let [moved-ice (move state side card (conj (server->zone state target) :ices))] (redirect-run state side target) (wait-for (trash state side (make-eid state eid) moved-ice {:unpreventable true :cause :subroutine}) @@ -3767,6 +3824,7 @@ (defcard "Shiro" {:subroutines [{:label "Rearrange the top 3 cards of R&D" :msg "rearrange the top 3 cards of R&D" + :change-in-game-state {:silent true :req (req (seq (:deck corp)))} :async true :waiting-prompt true :effect (effect (continue-ability @@ -3853,6 +3911,7 @@ :async true :effect (effect (reveal eid (:hand runner)))} :abilities [{:req (req (pos? (get-counters card :power))) + :change-in-game-state {:req (req (seq (:hand runner)))} :cost [(->c :power 1)] :label "Reveal all cards in the grip and trash 1 card" :async true @@ -3886,17 +3945,17 @@ (req (update! state side (dissoc-in card [:special :sorocaban-blade])))}] :subroutines [trash-resource-sub (assoc trash-hardware-sub - :req (req (not (get-in card [:special :sorocaban-blade])))) + :change-in-game-state {:silent true :req (req (not (get-in card [:special :sorocaban-blade])))}) (assoc trash-program-sub - :req (req (not (get-in card [:special :sorocaban-blade]))))]}) + :change-in-game-state {:silent true :req (req (not (get-in card [:special :sorocaban-blade])))})]}) (defcard "Special Offer" {:subroutines [{:label "Gain 5 [Credits] and trash this ice" :msg "gain 5 [Credits] and trash itself" :async true :effect (req (wait-for (gain-credits state :corp 5) - (trash state :corp (make-eid state eid) card {:cause :subroutine}) - (encounter-ends state side eid)))}]}) + (wait-for (trash state :corp card {:cause :subroutine}) + (encounter-ends state side eid))))}]}) (defcard "Spiderweb" {:subroutines [end-the-run @@ -3948,6 +4007,7 @@ (defcard "Susanoo-no-Mikoto" {:subroutines [{:async true + :change-in-game-state {:silent true :req (req (not= (:server run) [:discard]))} :req (req (not= (:server run) [:discard])) :msg "make the Runner continue the run on Archives" :effect (req (if run @@ -3997,6 +4057,7 @@ :prompt "Choose an AI program to trash" :msg (msg "trash " (:title target)) :label "Trash an AI program" + :change-in-game-state {:silent true :req (req (some #(and (installed? %) (program? %) (has-subtype? % "AI")) (all-installed state :runner)))} :choices {:card #(and (installed? %) (program? %) (has-subtype? % "AI"))} @@ -4168,13 +4229,7 @@ (defcard "Trebuchet" {:on-rez take-bad-pub - :subroutines [{:prompt "Choose a card to trash" - :label "Trash 1 installed Runner card" - :msg (msg "trash " (:title target)) - :choices {:card #(and (installed? %) - (runner? %))} - :async true - :effect (req (trash state side eid target {:cause :subroutine}))} + :subroutines [trash-installed-sub (trace-ability 6 cannot-steal-or-trash-sub)]}) (defcard "Tree Line" @@ -4284,9 +4339,7 @@ :subroutines [(end-the-run-unless-runner-pays (->c :click 3))]}) (defcard "Turnpike" - {:on-encounter {:msg "force the Runner to lose 1 [Credits]" - :async true - :effect (effect (lose-credits :runner eid 1))} + {:on-encounter (runner-loses-credits 1) :subroutines [(tag-trace 5)]}) (defcard "Týr" @@ -4358,7 +4411,7 @@ (runner-loses-credits 2) (assoc end-the-run :label "End the run if you have more credits than the Runner" - :req (req (> (:credit corp) (:credit runner))))]}) + :change-in-game-state {:silent true :req (req (> (:credit corp) (:credit runner)))})]}) (defcard "Vampyronassa" {:subroutines [(runner-loses-credits 2) @@ -4389,14 +4442,8 @@ :subroutines [(give-tags 1)]}) (defcard "Veritas" - {:subroutines [{:label "Corp gains 2 [Credits]" - :msg "gain 2 [Credits]" - :async true - :effect (effect (gain-credits :corp eid 2))} - {:label "Runner loses 2 [Credits]" - :msg "force the Runner to lose 2 [Credits]" - :async true - :effect (effect (lose-credits :runner eid 2))} + {:subroutines [(gain-credits-sub 2) + (runner-loses-credits 2) (trace-ability 2 (give-tags 1))]}) (defcard "Vikram 1.0" @@ -4460,7 +4507,8 @@ :prompt "Choose a card to add to HQ" :msg "add a card from R&D to HQ" :choices (req (cancellable (:deck corp) :sorted)) - :cancel-effect (effect (system-msg "cancels the effect of Watchtower") + :cancel-effect (effect (system-msg "shuffles R&D") + (shuffle! :deck) (effect-completed eid)) :effect (effect (shuffle! :deck) (move target :hand))}]}) @@ -4490,14 +4538,15 @@ (defcard "Weir" {:subroutines [runner-loses-click {:label "Runner trashes 1 card from the grip" - :req (req (pos? (count (:hand runner)))) + :change-in-game-state {:req (req (pos? (count (:hand runner)))) :silent true} :prompt "Choose a card to trash" :player :runner :choices (req (:hand runner)) :not-distinct true + :display-side :corp + :msg (msg "force the Runner to trash " (:title target) " from [their] grip") :async true - :effect (effect (system-msg :runner (str "trashes " (:title target) " from the grip")) - (trash :runner eid target {:cause :subroutine}))}]}) + :effect (effect (trash :runner eid target {:cause :subroutine}))}]}) (defcard "Wendigo" (implementation-note @@ -4510,13 +4559,13 @@ :msg "prevent the Runner from jacking out and trash itself" :async true :effect (req (prevent-jack-out state side) - (wait-for (trash state :corp (make-eid state eid) card {:cause :subroutine}) + (wait-for (trash state :corp card {:cause :subroutine}) (encounter-ends state side eid)))}]}) (defcard "Whitespace" {:subroutines [(runner-loses-credits 3) {:label "End the run if the Runner has 6 [Credits] or less" - :req (req (< (:credit runner) 7)) + :change-in-game-state {:req (req (< (:credit runner) 7)) :silent true} :msg "end the run" :async true :effect (effect (end-run :corp eid card))}]}) @@ -4556,6 +4605,7 @@ (defcard "Yagura" {:subroutines [{:label "Look at the top card of R&D" + :change-in-game-state {:silent true :req (req (seq (:deck corp)))} :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))} diff --git a/src/clj/game/cards/identities.clj b/src/clj/game/cards/identities.clj index eac326e05f..7435c6110f 100644 --- a/src/clj/game/cards/identities.clj +++ b/src/clj/game/cards/identities.clj @@ -282,6 +282,11 @@ :async true :effect (effect (trash :corp eid target nil))}]}) + +(defcard "Ampère: Cybernetics For Anyone" + ;; No special implementation + {}) + (defcard "Andromeda: Dispossessed Ristie" {:events [{:event :pre-start-game :req (req (= side :runner)) @@ -618,6 +623,7 @@ (assoc ability :event :agenda-stolen :req (req true))] :abilities [{:action true :label "Look at the top 3 cards of R&D" + :change-in-game-state {:req (req (seq (:deck corp)))} :cost [(->c :click 1) (->c :power 1)] :msg "look at the top 3 cards of R&D" :async true @@ -1124,6 +1130,7 @@ :label "Install a non-virus program from the stack, lowering the cost by 1 [Credit]" :cost [(->c :click 1)] :prompt "Choose a program" + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (cancellable (filter #(and (program? %) (not (has-subtype? % "Virus")) @@ -1750,6 +1757,7 @@ :once :per-turn :makes-run true :async true + :change-in-game-state {:req (req archives-runnable)} :effect (effect (update! (assoc-in card [:special :omar-run] true)) (make-run eid :archives (get-card state card)))}] :events [{:event :pre-successful-run @@ -1764,12 +1772,8 @@ {:event :run-ends :effect (effect (update! (dissoc-in card [:special :omar-run])))}]}) -(defcard "Ampère: Cybernetics For Anyone" - ;; No special implementation - {}) - (defcard "Nova Initiumia: Catalyst & Impetus" - ;; No special implementation + ;; No special implementation {}) (defcard "Pālanā Foods: Sustainable Growth" @@ -1863,6 +1867,7 @@ :async true :label "Install a card from HQ" :cost [(->c :click 1) (->c :credit 1)] + :change-in-game-state {:req (req (seq (:hand corp)))} :prompt "Choose a card to install from HQ" :choices {:card #(and (or (asset? %) (agenda? %) (upgrade? %)) (corp? %) diff --git a/src/clj/game/cards/operations.clj b/src/clj/game/cards/operations.clj index 9f37a15269..5ba3d1b8d0 100644 --- a/src/clj/game/cards/operations.clj +++ b/src/clj/game/cards/operations.clj @@ -79,7 +79,7 @@ {:on-play {:additional-cost [(->c :forfeit)] :async true - :change-in-game-state (req (pos? (count (:scored corp)))) + :change-in-game-state {:req (req (pos? (count (:scored corp))))} :effect (req (continue-ability state side {:prompt "Choose an agenda in your score area" @@ -129,7 +129,7 @@ :async true :effect (req (trash-cards state side eid remaining-cards {:unpreventable true :cause-card card}))})))] {:prompt (msg "The top cards of R&D are (top->bottom): " (enumerate-str (map :title (take 3 (:deck corp))))) - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :choices ["OK"] :async true :effect (req (continue-ability @@ -189,7 +189,7 @@ (defcard "Aggressive Negotiation" {:on-play {:req (req (:scored-agenda corp-reg)) - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :prompt "Choose a card" :choices (req (cancellable (:deck corp) :sorted)) :msg "search R&D for a card and add it to HQ" @@ -237,8 +237,8 @@ (defcard "Ark Lockdown" {:on-play - {:change-in-game-state (req (and (not-empty (:discard runner)) - (not (zone-locked? state :runner :discard)))) + {:change-in-game-state {:req (req (and (not-empty (:discard runner)) + (not (zone-locked? state :runner :discard))))} :prompt "Name a card to remove all copies in the Heap from the game" :choices (req (cancellable (:discard runner) :sorted)) :msg (msg "remove all copies of " (:title target) " in the Heap from the game") @@ -316,9 +316,9 @@ {:prompt "Choose an installed card in a server to trash" :choices {:card #(and (= (last (get-zone %)) :content) (is-remote? (second (get-zone %))))} - :change-in-game-state (req (some #(and (= (last (get-zone %)) :content) - (is-remote? (second (get-zone %)))) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (= (last (get-zone %)) :content) + (is-remote? (second (get-zone %)))) + (all-installed state :corp)))} :msg (msg "trash " (card-str state target) " and gain " (* 3 (get-counters target :advancement)) " [Credits]") :async true @@ -352,11 +352,11 @@ (installed? target) (not (facedown? target)) (<= (:cost target) (count-tags state))))} - :change-in-game-state (req (some #(and (runner? %) - (installed? %) - (not (facedown? %)) - (<= (:cost %) (count-tags state))) - (all-installed state :runner))) + :change-in-game-state {:req (req (some #(and (runner? %) + (installed? %) + (not (facedown? %)) + (<= (:cost %) (count-tags state))) + (all-installed state :runner)))} :msg (msg "trash " (:title target)) :async true :effect (effect (trash eid target {:cause-card card}))}}) @@ -414,7 +414,7 @@ :choices {:card #(and (corp? %) (installed? %))} :msg (msg "place 4 advancement counters on " (card-str state target)) - :change-in-game-state (req (seq (all-installed state :corp))) + :change-in-game-state {:req (req (seq (all-installed state :corp)))} :effect (req (wait-for (add-prop state :corp target :advance-counter 4 {:placed true}) (let [card-to-score target] (continue-ability @@ -432,12 +432,12 @@ (has-subtype? % "Bioroid") (installed? %) (not (rezzed? %)))} - :change-in-game-state (req (some #(and (ice? %) - (not (rezzed? %))) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (ice? %) + (not (rezzed? %))) + (all-installed state :corp)))} :msg (msg "rez " (card-str state target {:visible true}) " at no cost") :async true - :cancel-effect (req (do-nothing state side eid card)) + :cancel-effect (req (do-nothing state side eid nil card)) :effect (req (wait-for (rez state side target {:ignore-cost :all-costs}) (install-as-condition-counter state side eid card (:card async-result))))} :events [{:event :end-of-encounter @@ -508,7 +508,7 @@ (has-subtype? % "Barrier") (in-hand? %))} :async true - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :effect (req (wait-for (reveal-loud state side card nil target) (corp-install state side eid target nil {:ignore-all-cost true @@ -535,8 +535,8 @@ (add-prop state :corp eid f1 :advance-counter 1 {:placed true}))))}] {:on-play (choose-one-helper {:optional :after-first - :change-in-game-state (req (or (something-can-be-advanced? state) - (some #(pos? (get-counters % :virus)) (all-installed state :runner)))) + :change-in-game-state {:req (req (or (something-can-be-advanced? state) + (some #(pos? (get-counters % :virus)) (all-installed state :runner))))} :count (req (if (threat-level 3 state) 2 1))} [{:option "Place 1 advancement counter on up to two cards you can advance" :ability kaguya} @@ -546,7 +546,7 @@ (defcard "Casting Call" {:on-play {:choices {:card #(and (agenda? %) (in-hand? %))} - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :async true :effect (req (wait-for (corp-install state side target nil {:install-state :face-up @@ -567,7 +567,7 @@ {:choices {:max 5 :card #(and (corp? %) (in-hand? %))} - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :msg (msg "reveal " (enumerate-str (map :title (sort-by :title targets))) " from HQ and gain " (* 2 (count targets)) " [Credits]") :async true :effect (req (wait-for @@ -601,7 +601,7 @@ (defcard "Closed Accounts" {:on-play {:req (req tagged) - :change-in-game-state (req (pos? (:credit runner))) + :change-in-game-state {:req (req (pos? (:credit runner)))} :msg (msg "force the Runner to lose all " (:credit runner) " [Credits]") :async true :effect (effect (lose-credits :runner eid :all))}}) @@ -609,8 +609,8 @@ (defcard "Commercialization" {:on-play {:msg (msg "gain " (get-counters target :advancement) " [Credits]") - :change-in-game-state (req (some #(and (ice? %) (pos? (get-counters % :advancement))) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (ice? %) (pos? (get-counters % :advancement))) + (all-installed state :corp)))} :choices {:card #(and (ice? %) (installed? %))} :async true @@ -644,7 +644,7 @@ (defcard "Consulting Visit" {:on-play {:prompt "Choose an Operation from R&D to play" - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :choices (req (cancellable (filter #(and (operation? %) (<= (:cost %) (:credit corp))) @@ -724,8 +724,8 @@ {:req (req (and (< 1 (:turn @state)) (not (some #{:hq} (:successful-run runner-reg-last))))) :prompt "Choose an Agenda" - :change-in-game-state (req (or (seq (:deck corp)) - (seq (:hand corp)))) + :change-in-game-state {:req (req (or (seq (:deck corp)) + (seq (:hand corp))))} :choices (req (conj (vec (filter agenda? (:deck corp))) "None")) :msg (msg (if (= "None" target) "shuffle R&D" @@ -814,7 +814,7 @@ {:on-play {:msg (msg "gain " (number-of-non-empty-remotes state) " [Credits]") - :change-in-game-state (req (pos? (number-of-non-empty-remotes state))) + :change-in-game-state {:req (req (pos? (number-of-non-empty-remotes state)))} :async true :effect (effect (gain-credits eid (number-of-non-empty-remotes state)))}})) @@ -824,7 +824,7 @@ :choices {:card #(and (installed? %) (rezzed? %)) :max (req (count (filter rezzed? (all-installed state :corp))))} - :change-in-game-state (req (seq (all-installed state :corp))) + :change-in-game-state {:req (req (seq (all-installed state :corp)))} :async true :effect (req (doseq [c targets] (derez state side c {:source-card card})) @@ -856,7 +856,7 @@ {:on-play {:choices {:card #(and (ice? %) (installed? %))} :msg (msg "give " (card-str state target {:visible false}) " additional text") - :change-in-game-state (req (some ice? (all-installed state :corp))) + :change-in-game-state {:req (req (some ice? (all-installed state :corp)))} :async true :effect (effect (install-as-condition-counter eid card target))} :events [{:event :encounter-ice @@ -871,7 +871,7 @@ {:on-play {:req (req (last-turn? state :runner :successful-run)) :async true - :change-in-game-state (req (>= (:credit runner) 4)) + :change-in-game-state {:req (req (>= (:credit runner) 4))} :msg "make the runner lose 4 [Credits]" :effect (effect (lose-credits :runner eid 4))}}) @@ -924,7 +924,7 @@ (defcard "Exchange of Information" {:on-play {:req (req tagged) - :change-in-game-state (req (and (seq (:scored runner)) (seq (:scored corp)))) + :change-in-game-state {:req (req (and (seq (:scored runner)) (seq (:scored corp))))} :prompt "Choose an agenda in the Runner's score area to swap" :choices {:req (req (in-runner-scored? state side target))} :async true @@ -963,7 +963,7 @@ {:x-fn (req (-> runner :scored count)) :on-play {:async true - :change-in-game-state (req (pos? ((get-x-fn) state side eid card targets))) + :change-in-game-state {:req (req (pos? ((get-x-fn) state side eid card targets)))} :msg (msg "gain " ((get-x-fn) state side eid card targets) " [Credits]") :effect (req (let [draw {:async true @@ -1001,7 +1001,7 @@ (defcard "Fast Track" {:on-play {:prompt "Choose an Agenda" - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :choices (req (cancellable (filter agenda? (:deck corp)) :sorted)) :async true :msg (msg "reveal " (:title target) " from R&D and add it to HQ") @@ -1016,7 +1016,7 @@ {:on-play {:optional {:req (req (<= 6 (:credit runner))) - :change-in-game-state (req (pos? (count-resources state))) + :change-in-game-state {:req (req (pos? (count-resources state)))} :player :runner :waiting-prompt true :prompt "Trash a resource?" @@ -1081,7 +1081,7 @@ (defcard "Freelancer" {:on-play {:req (req tagged) - :change-in-game-state (req (some resource? (all-installed state :runner))) + :change-in-game-state {:req (req (some resource? (all-installed state :runner)))} :msg (msg "trash " (enumerate-str (map :title (sort-by :title targets)))) :choices {:max 2 :card #(and (installed? %) @@ -1104,7 +1104,7 @@ (effect-completed state side eid))))})] {:on-play {:async true - :change-in-game-state (req (seq (:discard corp))) + :change-in-game-state {:req (req (seq (:discard corp)))} :effect (effect (continue-ability (fhelper 1) card nil))} })) (defcard "Fully Operational" @@ -1135,7 +1135,7 @@ (defcard "Game Changer" {:on-play {:rfg-instead-of-trashing true - :change-in-game-state (req (pos? (count (:scored runner)))) + :change-in-game-state {:req (req (pos? (count (:scored runner))))} :effect (effect (gain-clicks (count (:scored runner))))}}) (defcard "Game Over" @@ -1242,7 +1242,7 @@ {:on-play {:req (req (last-turn? state :runner :trashed-card)) :prompt "Choose an installed Corp card" - :change-in-game-state (req (seq (all-installed state :corp))) + :change-in-game-state {:req (req (seq (all-installed state :corp)))} :choices {:card #(and (corp? %) (installed? %))} :async true @@ -1406,7 +1406,7 @@ (defcard "Hunter Seeker" {:on-play {:req (req (last-turn? state :runner :stole-agenda)) - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:req (req (seq (all-installed state :runner)))} :prompt "Choose a card to trash" :choices {:card installed?} :msg (msg "trash " (card-str state target)) @@ -1438,8 +1438,8 @@ (defcard "Interns" {:on-play {:prompt "Choose a card to install from Archives or HQ" - :change-in-game-state (req (or (seq (:hand corp)) - (some #(or (not (operation? %)) (not (:seen %))) (:discard corp)))) + :change-in-game-state {:req (req (or (seq (:hand corp)) + (some #(or (not (operation? %)) (not (:seen %))) (:discard corp))))} :show-discard true :not-distinct true :choices {:card #(and (not (operation? %)) @@ -1569,7 +1569,7 @@ :choices {:max (req (count (filter #(not (agenda? %)) (all-active-installed state :corp)))) :card #(and (rezzed? %) (not (agenda? %)))} - :change-in-game-state (req (some rezzed? (all-installed state :corp))) + :change-in-game-state {:req (req (some rezzed? (all-installed state :corp)))} :msg (msg "trash " (enumerate-str (map :title targets)) " and gain " (* (count targets) 3) " [Credits]") :async true @@ -1587,7 +1587,7 @@ {:on-play {:prompt "Choose a card" :choices (req (cancellable (:deck corp) :sorted)) - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :async true :effect (effect (continue-ability @@ -1616,7 +1616,7 @@ (get-in @state [:runner :credit])))] {:on-play {:req (req tagged) - :change-in-game-state (req (pos? (:credit runner))) + :change-in-game-state {:req (req (pos? (:credit runner)))} :msg (msg (let [c (credit-diff state)] (str "make the runner lose " c " [Credits], and gain " c " [Credits]"))) :async true @@ -1628,15 +1628,15 @@ {:on-play {:msg (msg "gain " (* 2 (count (filter #(pos? (get-counters % :advancement)) (get-all-installed state)))) " [Credits]") - :change-in-game-state (req (pos? (count (filter #(pos? (get-counters % :advancement)) - (get-all-installed state))))) + :change-in-game-state {:req (req (pos? (count (filter #(pos? (get-counters % :advancement)) + (get-all-installed state)))))} :async true :effect (effect (gain-credits eid (* 2 (count (filter #(pos? (get-counters % :advancement)) (get-all-installed state))))))}}) (defcard "MCA Informant" {:on-play {:prompt "Choose a connection to host MCA Informant on" - :change-in-game-state (req (some #(has-subtype? % "Connection") (all-installed state :runner))) + :change-in-game-state {:req (req (some #(has-subtype? % "Connection") (all-installed state :runner)))} :choices {:card #(and (runner? %) (has-subtype? % "Connection") (installed? %))} @@ -1659,7 +1659,7 @@ {:prompt "Choose an agenda in the runner's score area" :choices {:req (req (and (agenda? target) (is-scored? state :runner target)))} - :change-in-game-state (req (seq (:scored runner))) + :change-in-game-state {:req (req (seq (:scored runner)))} :effect (req (update! state side (assoc card :title (:title target) :abilities (ability-init (card-def target)))) (card-init state side (get-card state card) {:resolve-effect false :init-data true}) (update! state side (assoc (get-card state card) :title "Media Blitz")))}}) @@ -1735,7 +1735,7 @@ (effect-completed state side eid)))))] {:on-play {:prompt "Choose 2 cards to install in new remote servers" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:card #(and (not (operation? %)) (corp? %) (in-hand? %)) @@ -1746,7 +1746,7 @@ (defcard "Mushin No Shin" {:on-play {:prompt "Choose a card to install from HQ" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:card #(and (not (operation? %)) (corp? %) (in-hand? %))} @@ -1816,7 +1816,7 @@ {:on-play {:prompt "Choose any number of rezzed cards to trash" :interactive (req true) - :change-in-game-state (req (some rezzed? (all-installed state :corp))) + :change-in-game-state {:req (req (some rezzed? (all-installed state :corp)))} :choices {:max (req (count (filter #(not (agenda? %)) (all-active-installed state :corp)))) :card #(and (rezzed? %) (not (agenda? %)))} @@ -1842,7 +1842,7 @@ (defcard "Neurospike" {:on-play {:msg (msg "do " (:scored-agenda corp-reg 0) " net damage") - :change-in-game-state (req (pos? (:scored-agenda corp-reg 0))) + :change-in-game-state {:req (req (pos? (:scored-agenda corp-reg 0)))} :async true :effect (effect (damage eid :net (:scored-agenda corp-reg 0) {:card card}))}}) @@ -1895,7 +1895,7 @@ {:additional-cost [(->c :tag 1)] :req (req (and (pos? (count-real-tags state)) (< (:credit runner) 6))) - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:req (req (seq (all-installed state :runner)))} :prompt "Choose an installed card to trash" :choices {:card #(and (runner? %) (installed? %))} @@ -1926,8 +1926,8 @@ {:on-play {:choices {:card #(and (ice? %) (not (rezzed? %)) (= (last (get-zone %)) :ices))} - :change-in-game-state (req (some (every-pred ice? (complement rezzed?)) - (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? (complement rezzed?)) + (all-installed state :corp)))} :msg (msg "rez " (card-str state target) " at no cost") :async true :effect (req (wait-for (rez state side target {:ignore-cost :all-costs :no-msg true}) @@ -1943,7 +1943,7 @@ (defcard "Patch" {:on-play {:choices {:card #(and (ice? %) (rezzed? %))} - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :msg (msg "give +2 strength to " (card-str state target)) :async true :effect (effect (install-as-condition-counter eid card target))} @@ -1963,7 +1963,7 @@ (+ c (count (filter (fn [ice] (:rezzed ice)) (:ices server))))) 0 (flatten (seq (:servers corp)))) " [Credits]") - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :async true :effect (effect (gain-credits eid @@ -1978,9 +1978,9 @@ :waiting-prompt true :msg (msg "reveal " (:title target) " from R&D and add it to HQ") :choices (req (sort-by :title (filter #(or (operation? %) (agenda? %)) (:deck corp)))) - :change-in-game-state (req (or (seq (:deck corp)) - (and (threat-level 3 state) - (seq (:hand corp))))) + :change-in-game-state {:req (req (or (seq (:deck corp)) + (and (threat-level 3 state) + (seq (:hand corp)))))} :async true :effect (req (wait-for (reveal state side target) (shuffle! state :corp :deck) @@ -2056,7 +2056,7 @@ (defcard "Precognition" {:on-play {:msg "rearrange the top 5 cards of R&D" - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :waiting-prompt true :async true :effect (effect (continue-ability @@ -2093,7 +2093,7 @@ (defcard "Preemptive Action" {:on-play {:rfg-instead-of-trashing true - :change-in-game-state (req (seq (:discard corp))) + :change-in-game-state {:req (req (seq (:discard corp)))} :async true :effect (effect (shuffle-into-rd-effect eid card 3 true))}}) @@ -2107,7 +2107,7 @@ :display-origin true}}))})] {:on-play {:prompt "Choose a piece of ice in HQ to install" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:card #(and (in-hand? %) (corp? %) (ice? %))} @@ -2119,8 +2119,8 @@ (defcard "Product Recall" {:on-play {:prompt "Choose a rezzed asset or upgrade to trash" - :change-in-game-state (req (some #(and (rezzed? %) (or (asset? %) (upgrade? %))) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (rezzed? %) (or (asset? %) (upgrade? %))) + (all-installed state :corp)))} :choices {:card #(and (rezzed? %) (or (asset? %) (upgrade? %)))} @@ -2145,7 +2145,7 @@ (continue-ability state side {:msg (msg "place " (quantify c " advancement token") " on " (card-str state target)) - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :choices {:req (req (can-be-advanced? state target))} :async true :effect (effect (add-prop eid target :advance-counter c {:placed true}))} @@ -2163,7 +2163,7 @@ :display-origin true}}))})] {:on-play {:async true - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :msg "look at the top 5 cards of R&D" :effect (effect @@ -2318,7 +2318,7 @@ {:on-play {:prompt "Choose an installed card that can be advanced" :choices {:req (req (can-be-advanced? state target))} - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :async true :effect (req (let [installed (get-all-installed state) total-adv (reduce + (map #(get-counters % :advancement) installed))] @@ -2400,7 +2400,7 @@ (defcard "Retribution" {:on-play {:req (req tagged) - :change-in-game-state (req (some #(or (program? %) (hardware? %)) (all-installed state :runner))) + :change-in-game-state {:req (req (some #(or (program? %) (hardware? %)) (all-installed state :runner)))} :prompt "Choose a program or piece of hardware to trash" :choices {:req (req (and (installed? target) (or (program? target) @@ -2412,7 +2412,7 @@ (defcard "Reuse" {:on-play {:prompt (msg "Choose up to " (quantify (count (:hand corp)) "card") " in HQ to trash") - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:max (req (count (:hand corp))) :card #(and (corp? %) (in-hand? %))} @@ -2452,7 +2452,7 @@ (defcard "Rework" {:on-play {:prompt "Choose a card from HQ to shuffle into R&D" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:card #(and (corp? %) (in-hand? %))} :msg "shuffle a card from HQ into R&D" @@ -2487,7 +2487,7 @@ (defcard "Rover Algorithm" {:on-play {:choices {:card #(and (ice? %) (rezzed? %))} - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :msg (msg "host itself as a condition counter on " (card-str state target)) :async true :effect (effect (install-as-condition-counter eid card target))} @@ -2505,7 +2505,7 @@ {:on-play {:additional-cost [(->c :forfeit)] :async true - :change-in-game-state (req (pos? (count-bad-pub state))) + :change-in-game-state {:req (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 @@ -2572,10 +2572,10 @@ (defcard "Seamless Launch" {:on-play {:prompt "Choose an installed card" - :change-in-game-state (req (some #(and (corp? %) - (installed? %) - (not= :this-turn (installed? %))) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (corp? %) + (installed? %) + (not= :this-turn (installed? %))) + (all-installed state :corp)))} :choices {:card #(and (corp? %) (installed? %) (not= :this-turn (installed? %)))} @@ -2586,7 +2586,7 @@ (defcard "Secure and Protect" {:on-play {:interactive (req true) - :change-in-game-state (req (seq (:deck corp))) + :change-in-game-state {:req (req (seq (:deck corp)))} :waiting-prompt true :async true :effect (req (if (seq (filter ice? (:deck corp))) @@ -2618,7 +2618,7 @@ {:on-play {:req (req tagged) :prompt "Choose 2 installed Runner cards" - :change-in-game-state (req (seq (all-installed state :runner))) + :change-in-game-state {:req (req (seq (all-installed state :runner)))} :choices {:card #(and (installed? %) (runner? %)) :max 2} @@ -2638,7 +2638,7 @@ :req (req (and (corp? target) (installed? target) (can-be-advanced? state target)))} - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :msg (msg "place 1 advancement token on " (quantify (count targets) "card")) :async true :effect (req (let [[f1 f2] targets] @@ -2660,14 +2660,14 @@ (continue-ability state side (shelper (inc n)) card nil)))}))] {:on-play {:async true - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :effect (effect (continue-ability (shelper 0) card nil))}})) (defcard "Shipment from SanSan" {:on-play {:choices ["0" "1" "2"] :prompt "How many advancement tokens do you want to place?" - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :async true :effect (req (let [c (str->int target)] (continue-ability @@ -2702,7 +2702,7 @@ {:on-play {:async true :req (req (<= 2 (count-tags state))) - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :effect (effect (continue-ability (ability 4) card nil))}})) (defcard "Shoot the Moon" @@ -2713,7 +2713,7 @@ (continue-ability state side (rez-helper (rest ice)) card nil)))}))] {:on-play {:req (req tagged) - :change-in-game-state (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? (complement rezzed?)) (all-installed state :corp)))} :choices {:card #(and (ice? %) (not (rezzed? %))) :max (req (min (count-tags state) @@ -2727,7 +2727,7 @@ {:on-play {:rfg-instead-of-trashing true :prompt "Choose up to 5 cards in HQ to trash" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :waiting-prompt true :choices {:max (req 5) :card #(and (corp? %) @@ -2780,7 +2780,7 @@ (defcard "Special Report" {:on-play {:prompt "Choose any number of cards in HQ to shuffle into R&D" - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :choices {:max (req (count (:hand corp))) :card #(and (corp? %) (in-hand? %))} @@ -2828,7 +2828,7 @@ (defcard "Stock Buy-Back" {:on-play {:msg (msg "gain " (* 3 (count (:scored runner))) " [Credits]") - :change-in-game-state (req (seq (:scored runner))) + :change-in-game-state {:req (req (seq (:scored runner)))} :async true :effect (effect (gain-credits eid (* 3 (count (:scored runner)))))}}) @@ -2870,7 +2870,7 @@ :effect (effect (end-run eid card))} :on-play {:choices {:card #(and (ice? %) (rezzed? %))} - :change-in-game-state (req (some (every-pred ice? rezzed?) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred ice? rezzed?) (all-installed state :corp)))} :msg (msg "make " (card-str state target) " gain Barrier and \"[Subroutine] End the run\"") :async true :effect (req (add-extra-sub! state :corp (get-card state target) new-sub (:cid card)) @@ -2899,7 +2899,7 @@ (effect-completed state side eid))))})] {:on-play {:req (req tagged) - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :async true :effect (effect (continue-ability (sc 1 card) card nil))}})) @@ -2936,7 +2936,7 @@ {:on-play {:additional-cost [(->c :forfeit)] :choices {:req (req (can-be-advanced? state target))} - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :msg (msg "advance " (card-str state target) " " (quantify (get-advancement-requirement (cost-target eid :forfeit)) "time")) :async true @@ -2983,7 +2983,7 @@ (defcard "Sweeps Week" {:on-play {:msg (msg "gain " (count (:hand runner)) " [Credits]") - :change-in-game-state (req (seq (:hand runner))) + :change-in-game-state {:req (req (seq (:hand runner)))} :async true :effect (effect (gain-credits eid (count (:hand runner))))}}) @@ -3023,7 +3023,7 @@ :effect (effect (trash-cards :corp eid (filter resource? (all-active-installed state :runner)) {:cause-card card}))}] {:on-play {:req (req tagged) - :change-in-game-state (req (some resource? (all-active-installed state :runner))) + :change-in-game-state {:req (req (some resource? (all-active-installed state :runner)))} :async true :effect (effect (continue-ability @@ -3100,7 +3100,7 @@ :on-play {:choices {:card #(and (agenda? %) (installed? %) (not (faceup? %)))} - :change-in-game-state (req (some (every-pred (complement faceup?) (complement ice?)) (all-installed state :corp))) + :change-in-game-state {:req (req (some (every-pred (complement faceup?) (complement ice?)) (all-installed state :corp)))} :async true :effect (req (let [target (update! state side (assoc target :seen true @@ -3122,7 +3122,7 @@ {:prompt "Choose an installed card you can advance" :choices {:req (req (and (can-be-advanced? state target) (installed? target)))} - :change-in-game-state (req (something-can-be-advanced? state)) + :change-in-game-state {:req (req (something-can-be-advanced? state))} :async true :effect (effect (continue-ability @@ -3181,8 +3181,8 @@ :install-state :rezzed-no-cost}))}] {:on-play {:req (req tagged) :msg (msg "trash " (:title target)) - :change-in-game-state (req (or (some resource? (all-active-installed state :runner)) - (some #(or (not (operation? %)) (not (:seen %))) (:discard corp)))) + :change-in-game-state {:req (req (or (some resource? (all-active-installed state :runner)) + (some #(or (not (operation? %)) (not (:seen %))) (:discard corp))))} :prompt "Choose a resource to trash" :choices {:card #(and (installed? %) (resource? %))} @@ -3252,9 +3252,9 @@ {:rfg-instead-of-trashing true :req (req (last-turn? state :runner :trashed-card)) :prompt "Choose a piece of hardware or non-virtual resource" - :change-in-game-state (req (some #(or (hardware? %) - (and (resource? %) (not (has-subtype? % "Virtual")))) - (all-active-installed state :runner))) + :change-in-game-state {:req (req (some #(or (hardware? %) + (and (resource? %) (not (has-subtype? % "Virtual")))) + (all-active-installed state :runner)))} :choices {:card #(or (hardware? %) (and (resource? %) (not (has-subtype? % "Virtual"))))} @@ -3284,8 +3284,8 @@ (rezzed? %))} :msg (msg "give " (card-str state target) " \"[Subroutine] Do 1 core damage\" before all its other subroutines") :async true - :change-in-game-state (req (some #(and (ice? %) (rezzed? %) (has-subtype? % "Bioroid")) - (all-installed state :corp))) + :change-in-game-state {:req (req (some #(and (ice? %) (rezzed? %) (has-subtype? % "Bioroid")) + (all-installed state :corp)))} :effect (req (add-extra-sub! state :corp target new-sub (:cid card) {:front true}) (install-as-condition-counter state side eid card (get-card state target)))} :sub-effect (do-brain-damage 1) @@ -3297,11 +3297,11 @@ (defcard "Witness Tampering" {:on-play {:msg "remove 2 bad publicity" - :change-in-game-state (req (pos? (count-bad-pub state))) + :change-in-game-state {:req (req (pos? (count-bad-pub state)))} :effect (effect (lose-bad-publicity 2))}}) (defcard "Your Digital Life" {:on-play {:msg (msg "gain " (count (:hand corp)) " [Credits]") - :change-in-game-state (req (seq (:hand corp))) + :change-in-game-state {:req (req (seq (:hand corp)))} :async true :effect (effect (gain-credits :corp eid (count (:hand corp))))}}) diff --git a/src/clj/game/cards/programs.clj b/src/clj/game/cards/programs.clj index 6744f82e73..4c8020b7ba 100644 --- a/src/clj/game/cards/programs.clj +++ b/src/clj/game/cards/programs.clj @@ -492,6 +492,7 @@ :msg "make a run on R&D" :makes-run true :async true + :change-in-game-state {:req (req rd-runnable)} :effect (effect (register-events card [ability]) (make-run eid :rd card))}]})) @@ -910,6 +911,7 @@ :msg "make a run on R&D" :makes-run true :async true + :change-in-game-state {:req (req rd-runnable)} :effect (req (make-run state side eid :rd card))} (set-autoresolve :auto-place-counter "Conduit placing virus counters on itself")]}) @@ -934,7 +936,7 @@ ab (if (= 1 amt-trashed) sing-ab mult-ab)] (continue-ability state side ab card targets)))}] :abilities [{:action true - :req (req (pos? (get-virus-counters state card))) + :change-in-game-state {:req (req (pos? (get-virus-counters state card)))} :cost [(->c :click 1)] :label "Gain 2 [Credits] for each hosted virus counter, then remove all virus counters" :async true @@ -1298,6 +1300,7 @@ :no-mu true :max-mu 3}] :abilities [{:action true + :change-in-game-state {:req (req (seq (:deck runner)))} :label "Search the stack for a virus program and add it to the grip" :prompt "Choose a Virus" :msg (msg "add " (:title target) " from the stack to the grip") @@ -1390,6 +1393,7 @@ :effect (effect (reveal eid (:hand corp)))}})] {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req hq-runnable)} :msg "make a run on HQ" :makes-run true :async true @@ -1484,7 +1488,7 @@ :async true :effect (effect (add-counter eid card :virus 1 nil))}] :abilities [{:action true - :req (req (pos? (get-virus-counters state card))) + :change-in-game-state {: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]")) @@ -1613,6 +1617,7 @@ :abilities [{:action true :async true :cost [(->c :click 1) (->c :virus 1)] + :change-in-game-state {:req (req (seq (:deck corp)))} :keep-menu-open :while-virus-tokens-left :msg "force the Corp to trash the top card of R&D" :effect (effect (mill :corp eid :corp 1))}]})) @@ -1705,7 +1710,7 @@ :abilities [{:action true :cost [(->c :click 1) (->c :virus 2)] :keep-menu-open :while-2-virus-tokens-left - :req (req (pos? (count (:hand corp)))) + :change-in-game-state {:req (req (seq (:hand corp)))} :msg "force the Corp to trash 1 card from HQ" :async true :effect (req (continue-ability @@ -1898,6 +1903,7 @@ (trash eid (assoc target :seen true) {:cause-card card}))}})] {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req rd-runnable)} :msg "make a run on R&D" :makes-run true :async true @@ -2992,7 +2998,8 @@ {:abilities [{:cost [(->c :credit 2)] :label "Install a program" :once :per-turn - :req (req (not (install-locked? state side))) + :change-in-game-state {:req (req (and (not (install-locked? state side)) + (seq (:hand runner))))} :prompt "Choose a program to install" :choices {:card #(and (program? %) (in-hand? %))} @@ -3011,8 +3018,7 @@ :effect (req (gain-credits state side eid 1))}]}) (defcard "Self-modifying Code" - {:abilities [{:req (req (not (install-locked? state side))) - :label "Install a program from the stack" + {:abilities [{:label "Install a program from the stack" :cost [(->c :trash-can) (->c :credit 2)] :async true :effect (effect @@ -3022,6 +3028,7 @@ (->> (:deck runner) (filter #(and (program? %) + (not (install-locked? state side)) (can-pay? state side (assoc eid :source card :source-type :runner-install) % nil [(->c :credit (install-cost state side %))]))) @@ -3063,6 +3070,7 @@ (defcard "Sneakdoor Beta" {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req archives-runnable)} :msg "make a run on Archives" :makes-run true :async true @@ -3183,6 +3191,7 @@ :once :per-turn :msg "make a run on R&D" :makes-run true + :change-in-game-state {:req (req rd-runnable)} :async true :effect (effect (register-events card [ability]) (make-run eid :rd card))}]})) @@ -3290,7 +3299,8 @@ {:abilities [{:action true :label "Make a run on targeted server" :cost [(->c :click 1) (->c :credit 2)] - :req (req (some #(= (:card-target card) %) runnable-servers)) + :change-in-game-state + {:req (req (some #(= (:card-target card) %) runnable-servers))} :msg (msg "make a run on " (:card-target card) ". Prevent the first subroutine that would resolve from resolving") :async true :effect (effect (register-events card [prevent-sub]) diff --git a/src/clj/game/cards/resources.clj b/src/clj/game/cards/resources.clj index 9d3aec8cb7..01bc5381a6 100644 --- a/src/clj/game/cards/resources.clj +++ b/src/clj/game/cards/resources.clj @@ -318,7 +318,7 @@ :abilities [{:cost [(->c :power 1)] :keep-menu-open :while-power-tokens-left :msg "reveal the top card of Stack" - :req (req (seq (:deck runner))) + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :effect (req (let [top-card (first (:deck runner))] @@ -347,6 +347,7 @@ (defcard "Artist Colony" {:abilities [{:prompt "Choose a card to install" :label "install a card" + :change-in-game-state {:req (req (seq (:deck runner)))} :req (req (not (install-locked? state side))) :cost [(->c :forfeit)] :choices (req (cancellable (filter #(not (event? %)) (:deck runner)) :sorted)) @@ -539,6 +540,7 @@ :msg "Make a run on HQ" :makes-run true :async true + :change-in-game-state {:req (req hq-runnable)} :effect (req (make-run state :runner eid :hq card))}] :events [(successful-run-replace-breach {:target-server :hq @@ -674,6 +676,7 @@ :prompt "Choose a server" :choices (req runnable-servers) :msg (msg "make a run on " target) + :change-in-game-state {:req (req (seq runnable-servers))} :async true :effect (effect @@ -722,6 +725,7 @@ {:action true :cost [(->c :click 1)] :keep-menu-open :while-clicks-left + :change-in-game-state {:req (req (seq (:hand runner)))} :label "Install a program from the grip" :prompt "Choose a program to install" :async true @@ -769,7 +773,7 @@ :effect (req (add-counter state side eid card :power 1))}] :abilities [{:label "Trash 1 random card from HQ for each hosted power counter" :async true - :req (req (pos? (get-counters card :power))) + :change-in-game-state {:req (req (pos? (get-counters card :power)))} :cost [(->c :trash-can)] :msg (msg "trash " (quantify (min (get-counters card :power) (count (:hand corp))) "card") " from HQ") @@ -995,6 +999,7 @@ :async true :label "Install a virus program from the stack" :prompt "Choose a virus" + :change-in-game-state {:req (req (seq (:deck runner)))} :choices (req (cancellable (filter #(and (program? %) (has-subtype? % "Virus")) (:deck runner)) :sorted)) @@ -1088,6 +1093,7 @@ :abilities [{:action true :async true :req (req tagged) + :change-in-game-state {:req (req (seq (:deck corp)))} :cost [(->c :click 1)] :keep-menu-open :while-clicks-left :effect (req (mill state :corp eid :corp 1)) @@ -1109,7 +1115,7 @@ true)))))}]}) (defcard "Dean Lister" - {:abilities [{:req (req run) + {:abilities [{:change-in-game-state {:req (req run)} :label "pump icebreaker" :msg (msg "give +1 strength for each card in [their] Grip to " (:title target) " until the end of the run") :choices {:card #(and (installed? %) @@ -1164,8 +1170,8 @@ {:implementation "Place counters manually for programs or pieces of hardware trashed manually (e.g. by being over MU)" :abilities [{:action true :label "Add a card from the heap to the grip" - :req (req (and (seq (eligible-cards runner)) - (not (zone-locked? state :runner :discard)))) + :change-in-game-state {:req (req (and (seq (eligible-cards runner)) + (not (zone-locked? state :runner :discard))))} :cost [(->c :click 1) (->c :power 3)] :prompt "Choose a card to add to grip" :choices (req (eligible-cards runner)) @@ -1267,6 +1273,7 @@ :keep-menu-open :while-clicks-left :cost [(->c :click 1) (->c :power 1)] :async true + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (req (wait-for (draw state :runner 3) (if (pos? (get-counters (get-card state card) :power)) (effect-completed state side eid) @@ -1313,6 +1320,7 @@ (defcard "Duggar's" {:abilities [{:action true :cost [(->c :click 4)] + :change-in-game-state {:req (req (seq (:deck runner)))} :keep-menu-open :while-4-clicks-left :async true :effect (effect (draw eid 10)) @@ -1418,6 +1426,7 @@ replace-breach-event] :abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req archives-runnable)} :msg "make a run on Archives" :label "Take 1 tag and run Archives" :makes-run true @@ -1495,7 +1504,7 @@ :abilities [{:action true :cost [(->c :click 2)] :label "Add hosted agenda to your score area" - :req (req (get-agenda card)) + :change-in-game-state {:req (req (get-agenda card))} :async true :msg (msg (let [c (get-agenda card)] (str "add " (:title c) " to [their] score area and gain " @@ -1550,6 +1559,7 @@ (defcard "First Responders" {:abilities [{:cost [(->c :credit 2)] :req (req (some corp? (map #(:card (first %)) (turn-events state :runner :damage)))) + :change-in-game-state {:req (req (seq (:deck runner)))} :msg "draw 1 card" :async true :effect (effect (draw eid 1))}]}) @@ -1756,6 +1766,7 @@ {:async true :label "Install the top 3 cards of the stack facedown" :msg "install the top 3 cards of the stack facedown" + :change-in-game-state {:req (req (seq (:deck runner)))} :cost [(->c :trash-can)] :effect (effect (continue-ability (ri (take 3 (:deck runner))) card nil))})]}) @@ -1961,6 +1972,7 @@ :effect (effect (add-counter eid card :credit 3))} {:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :msg (msg "gain " (get-counters card :credit) " [Credits]") :once :per-turn :label "Take all credits" @@ -2020,6 +2032,7 @@ card nil))})] {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (seq (:deck runner)))} :keep-menu-open :while-clicks-left :label "Reveal the top 4 cards of the stack" :msg (msg "reveal " (enumerate-str (map :title (take 4 (:deck runner)))) " from the top of the stack") @@ -2052,8 +2065,8 @@ {:data {:counter {:credit 16}} :abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :keep-menu-open :while-clicks-left - :change-in-game-state (req (pos? (get-counters card :credit))) :label "gain 4 [Credits]" :msg (msg "gain " (min 4 (get-counters card :credit)) " [Credits]") :async true @@ -2137,6 +2150,7 @@ :cost [(->c :click 1)] :keep-menu-open :while-clicks-left :prompt "Choose a non-virus program in the grip" + :change-in-game-state {:req (req (seq (:hand runner)))} :choices {:card #(and (program? %) (not (has-subtype? % "Virus")) (in-hand? %))} @@ -2148,6 +2162,7 @@ :label "Add a hosted program to the grip" :cost [(->c :click 1)] :keep-menu-open :while-clicks-left + :change-in-game-state {:req (req (seq (:hosted (get-card state card))))} :choices {:req (req (same-card? card (:host target)))} :msg (msg "add " (:title target) " to [their] Grip") :effect (effect (move target :hand))}] @@ -2383,6 +2398,7 @@ :effect (effect (gain-credits eid 3))} {:label "Remove 1 tag" :msg "remove 1 tag" + :change-in-game-state {:req (req tagged)} :cost [(->c :trash-can)] :async true :effect (effect (lose-tags :runner eid 1))}]}) @@ -2426,6 +2442,7 @@ (defcard "Officer Frank" {:abilities [{:cost [(->c :credit 1) (->c :trash-can)] :req (req (find-first #(= :meat (:damage-type (first %))) (turn-events state :runner :damage))) + :change-in-game-state {:req (req (seq (:hand corp)))} :msg "force the Corp to trash 2 random cards from HQ" :async true :effect (effect (trash-cards :corp eid (take 2 (shuffle (:hand corp))) {:cause-card card}))}]}) @@ -2433,6 +2450,7 @@ (defcard "Oracle May" {:abilities [{:action true :cost [(->c :click 1)] + :change-in-game-state {:req (req (seq (:deck runner)))} :label "Name a card type" :once :per-turn :prompt "Choose one" @@ -2960,13 +2978,14 @@ " of R&D") :effect (effect (mill :corp eid :corp (get-turn-damage state :runner)))}}}]}) +;; TODO - limit selection to what runner can play (defcard "Same Old Thing" {:abilities [{:action true :async true :label "play an event in the heap" :cost [(->c :click 2) (->c :trash-can)] - :req (req (and (not (zone-locked? state :runner :discard)) - (pos? (count (filter event? (:discard runner)))))) + :change-in-game-state {:req (req (and (not (zone-locked? state :runner :discard)) + (pos? (count (filter event? (:discard runner))))))} :prompt "Choose an event in the heap" :msg (msg "play " (:title target)) :show-discard true @@ -3096,6 +3115,7 @@ {:abilities [{:label "Draw 2 cards" :msg "draw 2 cards" :cost [(->c :trash-can)] + :change-in-game-state {:req (req (seq (:deck runner)))} :async true :effect (effect (draw :runner eid 2))} {:label "Charge a card" @@ -3138,14 +3158,14 @@ :abilities [{:async true :label "install a hosted card" :trash-icon true - :req (req (some #(and (not (event? (get-card state %))) - (runner-can-pay-and-install? - state side - (assoc eid :source card :source-type :runner-install) - (get-card state %) - {:cost-bonus -1 - :no-toast true})) - (seq (:hosted card)))) + :change-in-game-state {:req (req (some #(and (not (event? (get-card state %))) + (runner-can-pay-and-install? + state side + (assoc eid :source card :source-type :runner-install) + (get-card state %) + {:cost-bonus -1 + :no-toast true})) + (seq (:hosted card))))} :effect (req (let [set-aside-cards (set-aside state side eid (:hosted card))] (wait-for (trash state side card {:cause :ability-cost :cause-card card}) (system-msg state side "trashed") @@ -3184,6 +3204,7 @@ {:abilities [{:label "Draw 1 card for each bad publicity the Corp has" :async true :cost [(->c :trash-can)] + :change-in-game-state {:req (req (pos? (count-bad-pub state)))} :effect (effect (draw eid (count-bad-pub state))) :msg (msg "draw " (quantify (count-bad-pub state) "card"))}] :events [{:event :play-operation @@ -3228,7 +3249,7 @@ :abilities [{:action true :label "Take 3 [Credits] from this resource" :cost [(->c :click 1)] - :change-in-game-state (req (pos? (get-counters card :credit))) + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :once :per-turn :msg "gain 3 [Credits]" :async true @@ -3711,6 +3732,7 @@ :choices (req (cancellable (filter hardware? (:deck runner)) :sorted)) :cost [(->c :click 2)] :keep-menu-open :while-2-clicks-left + :change-in-game-state {:req (req (seq (:deck runner)))} :effect (effect (trigger-event :searched-stack) (shuffle! :deck) (move target :hand))}]}) @@ -3795,7 +3817,7 @@ :abilities [{:action true :cost [(->c :click 1)] :label "move hosted virus counter" - :req (req (pos? (get-counters card :virus))) + :change-in-game-state {:req (req (pos? (get-counters card :virus)))} :async true :effect (req (continue-ability state side @@ -3905,6 +3927,7 @@ :abilities [{:action true :cost [(->c :click 1)] :msg (msg "gain " (get-counters card :credit) " [Credits]") + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :label "Take all credits" :async true :effect (req (take-credits state side eid card :credit :all))}]})) diff --git a/src/clj/game/cards/upgrades.clj b/src/clj/game/cards/upgrades.clj index e6b4834710..29bf3f8de3 100644 --- a/src/clj/game/cards/upgrades.clj +++ b/src/clj/game/cards/upgrades.clj @@ -178,6 +178,7 @@ :display-origin true}}))}] {:events [{:event :agenda-scored :req (req (= (:previous-zone (:card context)) (get-zone card))) + :change-in-game-state {:silent true :req (req (seq (:hand corp)))} :interactive (req (some corp-installable-type? (:hand corp))) :silent (req (not-any? corp-installable-type? (:hand corp))) :async true @@ -242,7 +243,7 @@ {:install-req (req (filter #{"R&D"} targets)) :abilities [{:action true :cost [(->c :click 1)] - :req (req (pos? (count (:deck corp)))) + :change-in-game-state {: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")) :label "Add 1 card from top 3 of R&D to HQ" @@ -299,7 +300,7 @@ {:install-req (req (remove #{"HQ" "R&D" "Archives"} targets)) :advanceable :always :abilities [{:label "End the run" - :req (req (:run @state)) + :change-in-game-state {:req (req (:run @state))} :msg "end the run" :async true :cost [(->c :advancement 2) (->c :trash-can)] @@ -486,6 +487,7 @@ :req (req (= (:server (second targets)) (unknown->kw (get-zone card)))) :value (req (repeat (get-counters card :power) [(->c :credit 1) (->c :click 1)]))}] :events [{:event :corp-turn-begins + :interactive (req true) :req (req (pos? (get-counters card :power))) :msg "remove all hosted power counters" :async true @@ -680,7 +682,7 @@ :cost [(->c :credit 1)] :msg "place 1 power counter on itself"}}} card nil))} - etr {:req (req this-server) + etr {:req (req (and this-server run)) :cost [(->c :power 1)] :msg "end the run" :async true @@ -789,14 +791,14 @@ :interactive (req true) :async true :req (req this-server) - :effect (effect + :effect (effect (continue-ability (let [credit-cost (* 2 (count (:scored runner)))] {:player :runner :async true :waiting-prompt true :prompt "Choose one" - :choices [(when (can-pay? state :runner eid card nil (->c :credit credit-cost)) + :choices [(when (can-pay? state :runner eid card nil (->c :credit credit-cost)) (str "Pay " credit-cost " [Credits]")) "End the run"] :msg (msg (if (= "End the run" target) @@ -821,7 +823,7 @@ {:abilities [{:label "All ice protecting this server has +2 strength until the end of the run" :msg "increase the strength of all ice protecting this server until the end of the run" :req (req (and this-server - (pos? (count run-ices)) + run (pos? (count (:hand corp))))) :cost [(->c :trash-from-hand 1)] :effect (effect (register-lingering-effect @@ -1616,13 +1618,14 @@ {:abilities [{:action true :cost [(->c :click 1)] - :msg "store 3 [Credits]" + :msg "place 3 [Credits]" :once :per-turn :async true :effect (effect (add-counter eid card :credit 3 nil))} {:action true :cost [(->c :click 1)] :msg (msg "gain " (get-counters card :credit) " [Credits]") + :change-in-game-state {:req (req (pos? (get-counters card :credit)))} :once :per-turn :label "Take all credits" :async true @@ -1631,7 +1634,7 @@ (defcard "Signal Jamming" {:abilities [{:label "Cards cannot be installed until the end of the run" :msg "prevent cards being installed until the end of the run" - :req (req this-server) + :req (req (and this-server run)) :cost [(->c :trash-can)] :effect (effect (register-run-flag! card :corp-lock-install (constantly true)) (register-run-flag! card :runner-lock-install (constantly true)) diff --git a/src/clj/game/core/engine.clj b/src/clj/game/core/engine.clj index 403d0d17a0..1b9a703199 100644 --- a/src/clj/game/core/engine.clj +++ b/src/clj/game/core/engine.clj @@ -324,25 +324,30 @@ (defn do-nothing "Does nothing (loudly)" - [state side eid card] - (system-msg state side (str "uses " (:title card) " to do nothing")) - (effect-completed state side eid)) + ([state side eid ability card] (do-nothing state side eid ability card nil)) + ([state side eid ability card payment-str] + (when-not (get-in ability [:change-in-game-state :silent]) + (print-msg state side (assoc ability :msg "do nothing") card [] payment-str)) + ;;(system-msg state side (str "uses " (:title card) " to do nothing"))) + (effect-completed state side eid))) (defn- change-in-game-state? "Concession for NCIGS going - uses a 'change-in-game-state' key to check when a card has no potential to do anything through resolving (different to req)" - [state side {:keys [change-in-game-state eid] :as ability} card targets] - (or (not (contains? ability :change-in-game-state)) - (change-in-game-state state side eid card targets))) + [state side {:keys [eid] :as ability} card targets] + (or (= nil (get-in ability [:change-in-game-state :req])) + ((get-in ability [:change-in-game-state :req]) state side eid card targets))) (defn- do-effect "Trigger the effect" - [state side {:keys [eid] :as ability} card targets] - (if-let [ability-effect (:effect ability)] - (if (change-in-game-state? state side ability card targets) - (ability-effect state side eid card targets) - (do-nothing state side eid card)) - (effect-completed state side eid))) + [state side {:keys [eid] :as ability} card payment-str targets] + (if (change-in-game-state? state side ability card targets) + (do (print-msg state side ability card targets payment-str) + (if-let [ability-effect (:effect ability)] + (ability-effect state side eid card targets) + (effect-completed state side eid))) + (do (do-nothing state side eid ability card payment-str) + (effect-completed state side eid)))) (defn merge-costs-paid ([cost-paid] cost-paid) @@ -371,11 +376,9 @@ ;; We still want the card if the card is trashed, so default to given ;; when the latest is gone. card (or (get-card state card) card)] - ;; Print the message - (print-msg state side ability card targets payment-str) ;; Trigger the effect (register-once state side ability card) - (do-effect state side ability card targets) + (do-effect state side ability card payment-str targets) ;; If the ability isn't async, complete it (when-not (:async ability) (effect-completed state side eid)))) @@ -414,7 +417,7 @@ (select-keys [:cancel-effect :prompt-type :show-discard :end-effect :waiting-prompt]) (assoc :targets targets))] (if-not (change-in-game-state? state side ability card targets) - (do-nothing state side eid card) + (do-nothing state side eid ability card) (if (map? choices) ;; Two types of choices use maps: select prompts, and :number prompts. (cond diff --git a/test/clj/game/cards/agendas_test.clj b/test/clj/game/cards/agendas_test.clj index 52933229a7..b26d44c274 100644 --- a/test/clj/game/cards/agendas_test.clj +++ b/test/clj/game/cards/agendas_test.clj @@ -1759,19 +1759,15 @@ (deftest hades-fragment ;; Hades Fragment (do-game - (new-game {:corp {:deck ["Hades Fragment" (qty "Hedge Fund" 2)]}}) + (new-game {:corp {:hand ["Hades Fragment"] :discard ["Hedge Fund"]}}) (starting-hand state :corp ["Hades Fragment"]) (play-and-score state "Hades Fragment") (take-credits state :corp) (take-credits state :runner) - (is (= 1 (count (:hand (get-corp)))) "Corp should have no opportunity to use Hades Shard") - (core/move state :corp (find-card "Hedge Fund" (:hand (get-corp))) :discard) - (take-credits state :corp) - (take-credits state :runner) (let [hf-scored (get-scored state :corp 0)] (card-ability state :corp hf-scored 0) - (click-card state :corp (find-card "Hedge Fund" (:discard (get-corp)))) - (is (= 2 (count (:deck (get-corp)))) "R&D should have 2 cards in it after Hades Fragment use")))) + (click-card state :corp (find-card "Hedge Fund" (:discard (get-corp))))) + (is (= 1 (count (:deck (get-corp)))) "R&D should have 1 card in it after Hades Fragment use"))) (deftest helium-3-deposit ;; Helium-3 Deposit diff --git a/test/clj/game/cards/assets_test.clj b/test/clj/game/cards/assets_test.clj index 6e1d8f6809..9d91c5d16e 100644 --- a/test/clj/game/cards/assets_test.clj +++ b/test/clj/game/cards/assets_test.clj @@ -337,7 +337,7 @@ (is (:run @state) "Cannot use B-1001 ability during runs on its own server") (run-continue state) (click-prompt state :runner "No action") - (run-empty-server state :hq) + (run-on state :hq) (is (changed? [(count-tags state) -1] (card-ability state :corp b 0) (is (not (:run @state)) "Run ended")) @@ -1264,13 +1264,14 @@ "Took all hosted credits") (is (= 1 (count (:discard (get-corp)))) "Cybersand Harvester got trashed")))) -(deftest cybersand-harvester-cant-be-trashed-when-no-credits +(deftest cybersand-harvester-can-be-trashed-when-no-credits (do-game (new-game {:corp {:deck ["Cybersand Harvester"]}}) (play-from-hand state :corp "Cybersand Harvester" "New remote") (rez state :corp (get-content state :remote1 0)) (card-ability state :corp (get-content state :remote1 0) 0) - (is (= "Cybersand Harvester" (:title (get-content state :remote1 0))) "Cybersand Harveste was not trashed"))) + (is (= "Cybersand Harvester" (->> (get-corp) :discard first :title)) + "Cybersand Harvester was trashed"))) (deftest daily-business-show-full-test ;; Full test diff --git a/test/clj/game/cards/events_test.clj b/test/clj/game/cards/events_test.clj index bc8b029b4d..2fc8563525 100644 --- a/test/clj/game/cards/events_test.clj +++ b/test/clj/game/cards/events_test.clj @@ -2963,33 +2963,32 @@ (is (= (+ discard 5) (count (:discard (get-corp)))) "Corp trashes 5 additional card")))) (deftest fear-the-masses-trebuchet-firing-incorrectly-prevents-fear-the-masses-effect-from-taking-place-issue-5294 - ;; Trebuchet firing incorrectly prevents Fear The Masses effect from taking place. Issue #5294 - (do-game - (new-game {:corp {:deck [(qty "Hedge Fund" 50)] - :hand ["Trebuchet"]} - :runner {:hand [(qty "Fear the Masses" 6)]}}) - (play-from-hand state :corp "Trebuchet" "HQ") - (take-credits state :corp) - (let [discard (count (:discard (get-corp))) - treb (get-ice state :hq 0)] - (play-from-hand state :runner "Fear the Masses") - (rez state :corp treb) - (run-continue state) - (card-subroutine state :corp treb 0) - (click-prompt state :corp "Done") - (card-subroutine state :corp treb 1) - (click-prompt state :corp "0") - (click-prompt state :runner "0") - (run-continue state) - (run-continue state) - (is (= (inc discard) (count (:discard (get-corp)))) "Corp trashes 1 card")) - (let [discard (count (:discard (get-corp)))] - (click-card state :runner (nth (:hand (get-runner)) 0)) - (click-card state :runner (nth (:hand (get-runner)) 1)) - (click-card state :runner (nth (:hand (get-runner)) 2)) - (click-card state :runner (nth (:hand (get-runner)) 3)) - (click-card state :runner (nth (:hand (get-runner)) 4)) - (is (= (+ discard 5) (count (:discard (get-corp)))) "Corp trashes 5 additional card")))) + ;; Trebuchet firing incorrectly prevents Fear The Masses effect from taking place. Issue #5294 + (do-game + (new-game {:corp {:deck [(qty "Hedge Fund" 50)] + :hand ["Trebuchet"]} + :runner {:hand [(qty "Fear the Masses" 6)]}}) + (play-from-hand state :corp "Trebuchet" "HQ") + (take-credits state :corp) + (let [discard (count (:discard (get-corp))) + treb (get-ice state :hq 0)] + (play-from-hand state :runner "Fear the Masses") + (rez state :corp treb) + (run-continue state) + (card-subroutine state :corp treb 0) + (card-subroutine state :corp treb 1) + (click-prompt state :corp "0") + (click-prompt state :runner "0") + (run-continue state) + (run-continue state) + (is (= (inc discard) (count (:discard (get-corp)))) "Corp trashes 1 card")) + (let [discard (count (:discard (get-corp)))] + (click-card state :runner (nth (:hand (get-runner)) 0)) + (click-card state :runner (nth (:hand (get-runner)) 1)) + (click-card state :runner (nth (:hand (get-runner)) 2)) + (click-card state :runner (nth (:hand (get-runner)) 3)) + (click-card state :runner (nth (:hand (get-runner)) 4)) + (is (= (+ discard 5) (count (:discard (get-corp)))) "Corp trashes 5 additional card")))) (deftest feint ;; Feint - bypass 2 pieces of ice on HQ, but access no cards diff --git a/test/clj/game/cards/hardware_test.clj b/test/clj/game/cards/hardware_test.clj index 1e3e53259b..89282e9a7b 100644 --- a/test/clj/game/cards/hardware_test.clj +++ b/test/clj/game/cards/hardware_test.clj @@ -2080,8 +2080,6 @@ (take-credits state :corp) (play-from-hand state :runner "Flip Switch") (let [flip (get-hardware state 0)] - (card-ability state :runner (get-hardware state 0) 0) - (is (refresh flip) "Flip Switch hasn't been trashed") (run-on state "HQ") (card-ability state :runner (get-hardware state 0) 0) (is (= "Runner jacks out." (-> @state :log last :text))) @@ -2097,10 +2095,7 @@ (play-from-hand state :runner "Flip Switch") (is (zero? (count-tags state)) "Runner starts with 0 tags") (let [flip (get-hardware state 0)] - (card-ability state :runner flip 1) - (is (refresh flip) "Flip Switch hasn't been trashed") (gain-tags state :runner 1) - (is (= 1 (count-tags state)) "Runner starts with 0 tags") (card-ability state :runner flip 1) (is (zero? (count-tags state)) "Runner has lost 1 tag") (is (nil? (refresh flip)) "Flip Switch has been trashed") @@ -4218,15 +4213,15 @@ (card-ability state :runner (get-hardware state 0) 1) (is (last-log-contains? state "reveal Sure Gamble from the top of the stack") "Correctly prints the revealed card")))) -(deftest prognostic-q-loop-doesn-t-fire-with-an-empty-deck - ;; Doesn't fire with an empty deck - (do-game - (new-game {:runner {:hand ["Prognostic Q-Loop"]}}) - (take-credits state :corp) - (play-from-hand state :runner "Prognostic Q-Loop") - (card-ability state :runner (get-hardware state 0) 1) - (is (last-log-contains? state "Runner spends [Click] and pays 1 [Credits] to install Prognostic Q-Loop.") - "Shouldn't print anything to log as the stack is empty"))) +(deftest prognostic-q-loop-does-nothing-with-an-empty-deck + ;; Doesn't fire with an empty deck + (do-game + (new-game {:runner {:hand ["Prognostic Q-Loop"]}}) + (take-credits state :corp) + (play-from-hand state :runner "Prognostic Q-Loop") + (card-ability state :runner (get-hardware state 0) 1) + (is (last-log-contains? state "Prognostic Q-Loop to do nothing.") + "Shouldn't print anything to log as the stack is empty"))) (deftest prognostic-q-loop-orders-correctly-with-other-on-run-triggers-when-firing-first-issue-4973 ;; Orders correctly with other on run triggers when firing first. Issue #4973 @@ -4965,7 +4960,8 @@ (play-from-hand state :runner "Corroder") (play-from-hand state :runner "Simulchip") (card-ability state :runner (get-hardware state 0) 0) - (is (no-prompt? state :runner) "No Simulchip prompt")))) + (is (not (no-prompt? state :runner)) + "Simulchip prompt (the great NCIGS paradigm shift)")))) (deftest simulchip-no-additional-cost-when-hosted-program-is-trashed-issue-4897 ;; No additional cost when hosted program is trashed. Issue #4897 diff --git a/test/clj/game/cards/ice_test.clj b/test/clj/game/cards/ice_test.clj index 1d6c386264..091e959f4e 100644 --- a/test/clj/game/cards/ice_test.clj +++ b/test/clj/game/cards/ice_test.clj @@ -2372,8 +2372,7 @@ (click-prompt state :runner "Pay 1 [Credits]")) "Paid 1c for subroutine") (card-subroutine state :corp fc1 1) - (is (= 1 (count (:choices (prompt-map :runner)))) "Only 1 choice in prompt") - (click-prompt state :runner "Trash an installed card") + (is (no-prompt? state :runner) "No prompt because we cannot pay!") (is (no-prompt? state :runner) "no lingering prompt")))) (deftest fairchild-2-0 diff --git a/test/clj/game/cards/upgrades_test.clj b/test/clj/game/cards/upgrades_test.clj index c98a362b08..2dc3e75b92 100644 --- a/test/clj/game/cards/upgrades_test.clj +++ b/test/clj/game/cards/upgrades_test.clj @@ -3947,7 +3947,7 @@ ;; Trash to stop installs for the rest of the run (do-game (new-game {:corp {:deck [(qty "Signal Jamming" 3)]} - :runner {:deck [(qty "Self-modifying Code" 3) "Reaver"]}}) + :runner {:hand [(qty "Self-modifying Code" 3)] :deck ["Reaver"] :credits 10}}) (starting-hand state :runner ["Self-modifying Code" "Self-modifying Code"]) (play-from-hand state :corp "Signal Jamming" "HQ") (take-credits state :corp) @@ -3960,7 +3960,8 @@ (run-on state "HQ") (card-ability state :corp sj 0) (card-ability state :runner smc1 0) - (is (no-prompt? state :runner) "SJ blocking SMC") + (is (= ["Done"] (prompt-titles :runner)) "Can only shuffle") + (click-prompt state :runner "Done") (run-jack-out state) (card-ability state :runner smc2 0) (click-prompt state :runner "Reaver"))))