Skip to content
Merged
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
19 changes: 19 additions & 0 deletions crates/engine/src/game/effects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6669,6 +6669,25 @@ pub(crate) fn publish_fresh_tracked_set(
set_id
}

/// CR 608.2c + CR 701.62a (#7467): publish `object_id` as the chain's fresh
/// tracked set iff the parked continuation actually reads one and the object
/// really sits on the battlefield — mirroring the resolver harvest's
/// destination filter, so an entry replacement that redirected the card
/// elsewhere publishes nothing. Shared by the two seams a manifest-dread
/// creature can finish entering from: the synchronous `ManifestDreadChoice`
/// arm and the paused-entry `RevealRestPile` completion.
pub(crate) fn publish_battlefield_object_for_pending_continuation(
state: &mut GameState,
object_id: ObjectId,
) {
let continuation_consumes_tracked_set = state
.active_ability_continuation()
.is_some_and(|continuation| chain_references_tracked_set(&continuation.chain));
if continuation_consumes_tracked_set && state.battlefield.contains(&object_id) {
publish_fresh_tracked_set(state, vec![object_id]);
}
}

/// CR 603.7 + CR 109.5: Returns `true` when the effect resolves an acting
/// subject relative to the parent target — i.e., any effect-target slot
/// reachable via [`effect_target_filter`] contains
Expand Down
4 changes: 4 additions & 0 deletions crates/engine/src/game/effects/reveal_until.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ pub fn resolve(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: Some(ability.source_id),
manifested_for_continuation: None,
},
);
return Ok(());
Expand Down Expand Up @@ -315,6 +316,7 @@ pub fn resolve(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: Some(ability.source_id),
manifested_for_continuation: None,
},
);
return Ok(());
Expand Down Expand Up @@ -349,6 +351,7 @@ pub fn resolve(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: Some(ability.source_id),
manifested_for_continuation: None,
},
);
return Ok(());
Expand Down Expand Up @@ -390,6 +393,7 @@ pub fn resolve(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: Some(ability.source_id),
manifested_for_continuation: None,
},
);
return Ok(());
Expand Down
6 changes: 3 additions & 3 deletions crates/engine/src/game/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19347,9 +19347,9 @@ mod stage2_injector_tests {
// resume/finalization helpers are above this existing producer;
// they do not mint an optional-effect prompt. The census above
// still finds exactly the same five production producers.
"game/effects/mod.rs:7325".to_string(),
"game/effects/mod.rs:7402".to_string(),
"game/effects/mod.rs:11229".to_string(),
"game/effects/mod.rs:7344".to_string(),
"game/effects/mod.rs:7421".to_string(),
"game/effects/mod.rs:11248".to_string(),
// UNMOVED across the rebase, and that is itself evidence the SET did not
// move: a census that had gained or lost a producer would not leave this
// entry both byte-identical AND at the same coordinate.
Expand Down
29 changes: 29 additions & 0 deletions crates/engine/src/game/engine_resolution_choices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,10 @@ pub(super) fn handle_resolution_choice(
clear_markers: cards.clone(),
publish_tracked_set: None,
emit_reveal_until_resolved: None,
// #7467 review round 2: the entry paused, so the
// publish below never runs — the completion drain
// publishes instead, once the entry completed.
manifested_for_continuation: Some(manifest_id),
},
);
return Ok(ResolutionChoiceOutcome::WaitingFor(
Expand All @@ -1864,6 +1868,15 @@ pub(super) fn handle_resolution_choice(
}
}

// CR 608.2c + CR 701.62a (#7467): the manifested creature enters
// from THIS continuation, so its `ZoneChanged` never reaches the
// resolver-side harvest — the chain's tracked set was published
// EMPTY when the head parked. Re-publish it here so a chained
// consumer ("Manifest dread X times, then put X +1/+1 counters on
// each of those creatures" — Valgavoth's Onslaught) binds the
// creature, the same seam as the search-choice publish above.
effects::publish_battlefield_object_for_pending_continuation(state, manifest_id);

// CR 614.6 + CR 701.62a class: route the non-manifested cards to the
// graveyard through the simultaneous-move batch so each card's own
// `Moved` redirects (Rest in Peace / Leyline of the Void: "would be
Expand Down Expand Up @@ -2096,6 +2109,7 @@ pub(super) fn handle_resolution_choice(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
},
);
return Ok(ResolutionChoiceOutcome::WaitingFor(
Expand Down Expand Up @@ -2160,6 +2174,7 @@ pub(super) fn handle_resolution_choice(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
}),
events,
) {
Expand Down Expand Up @@ -3519,6 +3534,7 @@ pub(super) fn handle_resolution_choice(
clear_markers: Vec::new(),
publish_tracked_set: None,
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
},
);
return Ok(ResolutionChoiceOutcome::WaitingFor(
Expand Down Expand Up @@ -3646,6 +3662,7 @@ pub(super) fn handle_resolution_choice(
clear_markers: Vec::new(),
publish_tracked_set: Some(kept.clone()),
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
},
);
return Ok(ResolutionChoiceOutcome::WaitingFor(
Expand Down Expand Up @@ -3708,6 +3725,7 @@ pub(super) fn handle_resolution_choice(
clear_markers: Vec::new(),
publish_tracked_set: Some(publish_set),
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
},
);
return Ok(ResolutionChoiceOutcome::WaitingFor(
Expand Down Expand Up @@ -7327,6 +7345,7 @@ fn route_kept_card_or_defer(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved: None,
manifested_for_continuation: None,
},
);
Some(ResolutionChoiceOutcome::WaitingFor(
Expand Down Expand Up @@ -7999,6 +8018,7 @@ pub(crate) fn run_batch_completion(
clear_markers,
publish_tracked_set,
emit_reveal_until_resolved,
manifested_for_continuation,
} => {
// The dig path (`publish_tracked_set.is_some()`) routes the rest pile
// through `route_rest_partition` (ordered library bottom); the
Expand Down Expand Up @@ -8027,6 +8047,7 @@ pub(crate) fn run_batch_completion(
clear_markers,
publish_tracked_set,
emit_reveal_until_resolved,
manifested_for_continuation,
},
);
return crate::game::zone_pipeline::BatchMoveResult::NeedsChoice;
Expand All @@ -8047,6 +8068,7 @@ pub(crate) fn run_batch_completion(
clear_markers,
publish_tracked_set: None,
emit_reveal_until_resolved,
manifested_for_continuation,
};
return effects::reveal_until::move_rest_then(
state,
Expand Down Expand Up @@ -8079,6 +8101,13 @@ pub(crate) fn run_batch_completion(
subject: None,
});
}
// CR 608.2c + CR 701.62a (#7467): the paused manifest entry has
// completed by now — publish its object for the parked consumer,
// the deferred mirror of the synchronous `ManifestDreadChoice`
// publish (same gate, same battlefield filter).
if let Some(manifested) = manifested_for_continuation {
effects::publish_battlefield_object_for_pending_continuation(state, manifested);
}
finish_with_continuation(state, player, events);
crate::game::zone_pipeline::BatchMoveResult::Done
}
Expand Down
10 changes: 10 additions & 0 deletions crates/engine/src/types/game_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5338,6 +5338,16 @@ pub enum BatchCompletion {
/// must too. `None` for the kept-choice / dig paths, which emit their own
/// `EffectResolved` before the pause (or rely on the continuation).
emit_reveal_until_resolved: Option<ObjectId>,
/// CR 608.2c + CR 701.62a (#7467): a paused manifest-dread entry's
/// chosen object. The completion drain publishes it as the chain's
/// fresh tracked set — only once the entry has actually finished
/// (battlefield gate) and right before the parked consumer drains —
/// the deferred mirror of the synchronous `ManifestDreadChoice`
/// publish. Deliberately separate from `publish_tracked_set`, whose
/// presence doubles as the dig-vs-reveal ROUTING selector for the rest
/// pile. `None` for every non-manifest rest pile.
#[serde(default)]
manifested_for_continuation: Option<ObjectId>,
},
/// CR 608.2c + CR 616.1: The rest half of a deterministic mass Dig settled
/// after a replacement choice. Resume its selected-card delivery only now,
Expand Down
Loading
Loading