use forge_foundation::ZoneType;
use super::EffectContext;
use crate::agent::GameLogEvent;
use crate::event::RunParams;
use crate::ids::{CardId, PlayerId};
use crate::spellability::{build_spell_ability, SpellAbility, StackEntry};
use crate::trigger::TriggerType;
pub fn cast_card_from_effect(
ctx: &mut EffectContext,
card_id: CardId,
controller: PlayerId,
without_mana_cost: bool,
label: &str,
) -> bool {
let abilities = ctx.game.card(card_id).abilities.clone();
let ability_text = match abilities.first() {
Some(text) => text.clone(),
None => return false,
};
let mut spell_sa = build_spell_ability(ctx.game, card_id, &ability_text, controller);
spell_sa.is_spell = true;
spell_sa.ir.cast_from_play_effect = true;
if without_mana_cost {
if let Some(ref mut cost) = spell_sa.pay_costs {
cost.parts
.retain(|part| !matches!(part, crate::cost::CostPart::Mana { .. }));
}
spell_sa.ir.without_mana_cost = true;
}
if let Some(ref mut cost) = spell_sa.pay_costs {
cost.mandatory = true;
}
spell_sa.setup_targets(ctx.game, ctx.agents, ctx.mana_pools);
push_spell_to_stack(ctx, card_id, spell_sa, label);
true
}
pub fn get_basic_spells(ctx: &EffectContext, card_id: CardId) -> Vec<String> {
let card = ctx.game.card(card_id);
let mut spells = Vec::new();
for ability_text in &card.abilities {
if ability_text.contains("AB$") || ability_text.contains("T$") {
continue;
}
if ability_text.contains("LandAbility") {
continue;
}
spells.push(ability_text.clone());
}
if spells.is_empty() && card.is_permanent() {
if let Some(first) = card.abilities.first() {
spells.push(first.clone());
}
}
spells
}
pub fn offer_cast_or_alternative(
ctx: &mut EffectContext,
card_id: CardId,
controller: PlayerId,
cast_label: &str,
alt_label: &str,
) -> bool {
let card_name = ctx.game.card(card_id).card_name.clone();
ctx.agents[controller.index()].snapshot_state(ctx.game, ctx.mana_pools);
ctx.agents[controller.index()].confirm_action(
controller,
Some("CastFromEffect"),
&format!("{}: {} or {}?", card_name, cast_label, alt_label),
&[cast_label.to_string(), alt_label.to_string()],
Some(card_id),
None,
)
}
fn push_spell_to_stack(
ctx: &mut EffectContext,
card_id: CardId,
spell_sa: SpellAbility,
label: &str,
) {
let controller = spell_sa.activating_player;
let is_creature = ctx.game.card(card_id).is_creature();
let is_permanent = ctx.game.card(card_id).is_permanent();
let cast_zone = Some(ctx.game.card(card_id).zone);
let card_name = ctx.game.card(card_id).card_name.clone();
let chosen_target = spell_sa.target_chosen.target_card;
let entry = StackEntry {
id: 0,
spell_ability: spell_sa,
is_pending_cast: false,
is_creature_spell: is_creature,
is_permanent_spell: is_permanent,
cast_from_zone: cast_zone,
optional_trigger_decider: None,
optional_trigger_description: None,
optional_trigger_source_name: None,
};
let trigger_sa = entry.spell_ability.clone();
ctx.game.stack.push(entry);
ctx.move_card(card_id, ZoneType::Stack, controller);
ctx.game.player_record_spell_cast(controller, card_id);
ctx.trigger_handler.run_trigger(
TriggerType::SpellCast,
RunParams {
spell_card: Some(card_id),
spell_controller: Some(controller),
source_sa: Some(trigger_sa.clone()),
..Default::default()
},
false,
);
super::emit_targeting_triggers(ctx, card_id, &trigger_sa);
let mut event = GameLogEvent::stack(format!("{}: cast {}", label, card_name))
.with_player(controller)
.with_source_card(card_id);
if let Some(target_id) = chosen_target {
event = event.with_target_card(target_id);
}
crate::agent::notify_all_agents(ctx.agents, event);
}