Skip to content

Commit

Permalink
Merge pull request #7934 from NBKelly/forced-encounter-fix
Browse files Browse the repository at this point in the history
Forced encounter fix
  • Loading branch information
NBKelly authored Jan 31, 2025
2 parents 83f35be + 6612b52 commit b085a66
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/clj/game/cards/hardware.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@
{:events [{:event :subroutines-broken
:optional
{:req (req
(let [pred (every-pred :all-subs-broken :outermost :during-run)]
(let [pred (every-pred :all-subs-broken :outermost :during-run :on-attacked-server)]
(and (pred context)
(get-card state (:ice context))
(first-event? state side :subroutines-broken #(pred (first %))))))
Expand Down
4 changes: 2 additions & 2 deletions src/clj/game/core/ice.clj
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,7 @@
(defn all-subs-broken?
[ice]
(let [subroutines (:subroutines ice)]
(and (seq subroutines)
(every? :broken subroutines))))
(every? :broken subroutines)))

(defn any-subs-broken-by-card?
[ice card]
Expand Down Expand Up @@ -539,6 +538,7 @@
[state ice broken-subs breaker]
{:outermost (when-let [server-ice (:ices (card->server state ice))] (same-card? ice (last server-ice)))
:during-run (some? (:run @state))
:on-attacked-server (= (get-in @state [:run :server]) [(second (:zone ice))])
:all-subs-broken (all-subs-broken? ice)
:broken-subs broken-subs
;; enough info to backtrack and find breakers without bloating the gamestate
Expand Down
33 changes: 27 additions & 6 deletions src/clj/game/core/runs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[game.core.engine :refer [checkpoint end-of-phase-checkpoint register-pending-event pay queue-event resolve-ability trigger-event trigger-event-simult]]
[game.core.flags :refer [can-run? cards-can-prevent? clear-run-register! get-prevent-list prevent-jack-out]]
[game.core.gaining :refer [gain-credits]]
[game.core.ice :refer [active-ice? get-current-ice get-run-ices update-ice-strength reset-all-ice reset-all-subs! set-current-ice]]
[game.core.ice :refer [active-ice? break-subs-event-context get-current-ice get-run-ices update-ice-strength reset-all-ice reset-all-subs! set-current-ice]]
[game.core.mark :refer [is-mark?]]
[game.core.payment :refer [build-cost-string build-spend-msg can-pay? merge-costs ->c]]
[game.core.prompts :refer [clear-run-prompts clear-wait-prompt show-run-prompts show-prompt show-wait-prompt]]
Expand Down Expand Up @@ -334,10 +334,19 @@
(checkpoint state side eid)))))})

(defn encounter-ice
;; note: as far as I can tell, this deliberately leaves on open eid (the run eid).
;; Attempting to change that breaks a very large number of tests, so I'm leaving this
;; note here to remind me when I look at this later. -nbk, 2025
;;
;; TODO: rewrite forced encounter to use it's own version of encounter-ice,
;; then we can close the eids on this. Right now, closing the eids breaks
;; forced encounters and nothing else.
[state side eid ice]
(swap! state update :encounters conj {:eid eid
:ice ice})
(check-auto-no-action state)
;; step 6.9.3a: The encounter begins. Conditions relating to the Runner encountering
;; this ice are met (this is on-encounter effects, etc)
(let [on-encounter (:on-encounter (card-def ice))
applied-encounters (get-effects state nil :gain-encounter-ability ice)
all-encounters (map #(preventable-encounter-abi % ice) (remove nil? (conj applied-encounters on-encounter)))]
Expand All @@ -349,8 +358,18 @@
(make-eid state)
{:cancel-fn (fn [state]
(should-end-encounter? state side ice))})
(when (should-end-encounter? state side ice)
(encounter-ends state side eid)))))
(if (should-end-encounter? state side ice)
(encounter-ends state side eid)
;; step 6.9.3b: if there are no subroutines on the ice,
;; the runner is considered to have broken all the subroutines on this ice.
;; This should fire an event, so it can get picked up with cards like hippo
;; or knifed.
(when-let [c-ice (get-current-ice state)]
(when (and (same-card? c-ice ice) (zero? (count (:subroutines c-ice))))
(wait-for
(trigger-event-simult state side :subroutines-broken nil (break-subs-event-context state c-ice [] (get-in @state [:runner :basic-action-card])))
(when (should-end-encounter? state side ice)
(encounter-ends state side eid)))))))))

