Skip to main content

manabrew_engine/ability/effects/
restart_game_effect.rs

1//! RestartGame — restart the game (Karn Liberated ultimate).
2//! Ported from Java's RestartGameEffect: resets all game state, moves all cards
3//! back to libraries, resets life totals, clears counters, and restarts.
4
5use forge_foundation::ZoneType;
6
7use super::EffectContext;
8use crate::ids::CardId;
9use crate::spellability::SpellAbility;
10
11/// Stack text override. Mirrors Java `RestartGameEffect.getStackDescription`.
12pub fn get_stack_description(sa: &SpellAbility) -> String {
13    sa.ir
14        .spell_description_text
15        .clone()
16        .unwrap_or_else(|| "Restart the game.".to_string())
17}
18
19/// Struct form of this effect so it can participate in the
20/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
21/// `RestartGameEffect` class extending `SpellAbilityEffect`.
22#[manabrew_engine_macros::spell_effect(RestartGameEffect)]
23fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
24    let activator = sa.activating_player;
25
26    // Get all player IDs
27    let player_ids: Vec<_> = ctx.game.players.iter().map(|p| p.id).collect();
28
29    // Collect cards to move back to library (from all restart zones)
30    let restart_zones = [
31        ZoneType::Battlefield,
32        ZoneType::Hand,
33        ZoneType::Graveyard,
34        ZoneType::Exile,
35    ];
36
37    // Optional: RestrictFromZone — leave some cards in a zone
38    let leave_zone = sa.ir.restrict_from_zone;
39
40    for &player_id in &player_ids {
41        // Reset player state
42        ctx.game.player_reset_for_restart(player_id);
43
44        // Collect all cards from restart zones for this player
45        let cards_to_move: Vec<CardId> = ctx
46            .game
47            .cards
48            .iter()
49            .filter(|c| {
50                c.owner == player_id
51                    && restart_zones.contains(&c.zone)
52                    && (leave_zone != Some(c.zone))
53            })
54            .map(|c| c.id)
55            .collect();
56
57        // Move all collected cards to library
58        for card_id in cards_to_move {
59            // Reset card state
60            ctx.game.card_mut(card_id).set_tapped(false);
61            ctx.game.card_mut(card_id).set_face_down(false);
62            ctx.game.card_mut(card_id).clear_counters();
63            ctx.game.card_mut(card_id).set_power_modifier(0);
64            ctx.game.card_mut(card_id).set_toughness_modifier(0);
65            ctx.game.card_mut(card_id).set_controller(player_id);
66            ctx.game.card_mut(card_id).clear_intrinsic_keywords();
67            ctx.move_card(card_id, ZoneType::Library, player_id);
68        }
69
70        // Shuffle library
71        ctx.game
72            .shuffle_zone_cards(ZoneType::Library, player_id, ctx.rng);
73    }
74
75    // Reset global game state
76    ctx.game.is_night = false;
77    ctx.game.day_night_started = false;
78
79    // Set active player to the activator (Karn's controller restarts)
80    let _ = activator;
81}