Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terminal directive campaign cards #7776

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/clj/game/cards/agendas.clj
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,24 @@
:async true
:effect (effect (gain-credits :corp eid 5))}}}})

(defcard "Evidence Collection"
{:events [{:event :win
:req (req (= :corp (:winner @state)))
:msg (msg "reveal set 2")}]})

(defcard "Evidence Collection 2"
{:events [{:event :win
:req (req (= :corp (:winner @state)))
:msg (msg "reveal set 5")}]})

(defcard "Evidence Collection 3"
{:events [{:event :win
:req (req (= :corp (:winner @state)))
:msg (msg "reveal set 8")}]})

(defcard "Evidence Collection 4"
{:agendapoints-runner (req 1)})

(defcard "False Lead"
{:abilities [{:req (req (<= 2 (:click runner)))
:label "runner loses [Click][Click]"
Expand Down
69 changes: 65 additions & 4 deletions src/clj/game/cards/assets.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[clojure.pprint :as pprint]
[clojure.set :as set]
[clojure.string :as str]
[game.core.access :refer [access-card installed-access-trigger]]
[game.core.access :refer [access-bonus access-card get-only-card-to-access installed-access-trigger num-cards-to-access]]
[game.core.actions :refer [score]]
[game.core.agendas :refer [update-all-advancement-requirements
update-all-agenda-points]]
Expand All @@ -28,9 +28,9 @@
[game.core.engine :refer [not-used-once? pay register-events resolve-ability]]
[game.core.events :refer [first-event? no-event? turn-events event-count]]
[game.core.expose :refer [expose-prevent]]
[game.core.flags :refer [lock-zone prevent-current
[game.core.flags :refer [in-runner-scored? lock-zone prevent-current
prevent-draw
register-turn-flag! release-zone]]
register-turn-flag! release-zone when-scored?]]
[game.core.gaining :refer [gain gain-clicks gain-credits lose lose-clicks
lose-credits]]
[game.core.hand-size :refer [corp-hand-size+ runner-hand-size+]]
Expand All @@ -40,7 +40,7 @@
[game.core.initializing :refer [card-init]]
[game.core.installing :refer [corp-install corp-install-msg]]
[game.core.moving :refer [as-agenda mill move remove-from-currently-drawing
swap-cards swap-installed trash trash-cards]]
swap-agendas swap-cards swap-installed trash trash-cards]]
[game.core.optional :refer [get-autoresolve set-autoresolve]]
[game.core.payment :refer [can-pay? cost-value ->c]]
[game.core.play-instants :refer [play-instant]]
Expand Down Expand Up @@ -1392,6 +1392,31 @@
:async true
:effect (effect (gain-credits eid 1))}]})

(defcard "Investigator Inez Delgado A"
{:events [{:event :agenda-scored
:interactive (req true)
:req (req (seq (:scored runner)))
:async true
:effect (effect
(continue-ability
(let [stolen (:card context)]
{:optional
{:prompt (msg "Swap " (:title stolen) " for an agenda in the Runner's score area?")
:yes-ability
{:prompt (str "Choose a scored Runner agenda to swap with " (:title stolen))
:choices {:card #(in-runner-scored? state side %)}
:msg (msg "swap " (:title stolen) " for " (:title target))
:async true
:effect (req (let [new-scored (second (swap-agendas state side target stolen))]
(continue-ability
state side
(when (when-scored? new-scored)
{:msg (msg "trigger the \"when scored\" ability of " (:title new-scored))
:async true
:effect (effect (continue-ability (:on-score (card-def new-scored)) target nil))})
card nil)))}}})
card targets))}]})

(defcard "Isabel McGuire"
{:abilities [{:action true
:label "Add an installed card to HQ"
Expand Down Expand Up @@ -1631,6 +1656,28 @@
:msg "give the Runner 1 tag"
:effect (req (gain-tags state :runner eid 1))}]})

(defcard "Lt. Todachine 2"
{:events [{:event :rez
:req (req (ice? (:card context)))
:async true
:msg "give the Runner 1 tag"
:effect (req (gain-tags state :runner eid 1))}
{:event :breach-server
:interactive (req true)
:player :corp
:req (req tagged)
:async true
;; the random-access check needs to be dereffed to work correctly
:effect (req (continue-ability
state side
{:req (req
(and tagged
(> (:random-access-limit (num-cards-to-access state :runner target nil)) 1)
(not (get-only-card-to-access state))))
:msg (msg "make the runner access 1 card fewer")
:effect (req (access-bonus state :runner target -1))}
card targets))}]})

(defcard "Malia Z0L0K4"
(let [unmark
(req (when-let [malia-target (get-in card [:special :malia-target])]
Expand Down Expand Up @@ -2951,6 +2998,20 @@
(contains? break-ability :break-cost)))))
:value true}]})