(defmethod start-next-phase :encounter-ice
[state side _]
Expand All @@ -375,9 +394,11 @@
(if (and (not (:run @state))
(empty? (:encounters @state)))
(forced-encounter-cleanup state :runner eid)
(do (when (and new-state (= new-state (get-in @state [:run :phase])))
(set-phase state old-state))
(effect-completed state side eid)))))))
(do
(when (and new-state (= new-state (get-in @state [:run :phase])))
(set-phase state old-state))
(set-current-ice state)
(effect-completed state side eid)))))))

(defmethod continue :encounter-ice
[state side _]
Expand Down
24 changes: 24 additions & 0 deletions test/clj/game/cards/hardware_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,30 @@
(click-prompt state :runner "End the run")
(is (no-prompt? state :runner) "No Hippo prompt on later ice")))

(deftest hippo-interaction-with-konjin
(do-game
(new-game {:corp {:hand ["Ice Wall" "Konjin"]}
:runner {:hand ["Hippo" "Eater"] :credits 15}})
(play-from-hand state :corp "Ice Wall" "HQ")
(play-from-hand state :corp "Konjin" "R&D")
(rez state :corp (get-ice state :hq 0))
(rez state :corp (get-ice state :rd 0))
(take-credits state :corp)
(play-from-hand state :runner "Hippo")
(play-from-hand state :runner "Eater")
(run-on state :rd)
(run-continue state :encounter-ice)
(is (= "Choose an amount to spend for Konjin" (:msg (prompt-map :corp))) "Psi Game")
(click-prompt state :corp "0 [Credits]")
(click-prompt state :runner "1 [Credits]")
(is (= "Choose a piece of ice" (:msg (prompt-map :corp))) "Prompt to choose Ice")
(click-card state :corp "Ice Wall")
(auto-pump-and-break state (get-program state 0))
(is (no-prompt? state :runner) "Not prompted to use hippo (we're not on the attacked server)")
(run-continue state :encounter-ice)
(click-prompt state :runner "Yes")
(is (= "Konjin" (-> (get-corp) :discard first :title)) "Trashed konjin with hippo (you have 'broken all subs' when the encounter phase ends)")))

(deftest hippocampic-mechanocytes
;; Hippocampic Mechanocytes
(do-game
Expand Down
30 changes: 30 additions & 0 deletions test/clj/game/cards/ice_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4398,6 +4398,36 @@
(fire-subs state (refresh iw))
(is (not (:run @state)) "The run should have ended"))))

(deftest konjin-target-ice-gets-trashed
;; Return to encountering Konjin after forced encounter
(do-game
(new-game {:corp {:hand ["Ice Wall" "Konjin"]}
:runner {:hand ["Arruaceiras Crew"]}})
(play-from-hand state :corp "Ice Wall" "HQ")
(play-from-hand state :corp "Konjin" "R&D")
(take-credits state :corp)
(play-from-hand state :runner "Arruaceiras Crew")
(let [konjin (get-ice state :rd 0)
iw (get-ice state :hq 0)]
(rez state :corp konjin)
(rez state :corp iw)
(run-on state :rd)
(run-continue state)
(is (= (refresh konjin) (core/get-current-ice state)) "The runner should be encountering Konjin")
(is (= "Choose an amount to spend for Konjin" (:msg (prompt-map :corp))) "Psi Game")
(click-prompt state :corp "0 [Credits]")
(click-prompt state :runner "1 [Credits]")
(is (= "Choose a piece of ice" (:msg (prompt-map :corp))) "Prompt to choose Ice")
(click-card state :corp iw)
(is (= (refresh iw) (core/get-current-ice state)) "The runner should be encountering Ice Wall")
(card-ability state :runner (get-resource state 0) 0)
(card-ability state :runner (get-resource state 0) 1)
(is (= "Ice Wall" (-> (get-corp) :discard first :title)) "Trashed ice wall")
(run-continue state :encounter-ice)
(is (= (refresh konjin) (core/get-current-ice state)) "The runner should be back to encountering Konjin")
(is (no-prompt? state :runner) "No repeat psi prompt")
(is (no-prompt? state :corp) "No repeat psi prompt"))))

(deftest lockdown
;; Lockdown - Prevent Runner from drawing cards for the rest of the turn
(do-game
Expand Down

0 comments on commit b085a66

Please sign in to comment.