package magic.model.event;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import magic.model.MagicAmount;
import magic.model.MagicCard;
import magic.model.MagicCardDefinition;
import magic.model.MagicChangeCardDefinition;
import magic.model.MagicGame;
import magic.model.MagicLocationType;
import magic.model.MagicManaCost;
import magic.model.MagicPayedCost;
import magic.model.MagicPermanent;
import magic.model.MagicSource;
import magic.model.action.PlayCardAction;
import magic.model.action.PutItemOnStackAction;
import magic.model.action.RemoveCardAction;
import magic.model.choice.MagicChoice;
import magic.model.condition.MagicCondition;
import magic.model.stack.MagicCardOnStack;
import magic.model.target.MagicTargetFilter;
public class MagicHandCastActivation extends MagicActivation<MagicCard> implements MagicChangeCardDefinition, MagicCardEvent {
public static final MagicCondition[] CARD_CONDITION = new MagicCondition[]{
MagicCondition.CARD_CONDITION,
};
final boolean usesStack;
public MagicHandCastActivation(final MagicCardDefinition cdef) {
super(
CARD_CONDITION,
cdef.getActivationHints(),
"Cast"
);
usesStack = cdef.usesStack();
}
protected MagicHandCastActivation(final MagicActivationHints hints, final String txt) {
super(MagicActivation.NO_COND, hints, txt);
usesStack = true;
}
protected MagicHandCastActivation(final MagicCondition[] conditions, final MagicActivationHints hints, final String txt) {
super(conditions, hints, txt);
usesStack = true;
}
@Override
boolean usesStack() {
return usesStack;
}
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
return source.getCostEvent();
}
@Override
public MagicEvent getEvent(final MagicSource source) {
return new MagicEvent(
source,
EVENT_ACTION,
"Play SN."
);
}
private final MagicEventAction EVENT_ACTION = genPlayEventAction(MagicLocationType.OwnersHand);
protected MagicEventAction genPlayEventAction(final MagicLocationType fromLocation) {
return (final MagicGame game, final MagicEvent event) -> {
final MagicCard card = event.getCard();
if (card.getCardDefinition().isLand()) {
game.incLandsPlayed();
}
game.doAction(new RemoveCardAction(card, fromLocation));
if (usesStack) {
final MagicCardOnStack cardOnStack=new MagicCardOnStack(
card,
MagicHandCastActivation.this,
game.getPayedCost()
);
cardOnStack.setFromLocation(fromLocation);
game.doAction(new PutItemOnStackAction(cardOnStack));
} else {
game.doAction(new PlayCardAction(card,card.getController()));
}
};
}
@Override
public void executeEvent(final MagicGame game, final MagicEvent event) {
throw new RuntimeException(getClass() + " did not override executeEvent");
}
@Override
public MagicEvent getEvent(final MagicCardOnStack cardOnStack,final MagicPayedCost payedCost) {
return cardOnStack.getCardDefinition().getCardEvent().getEvent(cardOnStack, payedCost);
}
@Override
MagicChoice getChoice(final MagicCard source) {
final MagicCardOnStack cardOnStack=new MagicCardOnStack(source,this,MagicPayedCost.NO_COST);
return cardOnStack.getEvent().getChoice();
}
@Override
public void change(final MagicCardDefinition cdef) {
cdef.addHandAct(this);
}
public static final MagicHandCastActivation create(final MagicCardDefinition cardDef, final String costs, final String name) {
return create(cardDef, CARD_CONDITION, costs, name);
}
public static final MagicHandCastActivation create(final MagicCardDefinition cardDef, final MagicCondition cond, final String costs, final String name) {
return create(cardDef, new MagicCondition[]{cond, MagicCondition.CARD_CONDITION}, costs, name);
}
public static final MagicHandCastActivation create(final MagicCardDefinition cardDef, final MagicCondition[] conds, final String costs, final String name) {
final List<MagicMatchedCostEvent> matchedCostEvents = MagicRegularCostEvent.buildCast(costs);
assert matchedCostEvents.size() > 0;
return new MagicHandCastActivation(conds, cardDef.getActivationHints(), name) {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
final List<MagicEvent> costEvents = new LinkedList<MagicEvent>();
for (final MagicMatchedCostEvent matched : matchedCostEvents) {
costEvents.add(matched.getEvent(source));
}
return costEvents;
}
};
}
public static final MagicHandCastActivation reduction(final MagicCardDefinition cardDef, final MagicAmount amount) {
return new MagicHandCastActivation(CARD_CONDITION, cardDef.getActivationHints(), "Cast") {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
return Collections.<MagicEvent>singletonList(
new MagicPayManaCostEvent(
source,
source.getGameCost().reduce(
amount.getAmount(source, source.getController())
)
)
);
}
@Override
public void change(final MagicCardDefinition cdef) {
cdef.setHandAct(this);
}
};
}
public static final MagicHandCastActivation reduction(final MagicCardDefinition cardDef, final int amt, final MagicCondition cond) {
return new MagicHandCastActivation(CARD_CONDITION, cardDef.getActivationHints(), "Cast") {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
final int n = cond.accept(source) ? amt : 0;
return Collections.<MagicEvent>singletonList(
new MagicPayManaCostEvent(
source,
source.getGameCost().reduce(n)
)
);
}
@Override
public void change(final MagicCardDefinition cdef) {
cdef.setHandAct(this);
}
};
}
public static final MagicHandCastActivation affinity(final MagicCardDefinition cardDef, final MagicTargetFilter<MagicPermanent> filter) {
return new MagicHandCastActivation(CARD_CONDITION, cardDef.getActivationHints(), "Cast") {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
return Collections.<MagicEvent>singletonList(
new MagicPayManaCostEvent(
source,
source.getGameCost().reduce(
source.getController().getNrOfPermanents(filter)
)
)
);
}
@Override
public void change(final MagicCardDefinition cdef) {
cdef.setHandAct(this);
}
};
}
public static final MagicHandCastActivation awaken(final MagicCardDefinition cardDef, final int n, final String costs) {
final List<MagicMatchedCostEvent> matchedCostEvents = MagicRegularCostEvent.buildCast(costs);
assert matchedCostEvents.size() > 0;
return new MagicHandCastActivation(CARD_CONDITION, cardDef.getActivationHints(), "Awaken") {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
final List<MagicEvent> costEvents = new LinkedList<MagicEvent>();
for (final MagicMatchedCostEvent matched : matchedCostEvents) {
costEvents.add(matched.getEvent(source));
}
return costEvents;
}
@Override
public MagicEvent getEvent(final MagicCardOnStack cardOnStack,final MagicPayedCost payedCost) {
final MagicEvent ev = cardDef.getCardEvent().getEvent(cardOnStack, payedCost);
final MagicEventAction awaken = (final MagicGame game, final MagicEvent event) -> {
ev.getEventAction().executeEvent(game, event);
game.addEvent(new MagicAwakenEvent(event.getSource(), event.getPlayer(), n));
};
return new MagicEvent(
ev.getSource(),
ev.getPlayer(),
ev.getChoice(),
ev.getTargetPicker(),
ev.getRef(),
awaken,
ev.getDescription() + " Awaken " + n + "."
);
}
};
}
public static final MagicHandCastActivation emerge(final MagicCardDefinition cardDef, final MagicManaCost manaCost) {
return new MagicHandCastActivation(CARD_CONDITION, cardDef.getActivationHints(), "Emerge") {
@Override
public Iterable<? extends MagicEvent> getCostEvent(final MagicCard source) {
return Collections.<MagicEvent>singletonList(
new MagicEmergeCostEvent(
source,
manaCost
)
);
}
};
}
}