(defcard "Trojan"
{:flags {:rd-reveal (req true)}
:poison true
:on-access {:async true
:req (req (not (in-discard? card)))
:msg (msg "lose 2 [Credits], destroy itself, and trash 1 card from HQ at random")
:effect (req (wait-for
(lose-credits state :corp 2)
(move state side card :destroyed)
(let [trash-target (first (shuffle (get-in @state [:corp :hand])))]
(if trash-target
(trash state :corp eid trash-target {:cause-card card})
(effect-completed state side eid)))))}})

(defcard "Turtlebacks"
{:events [{:event :server-created
:msg "gain 1 [Credits]"
Expand Down
17 changes: 16 additions & 1 deletion src/clj/game/cards/resources.clj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
all-installed-runner card->server get-all-cards server->zone]]
[game.core.card :refer [agenda? asset? assoc-host-zones card-index corp? condition-counter?
event? facedown? get-agenda-points get-card get-counters
get-title get-zone hardware? has-subtype? ice? identity? in-discard? in-hand? in-scored?
get-title get-zone hardware? has-subtype? ice? identity? in-discard? in-hand? in-set-aside? in-scored?
installed? is-type? program? resource? rezzed? runner? upgrade? virus-program?]]
[game.core.card-defs :refer [card-def]]
[game.core.charge :refer [can-charge charge-ability]]
Expand Down Expand Up @@ -2952,6 +2952,21 @@
:effect (effect (update! (dissoc card :card-target)))}]
:abilities [ability]}))

