package magic.model.event; import java.util.regex.Matcher; import java.util.regex.Pattern; import magic.model.MagicAbility; import magic.model.MagicCardDefinition; import magic.model.MagicChangeCardDefinition; import magic.model.MagicGame; import magic.model.MagicLocationType; import magic.model.MagicMessage; import magic.model.MagicPayedCost; import magic.model.action.ChangeCardDestinationAction; import magic.model.action.EnqueueTriggerAction; import magic.model.choice.MagicChoice; import magic.model.choice.MagicOrChoice; import magic.model.stack.MagicCardOnStack; public abstract class MagicSpellCardEvent implements MagicCardEvent,MagicEventAction,MagicChangeCardDefinition { @Override public void change(final MagicCardDefinition cdef) { cdef.setEvent(this); } @Override public void executeEvent(final MagicGame game, final MagicEvent event) { throw new RuntimeException(getClass() + " did not override executeEvent"); } public static MagicSpellCardEvent create(final MagicCardDefinition cdef, final String rule) { if (cdef.hasAbility(MagicAbility.Entwine)) { return Entwine(rule); } if (cdef.hasAbility(MagicAbility.Buyback)) { return Buyback(rule); } if (cdef.hasAbility(MagicAbility.HauntSpell)) { return Haunt(rule); } final MagicSourceEvent sourceEvent = MagicRuleEventAction.create(rule); return new MagicSpellCardEvent() { @Override public MagicEvent getEvent(final MagicCardOnStack cardOnStack,final MagicPayedCost payedCost) { return sourceEvent.getEvent(cardOnStack, payedCost); } }; } private static MagicSpellCardEvent Buyback(final String rule) { final MagicSourceEvent effect = MagicRuleEventAction.create(rule); return new MagicSpellCardEvent() { @Override public MagicEvent getEvent(final MagicCardOnStack cardOnStack,final MagicPayedCost payedCost) { final MagicEvent event = effect.getEvent(cardOnStack); return new MagicEvent( event.getSource(), event.getChoice(), payedCost, this, event.getDescription() ); } @Override public void executeEvent(final MagicGame game, final MagicEvent event) { effect.getAction().executeEvent(game, event); final MagicCardOnStack spell = event.getCardOnStack(); if (spell.isKicked()) { game.doAction(new ChangeCardDestinationAction(spell, MagicLocationType.OwnersHand)); game.logAppendMessage( event.getPlayer(), MagicMessage.format("%s is put into %s's hand as it resolves.", spell, event.getPlayer()) ); } } }; } private static MagicSpellCardEvent Haunt(final String rule) { final MagicSourceEvent effect = MagicRuleEventAction.create(rule); return new MagicSpellCardEvent() { @Override public MagicEvent getEvent(final MagicCardOnStack cardOnStack, final MagicPayedCost payedCost) { final MagicEvent event = effect.getEvent(cardOnStack); return new MagicEvent( event.getSource(), event.getChoice(), payedCost, this, event.getDescription() ); } @Override public void executeEvent(final MagicGame game, final MagicEvent event) { effect.getAction().executeEvent(game, event); game.doAction(new EnqueueTriggerAction( new MagicHauntEvent(event.getCardOnStack(), effect) )); } }; } private static MagicSpellCardEvent Entwine(final String rule) { final Pattern pattern = Pattern.compile("choose one — \\(1\\) (?<effect1>.*) \\(2\\) (?<effect2>.*)", Pattern.CASE_INSENSITIVE); final Matcher matcher = pattern.matcher(rule); if (!matcher.matches()) { throw new RuntimeException("unknown effect: \"" + rule + "\""); } final String text1 = matcher.group("effect1"); final String text2 = matcher.group("effect2"); final MagicSourceEvent effect1 = MagicRuleEventAction.create(text1); final MagicSourceEvent effect2 = MagicRuleEventAction.create(text2); final MagicChoice choice1 = effect1.getChoice(); final MagicChoice choice2 = effect2.getChoice(); if (choice1.isValid() && choice2.isValid()) { throw new RuntimeException("effect cannot have two valid choices: \"" + rule + "\""); } final String desc1 = MagicRuleEventAction.personalizeWithChoice(choice1, text1); final String desc2 = MagicRuleEventAction.personalizeWithChoice(choice2, text2); return new MagicSpellCardEvent() { @Override public MagicEvent getEvent(final MagicCardOnStack cardOnStack,final MagicPayedCost payedCost) { return new MagicEvent( cardOnStack, payedCost.isKicked() ? (choice1.isValid() ? choice1 : choice2): new MagicOrChoice( choice1, choice2 ), payedCost, this, payedCost.isKicked() ? desc1 + " " + desc2 : "Choose one$ — • " + desc1 + " • " + desc2 ); } @Override public void executeEvent(final MagicGame game, final MagicEvent event) { if (event.isKicked()) { event.executeAllEvents(game, effect1, effect2); } else { event.executeModalEvent(game, effect1, effect2); } } }; } }