manabrew_engine/ability/effects/
attach_effect.rs1use forge_foundation::ZoneType;
2
3use super::EffectContext;
4use crate::agent::types::GameEntity;
5use crate::player::player_controller::PlayerController;
6use crate::replacement::replacement_handler::{apply_replacements, ReplacementEvent};
7use crate::replacement::ReplacementResult;
8
9#[manabrew_engine_macros::spell_effect(AttachEffect)]
16fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
17 let aura_id = match sa.source {
19 Some(s) => s,
20 None => return,
21 };
22 let chooser = sa
23 .chooser()
24 .and_then(|defined| {
25 crate::ability::ability_utils::resolve_defined_players_with_sa(
26 defined,
27 sa,
28 sa.activating_player,
29 ctx.game,
30 )
31 .into_iter()
32 .next()
33 })
34 .unwrap_or(sa.activating_player);
35
36 let mut candidates: Vec<GameEntity> = Vec::new();
37 if let Some(target_card) = sa.target_chosen.target_card {
38 candidates.push(GameEntity::Card(target_card));
39 }
40 if let Some(target_player) = sa.target_chosen.target_player {
41 candidates.push(GameEntity::Player(target_player));
42 }
43 if candidates.is_empty() {
44 if let Some(defined) = sa.defined() {
45 candidates.extend(
46 crate::ability::ability_utils::get_defined_cards(
47 ctx.game,
48 Some(aura_id),
49 defined,
50 Some(sa.activating_player),
51 )
52 .into_iter()
53 .map(GameEntity::Card),
54 );
55 candidates.extend(
56 crate::ability::ability_utils::resolve_defined_players_with_sa(
57 defined,
58 sa,
59 sa.activating_player,
60 ctx.game,
61 )
62 .into_iter()
63 .map(GameEntity::Player),
64 );
65 }
66 }
67 if candidates.is_empty() {
68 return;
69 }
70 let chosen = {
71 let agent = ctx.agents[chooser.index()].as_mut();
72 let mut controller = PlayerController::new(ctx.game, chooser, agent);
73 controller.snapshot_state(ctx.mana_pools);
74 controller.choose_single_entity_for_effect(&candidates)
75 };
76 let chosen = match chosen {
77 Some(chosen) => chosen,
78 None => return,
79 };
80 let target = match chosen {
81 GameEntity::Card(c) => c,
82 GameEntity::Player(_) => return,
83 };
84
85 if ctx.game.card(aura_id).zone != ZoneType::Battlefield
87 || ctx.game.card(target).zone != ZoneType::Battlefield
88 {
89 return;
90 }
91 if crate::staticability::static_ability_cant_attach::cant_attach(
92 &ctx.game.cards,
93 ctx.game.card(aura_id),
94 ctx.game.card(target),
95 false,
96 ) {
97 return;
98 }
99
100 let mut event = ReplacementEvent::Attached {
102 card: aura_id,
103 target,
104 };
105 let result = apply_replacements(ctx.game, &mut event);
106 if result == ReplacementResult::Skipped || result == ReplacementResult::Replaced {
107 return;
108 }
109
110 ctx.game.attach_to(aura_id, target);
111
112 ctx.trigger_handler.run_trigger(
114 crate::trigger::TriggerType::Attached,
115 crate::event::RunParams {
116 card: Some(aura_id),
117 ..Default::default()
118 },
119 false,
120 );
121}