manabrew_engine/ability/effects/
copy_spell_ability_effect.rs1use super::EffectContext;
2use crate::event::RunParams;
3use crate::replacement::replacement_handler::{apply_replacements, ReplacementEvent};
4use crate::replacement::ReplacementResult;
5use crate::spellability::SpellAbility;
6use crate::trigger::TriggerType;
7
8pub fn build_spell_ability(sa: &mut SpellAbility) {
12 if sa.uses_targeting() {
13 if let Some(ref mut tr) = sa.target_restrictions {
14 tr.tgt_zone = vec![forge_foundation::ZoneType::Stack];
15 }
16 }
17}
18
19#[manabrew_engine_macros::spell_effect(CopySpellAbilityEffect)]
34fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
35 let controller = sa.activating_player;
36
37 let mut event = ReplacementEvent::CopySpell {
39 player: controller,
40 count: 1,
41 };
42 let result = apply_replacements(ctx.game, &mut event);
43 if result == ReplacementResult::Skipped || result == ReplacementResult::Replaced {
44 return;
45 }
46
47 let original = if let Some(defined) = sa.defined() {
48 crate::ability::ability_utils::get_defined_spell_abilities(defined, sa, ctx.game)
49 .into_iter()
50 .next()
51 } else {
52 let stack_entries: Vec<_> = ctx.game.stack.iter().collect();
53 stack_entries.iter().rev().find_map(|entry| {
54 if Some(entry.id) != sa.ir.stack_id {
55 Some(entry.spell_ability.clone())
56 } else {
57 None
58 }
59 })
60 };
61
62 let original = match original {
63 Some(spell) => spell,
64 None => return,
65 };
66 if crate::card::card_factory::spell_ability_cant_be_copied(&ctx.game.cards, &original) {
67 return;
68 }
69
70 let copy = crate::card::card_factory::copy_spell_ability(&original, controller);
72
73 let copy_entry = crate::spellability::StackEntry {
75 id: 0, spell_ability: copy,
77 is_pending_cast: false,
78 is_creature_spell: original.is_spell
79 && original
80 .source
81 .is_some_and(|cid| ctx.game.card(cid).is_creature()),
82 is_permanent_spell: original.is_spell
83 && original
84 .source
85 .is_some_and(|cid| ctx.game.card(cid).is_permanent()),
86 cast_from_zone: None,
87 optional_trigger_decider: None,
88 optional_trigger_description: None,
89 optional_trigger_source_name: None,
90 };
91
92 let trigger_sa = copy_entry.spell_ability.clone();
93 ctx.game.stack.push(copy_entry);
94 if let Some(source_id) = trigger_sa.source {
95 ctx.trigger_handler.run_trigger(
96 TriggerType::SpellCopied,
97 RunParams {
98 spell_card: Some(source_id),
99 spell_controller: Some(controller),
100 source_sa: Some(trigger_sa.clone()),
101 ..Default::default()
102 },
103 false,
104 );
105 super::emit_targeting_triggers(ctx, source_id, &trigger_sa);
106 }
107}