Skip to main content

manabrew_engine/ability/effects/
peek_and_reveal_effect.rs

1use forge_foundation::ZoneType;
2
3use super::{resolve_numeric_svar, EffectContext};
4
5/// Mirrors Java's `PeekAndRevealEffect.java`.
6#[manabrew_engine_macros::spell_effect(PeekAndRevealEffect)]
7fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
8    let num = if sa.ir.peek_amount_text.is_some() {
9        resolve_numeric_svar(ctx.game, sa, "PeekAmount", 1)
10    } else {
11        resolve_numeric_svar(ctx.game, sa, "NumCards", 1)
12    }
13    .max(0) as usize;
14    let remember_revealed = sa.ir.remember_revealed;
15    let imprint_revealed = sa.ir.imprint_revealed;
16    let remember_peeked = sa.ir.remember_peeked;
17    let reveal_optional = sa.ir.reveal_optional;
18
19    let peeking_player = sa.activating_player;
20    let no_peek = sa.ir.no_peek;
21    let no_reveal = sa.ir.no_reveal;
22    let src_zone = sa.ir.source_zone.unwrap_or(ZoneType::Library);
23
24    let src_zone_players =
25        crate::ability::spell_ability_effect::get_defined_players_or_targeted(ctx.game, sa);
26    let players: Vec<_> = if src_zone_players.is_empty() {
27        vec![peeking_player]
28    } else {
29        src_zone_players
30    };
31
32    for zone_to_peek in players {
33        let peeked: Vec<_> = {
34            let zone_cards = ctx.game.cards_in_zone(src_zone, zone_to_peek);
35            let take = num.min(zone_cards.len());
36            let start = zone_cards.len().saturating_sub(take);
37            zone_cards[start..].to_vec()
38        };
39
40        let revealable: Vec<_> = if let Some(valid) = sa.ir.reveal_valid_text.as_deref() {
41            peeked
42                .iter()
43                .copied()
44                .filter(|&cid| {
45                    crate::ability::ability_utils::matches_valid_cards_for_sa(
46                        ctx.game,
47                        sa,
48                        ctx.game.card(cid),
49                        sa.ir.reveal_valid_selector.as_ref(),
50                        valid,
51                    )
52                })
53                .collect()
54        } else {
55            peeked.clone()
56        };
57
58        if !no_peek && !peeked.is_empty() {
59            ctx.agents[peeking_player.index()].reveal_cards(
60                ctx.game,
61                peeking_player,
62                &peeked,
63                src_zone,
64                zone_to_peek,
65                sa.source.map(|cid| ctx.game.card(cid).card_name.as_str()),
66            );
67        }
68
69        let mut do_reveal = !no_reveal && !revealable.is_empty();
70        if do_reveal && reveal_optional {
71            do_reveal = ctx.agents[peeking_player.index()].confirm_action(
72                peeking_player,
73                None,
74                "Reveal the card to other players?",
75                &[],
76                sa.source,
77                sa.api,
78            );
79        }
80
81        if do_reveal {
82            let source_name = sa.source.map(|cid| ctx.game.card(cid).card_name.clone());
83            for agent in ctx.agents.iter_mut() {
84                agent.reveal_cards(
85                    ctx.game,
86                    peeking_player,
87                    &revealable,
88                    src_zone,
89                    zone_to_peek,
90                    source_name.as_deref(),
91                );
92            }
93            if let Some(source_id) = sa.source {
94                if remember_revealed {
95                    for &card_id in &revealable {
96                        ctx.game.card_mut(source_id).add_remembered_card(card_id);
97                    }
98                }
99                if imprint_revealed {
100                    for &card_id in &revealable {
101                        ctx.game.card_mut(source_id).add_imprinted_card(card_id);
102                    }
103                }
104            }
105        } else if remember_peeked {
106            if let Some(source_id) = sa.source {
107                for &card_id in &revealable {
108                    ctx.game.card_mut(source_id).add_remembered_card(card_id);
109                }
110            }
111        }
112    }
113}