(defcard "Shadow Team"
{:on-draw {:req (req (and (runner-can-pay-and-install? state side eid card)
(in-set-aside? card)))
:msg (msg "install itself")
:async true
:effect (req (runner-install state side eid card))}
:events [{:event :run
:req (req (seq (:hand runner)))
:msg :cost
:cost [(->c :trash-from-hand 1)]}
{:event :successful-run
:req (req (#{:hq :rd :archives} (target-server context)))
:msg (msg "destroy itself")
:effect (req (move state side card :destroyed))}]})

(defcard "Smartware Distributor"
(let [start-of-turn-ability {:once :per-turn
:label "Take 1 [Credits] (start of turn)"
Expand Down
1 change: 1 addition & 0 deletions src/clj/game/core/damage.clj
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
(swap! state update-in [:stats :corp :damage dmg-type] (fnil + 0) n)
(if (< (count hand) n)
(do (flatline state)
(trigger-event state side :win {:winner :corp})
(trash-cards state side eid cards-trashed {:unpreventable true}))
(wait-for (trash-cards state side cards-trashed {:unpreventable true
:cause dmg-type
Expand Down
1 change: 1 addition & 0 deletions src/clj/game/core/diffs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
:play-area
:current
:set-aside
:destroyed
:click
:credit
:toast
Expand Down
32 changes: 19 additions & 13 deletions src/clj/game/core/drawing.clj
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
(ns game.core.drawing
(:require
[game.core.card :refer [get-title]]
[game.core.eid :refer [effect-completed make-eid make-result]]
[game.core.engine :refer [checkpoint queue-event resolve-ability trigger-event trigger-event-simult trigger-event-sync]]
[game.core.events :refer [first-event?]]
[game.core.flags :refer [prevent-draw]]
[game.core.moving :refer [move]]
[game.core.say :refer [system-msg]]
[game.core.set-aside :refer [set-aside-for-me get-set-aside]]
[game.core.winning :refer [win-decked]]
[game.macros :refer [continue-ability msg req wait-for]]
[game.utils :refer [quantify safe-zero?]]
[jinteki.utils :refer [other-side]]))
[game.core.card :refer [get-title]]
[game.core.card-defs :refer [card-def]]
[game.core.eid :refer [effect-completed make-eid make-result]]
[game.core.engine :refer [checkpoint queue-event register-pending-event resolve-ability trigger-event trigger-event-simult trigger-event-sync]]
[game.core.events :refer [first-event?]]
[game.core.flags :refer [prevent-draw]]
[game.core.moving :refer [move]]
[game.core.say :refer [system-msg]]
[game.core.set-aside :refer [set-aside-for-me get-set-aside]]
[game.core.winning :refer [win-decked]]
[game.macros :refer [continue-ability msg req wait-for]]
[game.utils :refer [quantify safe-zero?]]
[jinteki.utils :refer [other-side]]))

(defn max-draw
"Put an upper limit on the number of cards that can be drawn in this turn."
Expand Down Expand Up @@ -68,7 +69,8 @@
deck-count (count (get-in @state [side :deck]))]
(swap! state update :bonus dissoc :draw);; clear bonus draws
(when (and (= side :corp) (< deck-count draws-after-prevent))
(win-decked state))
(when (win-decked state)
(trigger-event state :runner :win)))
(when (< draws-after-prevent draws-wanted)
(let [prevented (- draws-wanted draws-after-prevent)]
(system-msg state (other-side side)
Expand All @@ -93,6 +95,10 @@
(effect-completed state side eid))
(let [draw-event (if (= side :corp) :corp-draw :runner-draw)]
(swap! state update-in [side :register :currently-drawing] conj drawn)
(doseq [c drawn]
(when-let [on-draw (:on-draw (card-def c))]
(register-pending-event
state draw-event c (assoc on-draw :location :set-aside))))
(queue-event state draw-event {:cards drawn
:count drawn-count})
(wait-for
Expand Down
9 changes: 6 additions & 3 deletions src/clj/game/core/engine.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[cond-plus.core :refer [cond+]]
[game.core.board :refer [clear-empty-remotes get-all-cards all-installed all-installed-runner
all-installed-runner-type all-active-installed]]
[game.core.card :refer [active? facedown? faceup? get-card get-cid get-title ice? in-discard? in-hand? installed? rezzed? program? console? unique?]]
[game.core.card :refer [active? facedown? faceup? get-card get-cid get-title ice? in-discard? in-hand? in-set-aside? installed? rezzed? program? console? unique?]]
[game.core.card-defs :refer [card-def]]
[game.core.effects :refer [get-effect-maps unregister-lingering-effects is-disabled? is-disabled-reg? update-disabled-cards]]
[game.core.eid :refer [complete-with-result effect-completed make-eid]]
Expand Down Expand Up @@ -622,6 +622,8 @@
:inactive (not (active? card))
:in-location (or (and (contains? location :discard)
(in-discard? card))
(and (contains? location :set-aside)
(in-set-aside? card))
(and (contains? location :hand)
(in-hand? card)))
:test-condition true)
Expand Down Expand Up @@ -1176,9 +1178,10 @@
(wait-for
(unregister-expired-durations state nil (make-eid state eid) (conj durations duration) context-maps)
;; update the disabled-card registry here
(update-disabled-cards state)
(update-disabled-cards state)
;; c: Check winning or tying by agenda points
(check-win-by-agenda state)
(when (check-win-by-agenda state)
(trigger-event state nil :win))
;; d: uniqueness/console check
(wait-for
(check-unique-and-consoles state nil (make-eid state eid))
Expand Down
7 changes: 7 additions & 0 deletions src/cljc/game/core/card.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@
(= (get-zone card) #?(:clj [:play-area]
:cljs ["play-area"])))

(defn in-destroyed?
"Checks if the specific card is in a set-aside area."
[card]
(= (get-zone card) #?(:clj [:destroyed]
:cljs ["destroyed"])))

(defn in-set-aside?
"Checks if the specific card is in a set-aside area."
[card]
Expand Down Expand Up @@ -469,6 +475,7 @@
(in-current? card)
(in-play-area? card)
(in-rfg? card)
(in-destroyed? card)
(set-aside-visible? card side)
(if (= side :corp)
;; public runner cards:
Expand Down
8 changes: 6 additions & 2 deletions src/cljs/nr/gameboard/board.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2169,19 +2169,23 @@
[:div.right-inner-leftpane
(let [op-rfg (r/cursor game-state [op-side :rfg])
op-set-aside (r/cursor game-state [op-side :set-aside])
op-destroyed (r/cursor game-state [op-side :destroyed])
op-current (r/cursor game-state [op-side :current])
op-play-area (r/cursor game-state [op-side :play-area])
me-rfg (r/cursor game-state [me-side :rfg])
me-set-aside (r/cursor game-state [me-side :set-aside])
me-destroyed (r/cursor game-state [me-side :destroyed])
me-current (r/cursor game-state [me-side :current])
me-play-area (r/cursor game-state [me-side :play-area])]
[:div
(when-not (:replay @game-state)
[starting-timestamp @start-date @timer])
[rfg-view op-rfg (tr [:game.rfg "Removed from the game"]) true]
[rfg-view me-rfg (tr [:game.rfg "Removed from the game"]) true]
[rfg-view op-set-aside (tr [:game.set-aside "Set aside"]) true]
[rfg-view me-set-aside (tr [:game.set-aside "Set aside"]) true]
[rfg-view op-set-aside (tr [:game.set-aside "Set aside"]) false]
[rfg-view me-set-aside (tr [:game.set-aside "Set aside"]) false]
[rfg-view op-destroyed (tr [:game.destroyed "Destroyed"]) false]
[rfg-view me-destroyed (tr [:game.destroyed "Destroyed"]) false]
[play-area-view op-user (tr [:game.play-area "Play Area"]) op-play-area]
[play-area-view me-user (tr [:game.play-area "Play Area"]) me-play-area]
[rfg-view op-current (tr [:game.current "Current"]) false]
Expand Down
27 changes: 27 additions & 0 deletions test/clj/game/cards/assets_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3274,6 +3274,33 @@
(click-prompt state :corp "8")
(is (= (+ credits 8) (:credit (get-corp))) "Corp should gain 8 credits from Long-Term Investment ability")))))

(deftest lt-todachine
(do-game
(new-game {:corp {:hand ["Lt. Todachine" "Vanilla"]}})
(play-from-hand state :corp "Lt. Todachine" "New remote")
(play-from-hand state :corp "Vanilla" "HQ")
(rez state :corp (get-content state :remote1 0))
(rez state :corp (get-ice state :hq 0))
(is (= 1 (count-tags state)) "Runner has 1 tag")))

(deftest lt-todachine-2
(do-game
(new-game {:corp {:hand ["Lt. Todachine 2" "Vanilla"]
:deck [(qty "IPO" 3)]}
:runner {:hand ["Jailbreak"]}})
(play-from-hand state :corp "Lt. Todachine 2" "New remote")
(play-from-hand state :corp "Vanilla" "HQ")
(rez state :corp (get-content state :remote1 0))
(rez state :corp (get-ice state :hq 0))
(is (= 1 (count-tags state)) "Runner has 1 tag")
(take-credits state :corp)
(play-from-hand state :runner "Jailbreak")
(click-prompt state :runner "R&D")
(run-continue-until state :success)
(click-prompt state :runner "No action")
(is (no-prompt? state :runner) "No prompt")
(is (not (:run @state)) "Access ended after 1 card seen - todachine did his work")))

(deftest malia-z0l0k4
;; Malia Z0L0K4 - blank an installed non-virtual runner resource
(do-game
Expand Down
18 changes: 18 additions & 0 deletions test/clj/game/cards/resources_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5570,6 +5570,24 @@
(run-continue state)
(is (= (+ credits 5 2) (:credit (get-runner))) "Runner gains 5 from Dirty Laundry and 2 from Security Testing"))))

(deftest shadow-team-full-test
(do-game
(new-game {:runner {:hand ["Rezeki"]
:deck ["Shadow Team" "Shadow Team"]}})
(take-credits state :corp)
(click-draw state :runner)
(click-draw state :runner)
(is (= "Shadow Team"
(:title (get-resource state 0))
(:title (get-resource state 1)))
"installed 2 teams")
(run-on state :hq)
(click-card state :runner "Rezeki")
(is (no-prompt? state :runner) "Only forced to discard one card!")
(run-continue-until state :success)
(is (= ["Shadow Team" "Shadow Team"] (map :title (get-in @state [:runner :destroyed])))
"Destroyed both shadow teams")))

(deftest slipstream-there-is-an-ice-at-the-correct-position
;; There is an ice at the correct position
(do-game
Expand Down
Loading