From 585562c607e89b8cbdb416ca4e2473f8db50c55e Mon Sep 17 00:00:00 2001 From: Brian Butz Date: Sun, 3 Dec 2023 22:56:15 +0000 Subject: [PATCH] Implement BMI Buffer and BMI Buffer 2 --- src/clj/game/cards/hardware.clj | 48 ++++++++++++++++++++++++++- test/clj/game/cards/hardware_test.clj | 39 ++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/clj/game/cards/hardware.clj b/src/clj/game/cards/hardware.clj index 66d68e11a7..a722214df8 100644 --- a/src/clj/game/cards/hardware.clj +++ b/src/clj/game/cards/hardware.clj @@ -27,7 +27,7 @@ [game.core.events :refer [event-count first-event? first-trash? no-event? run-events]] [game.core.expose :refer [expose]] - [game.core.finding :refer [find-card]] + [game.core.finding :refer [find-card find-latest]] [game.core.flags :refer [can-trash? card-flag? in-corp-scored? register-run-flag! zone-locked?]] [game.core.gaining :refer [gain-clicks gain-credits lose-clicks @@ -234,6 +234,52 @@ card nil) (rez state :corp eid target))))}]}) +(defcard "BMI Buffer" + (let [grip-program-trash? + (fn [card] + (and (runner? card) + (program? card) + (in-discard? card) + (= (first (:previous-zone card)) :hand))) + triggered-ability + {:async true + :effect (req (doseq [c (filter grip-program-trash? (mapv #(find-latest state (:card %)) targets))] + (host state side (get-card state card) c)) + (effect-completed state side eid))}] + {:events [(assoc triggered-ability :event :runner-trash) + (assoc triggered-ability :event :corp-trash)] + :abilities [{:cost [:click 2] + :label "Install a hosted program" + :prompt "Choose a program to install" + :choices (req (cancellable (filter #(can-pay? state side (assoc eid :source card :source-type :runner-install) + % nil [:credit (install-cost state side %)]) + (:hosted card)))) + :msg (msg "install " (:title target)) + :async true + :effect (effect (runner-install (assoc eid :source card :source-type :runner-install) target))}]})) + +(defcard "BMI Buffer 2" + (let [grip-program-trash? + (fn [card] + (and (runner? card) + (program? card) + (in-discard? card) + (= (first (:previous-zone card)) :hand))) + triggered-ability + {:async true + :effect (req (doseq [c (filter grip-program-trash? (mapv #(find-latest state (:card %)) targets))] + (host state side (get-card state card) c)) + (effect-completed state side eid))}] + {:events [(assoc triggered-ability :event :runner-trash) + (assoc triggered-ability :event :corp-trash)] + :abilities [{:cost [:click 2] + :label "Install a hosted program" + :prompt "Choose a program to install" + :choices (req (:hosted card)) + :msg (msg "install " (:title target)) + :async true + :effect (effect (runner-install (assoc eid :source card :source-type :runner-install) target {:ignore-all-cost true}))}]})) + (defcard "Bookmark" {:abilities [{:label "Host up to 3 cards from the grip facedown" :cost [:click 1] diff --git a/test/clj/game/cards/hardware_test.clj b/test/clj/game/cards/hardware_test.clj index fcd8a9d82e..892a149362 100644 --- a/test/clj/game/cards/hardware_test.clj +++ b/test/clj/game/cards/hardware_test.clj @@ -418,6 +418,45 @@ (click-card state :runner "Ice Wall") (click-prompt state :corp "No")))) +(deftest bmi-buffer + (do-game + (new-game {:runner {:hand ["Abaasy" "BMI Buffer" "Freelance Coding Contract"]}}) + (take-credits state :corp) + (play-from-hand state :runner "BMI Buffer") + (play-from-hand state :runner "Freelance Coding Contract") + (click-card state :runner (find-card "Abaasy" (:hand (get-runner)))) + (click-prompt state :runner "Done") + (is (= 0 (count (filter #(= (:type %) "Program") (:discard (get-runner))))) "No programs in Heap") + (is (nil? (get-program state 0)) "Abaasy not installed") + (let [bmi (get-hardware state 0)] + (is (= 1 (count (:hosted bmi))) "BMI Buffer hosting Abaasy") + (changes-val-macro -2 (:credit (get-runner)) + "BMI Buffer requires install cost paid" + (card-ability state :runner bmi 0) + (click-prompt state :runner "Abaasy")) + (is (= 0 (count (:hosted (refresh bmi)))) "BMI Buffer no longer hosting Abaasy") + (is (= "Abaasy" (:title (get-program state 0))) "Abaasy is installed")))) + +(deftest bmi-buffer-2 + ;; BMI Buffer 2 installs ignoring all costs + (do-game + (new-game {:runner {:hand ["Abaasy" "BMI Buffer 2" "Freelance Coding Contract"]}}) + (take-credits state :corp) + (play-from-hand state :runner "BMI Buffer 2") + (play-from-hand state :runner "Freelance Coding Contract") + (click-card state :runner (find-card "Abaasy" (:hand (get-runner)))) + (click-prompt state :runner "Done") + (is (= 0 (count (filter #(= (:type %) "Program") (:discard (get-runner))))) "No programs in Heap") + (is (nil? (get-program state 0)) "Abaasy not installed") + (let [bmi (get-hardware state 0)] + (is (= 1 (count (:hosted bmi))) "BMI Buffer 2 hosting Abaasy") + (changes-val-macro 0 (:credit (get-runner)) + "BMI Buffer 2 ignores install cost" + (card-ability state :runner bmi 0) + (click-prompt state :runner "Abaasy")) + (is (= 0 (count (:hosted (refresh bmi)))) "BMI Buffer 2 no longer hosting Abaasy") + (is (= "Abaasy" (:title (get-program state 0))) "Abaasy is installed")))) + (deftest bookmark-click-ability ;; Click ability (do-game