Merge pull request #4183 from Zzooouhh/master

Implemented Raging River, some other difficult cards & False Orders/Balduvian Warlord/Ydwen Efreet changes
This commit is contained in:
Zzooouhh 2017-11-26 22:25:10 +01:00 committed by GitHub
commit 7e5f1d55c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 2306 additions and 111 deletions

View file

@ -27,6 +27,8 @@
*/
package mage.cards.b;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
@ -46,6 +48,7 @@ import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterBlockingCreature;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
@ -126,36 +129,65 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
// Choose new creature to block
if (permanent.isCreature()) {
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, new FilterAttackingCreature(), true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
}
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = true;
if (!chosenGroup.getBlockers().isEmpty()) {
notYetBlocked = false;
// according to the following mail response from MTG Rules Management about False Orders:
// "if Player A attacks Players B and C, Player B's creatures cannot block creatures attacking Player C"
// therefore we need to single out creatures attacking the target blocker's controller (disappointing, I know)
List<Permanent> list = new ArrayList<>();
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getDefendingPlayerId().equals(permanent.getControllerId())) {
for (UUID attackingCreatureId : combatGroup.getAttackers()) {
Permanent targetsControllerAttacker = game.getPermanent(attackingCreatureId);
list.add(targetsControllerAttacker);
}
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
}
return true;
Player targetsController = game.getPlayer(permanent.getControllerId());
if (targetsController != null) {
FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName());
filter.add(new PermanentInListPredicate(list));
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
}
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
}
}
return true;
}
}
return false;
}
}
class PermanentInListPredicate implements Predicate<Permanent> {
private final List<Permanent> permanents;
public PermanentInListPredicate(List<Permanent> permanents) {
this.permanents = permanents;
}
@Override
public boolean apply(Permanent input, Game game) {
return permanents.contains(input);
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class CharmPeddler extends CardImpl {
public CharmPeddler(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SPELLSHAPER);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {W}, {T}, Discard a card: The next time a source of your choice would deal damage to target creature this turn, prevent that damage.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{W}"));
ability.addCost(new TapSourceCost());
ability.addCost(new DiscardCardCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public CharmPeddler(final CharmPeddler card) {
super(card);
}
@Override
public CharmPeddler copy() {
return new CharmPeddler(this);
}
}

View file

@ -0,0 +1,152 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.d;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterObject;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.TargetSource;
/**
*
* @author ThomasLerner
*/
public class DarkSphere extends CardImpl {
public DarkSphere(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}");
// {tap}, Sacrifice Dark Sphere: The next time a source of your choice would deal damage to you this turn, prevent half that damage, rounded down.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DarkSpherePreventionEffect(), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
public DarkSphere(final DarkSphere card) {
super(card);
}
@Override
public DarkSphere copy() {
return new DarkSphere(this);
}
}
class DarkSpherePreventionEffect extends ReplacementEffectImpl {
private final TargetSource targetSource;
public DarkSpherePreventionEffect() {
super(Duration.OneUse, Outcome.RedirectDamage);
this.staticText = "The next time a source of your choice would deal damage to you this turn, prevent half that damage, rounded down";
this.targetSource = new TargetSource(new FilterObject("source of your choice"));
}
public DarkSpherePreventionEffect(final DarkSpherePreventionEffect effect) {
super(effect);
this.targetSource = effect.targetSource.copy();
}
@Override
public DarkSpherePreventionEffect copy() {
return new DarkSpherePreventionEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
DamageEvent damageEvent = (DamageEvent) event;
if (controller != null) {
controller.damage((int) Math.ceil(damageEvent.getAmount() / 2.0), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
StringBuilder sb = new StringBuilder(sourceObject != null ? sourceObject.getLogName() : "");
sb.append(": ").append(damageEvent.getAmount() / 2).append(" damage prevented");
sb.append(" from ").append(controller.getLogName());
game.informPlayers(sb.toString());
discard(); // only one use
return true;
}
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getSourceId().equals(targetSource.getFirstTarget()) && event.getTargetId().equals(source.getControllerId())) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.d;
import java.util.UUID;
import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.common.FilterCreaturePermanent;
/**
*
* @author L_J
*/
public class DefensiveFormation extends CardImpl {
public DefensiveFormation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}");
// Rather than the attacking player, you assign the combat damage of each creature attacking you. You can divide that creature's combat damage as you choose among any of the creatures blocking it.
this.addAbility(ControllerAssignCombatDamageToBlockersAbility.getInstance());
}
public DefensiveFormation(final DefensiveFormation card) {
super(card);
}
@Override
public DefensiveFormation copy() {
return new DefensiveFormation(this);
}
}

View file

@ -27,6 +27,8 @@
*/
package mage.cards.f;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
@ -43,6 +45,7 @@ import mage.filter.FilterPermanent;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.predicate.ObjectPlayer;
import mage.filter.predicate.ObjectPlayerPredicate;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Controllable;
import mage.game.Game;
@ -140,37 +143,66 @@ class FalseOrdersUnblockEffect extends OneShotEffect {
// Choose new creature to block
if (permanent.isCreature()) {
if (controller.chooseUse(Outcome.Benefit, "Do you want " + permanent.getLogName() + " to block an attacking creature?", source, game)) {
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, new FilterAttackingCreature(), true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
// according to the following mail response from MTG Rules Management about False Orders:
// "if Player A attacks Players B and C, Player B's creatures cannot block creatures attacking Player C"
// therefore we need to single out creatures attacking the target blocker's controller (disappointing, I know)
List<Permanent> list = new ArrayList<>();
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getDefendingPlayerId().equals(permanent.getControllerId())) {
for (UUID attackingCreatureId : combatGroup.getAttackers()) {
Permanent targetsControllerAttacker = game.getPermanent(attackingCreatureId);
list.add(targetsControllerAttacker);
}
}
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = true;
if (!chosenGroup.getBlockers().isEmpty()) {
notYetBlocked = false;
Player targetsController = game.getPlayer(permanent.getControllerId());
if (targetsController != null) {
FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName());
filter.add(new PermanentInListPredicate(list));
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
}
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
}
}
return true;
return true;
}
}
return false;
}
}
class PermanentInListPredicate implements Predicate<Permanent> {
private final List<Permanent> permanents;
public PermanentInListPredicate(List<Permanent> permanents) {
this.permanents = permanents;
}
@Override
public boolean apply(Permanent input, Game game) {
return permanents.contains(input);
}
}

View file

@ -27,7 +27,6 @@
*/
package mage.cards.g;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
@ -40,12 +39,10 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
import mage.watchers.common.AttackedLastTurnWatcher;
/**
*
@ -61,7 +58,7 @@ public class GiantTurtle extends CardImpl {
this.toughness = new MageInt(4);
// Giant Turtle can't attack if it attacked during your last turn.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GiantTurtleCantAttackEffect()), new GiantTurtleWatcher());
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackIfAttackedLastTurnEffect()), new AttackedLastTurnWatcher());
}
public GiantTurtle(final GiantTurtle card) {
@ -74,14 +71,14 @@ public class GiantTurtle extends CardImpl {
}
}
class GiantTurtleCantAttackEffect extends RestrictionEffect {
class CantAttackIfAttackedLastTurnEffect extends RestrictionEffect {
public GiantTurtleCantAttackEffect() {
public CantAttackIfAttackedLastTurnEffect() {
super(Duration.WhileOnBattlefield);
staticText = "{this} can't attack if it attacked during your last turn";
}
public GiantTurtleCantAttackEffect(final GiantTurtleCantAttackEffect effect) {
public CantAttackIfAttackedLastTurnEffect(final CantAttackIfAttackedLastTurnEffect effect) {
super(effect);
}
@ -92,51 +89,20 @@ class GiantTurtleCantAttackEffect extends RestrictionEffect {
@Override
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
GiantTurtleWatcher watcher = (GiantTurtleWatcher) game.getState().getWatchers().get(GiantTurtleWatcher.class.getSimpleName());
for (MageObjectReference mor : watcher.getAttackedLastTurnCreatures()) {
if (attacker.equals(mor.getPermanent(game)) && attacker.getZoneChangeCounter(game) == mor.getZoneChangeCounter()) {
AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName());
if (watcher != null) {
Set<MageObjectReference> attackingCreatures = watcher.getAttackedLastTurnCreatures(attacker.getControllerId());
MageObjectReference mor = new MageObjectReference(attacker, game);
if (attackingCreatures.contains(mor)) {
return false;
}
}
return false;
return true;
}
@Override
public GiantTurtleCantAttackEffect copy() {
return new GiantTurtleCantAttackEffect(this);
public CantAttackIfAttackedLastTurnEffect copy() {
return new CantAttackIfAttackedLastTurnEffect(this);
}
}
class GiantTurtleWatcher extends Watcher {
public final Set<MageObjectReference> attackedLastTurnCreatures = new HashSet<>();
public GiantTurtleWatcher() {
super(GiantTurtleWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public GiantTurtleWatcher(final GiantTurtleWatcher watcher) {
super(watcher);
this.attackedLastTurnCreatures.addAll(watcher.attackedLastTurnCreatures);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) {
this.attackedLastTurnCreatures.add(new MageObjectReference(event.getSourceId(), game));
}
if (event.getType() == GameEvent.EventType.BEGINNING_PHASE_PRE) {
this.attackedLastTurnCreatures.clear();
}
}
public Set<MageObjectReference> getAttackedLastTurnCreatures() {
return this.attackedLastTurnCreatures;
}
@Override
public GiantTurtleWatcher copy() {
return new GiantTurtleWatcher(this);
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.g;
import java.util.UUID;
import mage.abilities.effects.common.DestroyTargetAtBeginningOfNextEndStepEffect;
import mage.abilities.effects.common.PreventDamageToTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.BlockingPredicate;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class GlyphOfDestruction extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("blocking Wall you control");
static {
filter.add(new SubtypePredicate(SubType.WALL));
filter.add(new BlockingPredicate());
}
public GlyphOfDestruction(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}");
// Target blocking Wall you control gets +10/+0 until end of combat. Prevent all damage that would be dealt to it this turn. Destroy it at the beginning of the next end step.
this.getSpellAbility().addEffect(new BoostTargetEffect(10, 0, Duration.EndOfCombat));
this.getSpellAbility().addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE).setText("Prevent all damage that would be dealt to it this turn"));
this.getSpellAbility().addEffect(new DestroyTargetAtBeginningOfNextEndStepEffect().setText("Destroy it at the beginning of the next end step"));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(filter));
}
public GlyphOfDestruction(final GlyphOfDestruction card) {
super(card);
}
@Override
public GlyphOfDestruction copy() {
return new GlyphOfDestruction(this);
}
}

View file

@ -0,0 +1,107 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.h;
import java.util.Set;
import java.util.UUID;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.CumulativeUpkeepAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.watchers.common.AttackedLastTurnWatcher;
/**
*
* @author L_J
*/
public class HallsOfMist extends CardImpl {
public HallsOfMist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Cumulative upkeep-Pay {1}.
this.addAbility(new CumulativeUpkeepAbility(new GenericManaCost(1)));
// Creatures that attacked during their controller's last turn can't attack.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackIfAttackedLastTurnAllEffect()), new AttackedLastTurnWatcher());
}
public HallsOfMist(final HallsOfMist card) {
super(card);
}
@Override
public HallsOfMist copy() {
return new HallsOfMist(this);
}
}
class CantAttackIfAttackedLastTurnAllEffect extends RestrictionEffect {
public CantAttackIfAttackedLastTurnAllEffect() {
super(Duration.WhileOnBattlefield);
this.staticText = "Creatures that attacked during their controller's last turn can't attack";
}
public CantAttackIfAttackedLastTurnAllEffect(final CantAttackIfAttackedLastTurnAllEffect effect) {
super(effect);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.isCreature();
}
@Override
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName());
if (watcher != null) {
Set<MageObjectReference> attackingCreatures = watcher.getAttackedLastTurnCreatures(attacker.getControllerId());
MageObjectReference mor = new MageObjectReference(attacker, game);
if (attackingCreatures.contains(mor)) {
return false;
}
}
return true;
}
@Override
public CantAttackIfAttackedLastTurnAllEffect copy() {
return new CantAttackIfAttackedLastTurnAllEffect(this);
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.h;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterLandCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
/**
*
* @author emerald000 & L_J
*/
public class HiredGiant extends CardImpl {
public HiredGiant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}");
this.subtype.add(SubType.GIANT);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// When Hired Giant enters the battlefield, each other player may search his or her library for a land card and put that card onto the battlefield. Then each player who searched his or her library this way shuffles it.
this.addAbility(new EntersBattlefieldTriggeredAbility(new HiredGiantEffect()));
}
public HiredGiant(final HiredGiant card) {
super(card);
}
@Override
public HiredGiant copy() {
return new HiredGiant(this);
}
}
class HiredGiantEffect extends OneShotEffect {
HiredGiantEffect() {
super(Outcome.Detriment);
this.staticText = "each other player may search his or her library for a land card and put that card onto the battlefield. Then each player who searched his or her library this way shuffles it";
}
HiredGiantEffect(final HiredGiantEffect effect) {
super(effect);
}
@Override
public HiredGiantEffect copy() {
return new HiredGiantEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Set<Player> playersThatSearched = new HashSet<>(1);
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
if (playerId != controller.getId()) {
Player player = game.getPlayer(playerId);
if (player != null && player.chooseUse(Outcome.PutCreatureInPlay, "Search your library for a land card and put it onto the battlefield?", source, game)) {
TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard());
if (player.searchLibrary(target, game)) {
Card targetCard = player.getLibrary().getCard(target.getFirstTarget(), game);
if (targetCard != null) {
player.moveCards(targetCard, Zone.BATTLEFIELD, source, game);
playersThatSearched.add(player);
}
}
}
}
}
for (Player player : playersThatSearched) {
player.shuffleLibrary(source, game);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,191 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.i;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.AttacksOrBlocksEnchantedTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.DestroySourceEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.RemoveFromCombatTargetEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.BlockedByOnlyOneCreatureThisCombatWatcher;
/**
*
* @author L_J
*/
public class Imprison extends CardImpl {
public Imprison(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// Whenever a player activates an ability of enchanted creature with {T} in its activation cost that isn't a mana ability, you may pay {1}. If you do, counter that ability. If you don't, destroy Imprison.
this.addAbility(new ImprisonTriggeredAbility());
// Whenever enchanted creature attacks or blocks, you may pay {1}. If you do, tap the creature, remove it from combat, and creatures it was blocking that had become blocked by only that creature this combat become unblocked. If you don't, destroy Imprison.
this.addAbility(new AttacksOrBlocksEnchantedTriggeredAbility(Zone.BATTLEFIELD, new DoIfCostPaid(new ImprisonUnblockEffect(), new DestroySourceEffect(), new ManaCostsImpl("1"))));
}
public Imprison(final Imprison card) {
super(card);
}
@Override
public Imprison copy() {
return new Imprison(this);
}
}
class ImprisonTriggeredAbility extends TriggeredAbilityImpl {
ImprisonTriggeredAbility() {
super(Zone.BATTLEFIELD, new DoIfCostPaid(new CounterTargetEffect().setText("counter that ability"), new DestroySourceEffect(), new ManaCostsImpl("1")));
}
ImprisonTriggeredAbility(final ImprisonTriggeredAbility ability) {
super(ability);
}
@Override
public ImprisonTriggeredAbility copy() {
return new ImprisonTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.ACTIVATED_ABILITY;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent enchantment = game.getPermanentOrLKIBattlefield(sourceId);
if (enchantment != null && enchantment.getAttachedTo() != null) {
Permanent enchantedPermanent = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo());
if (event.getSourceId().equals(enchantedPermanent.getId())) {
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
if (!(stackAbility.getStackAbility() instanceof ActivatedManaAbilityImpl)) {
String abilityText = stackAbility.getRule(true);
if (abilityText.contains("{T},") || abilityText.contains("{T}:") || abilityText.contains("{T} or")) {
getEffects().get(0).setTargetPointer(new FixedTarget(stackAbility.getId()));
return true;
}
}
}
}
return false;
}
@Override
public String getRule() {
return "Whenever a player activates an ability of enchanted creature with {T} in its activation cost that isn't a mana ability, " + super.getRule();
}
}
class ImprisonUnblockEffect extends OneShotEffect {
public ImprisonUnblockEffect() {
super(Outcome.Benefit);
this.staticText = "tap the creature, remove it from combat, and creatures it was blocking that had become blocked by only that creature this combat become unblocked";
}
public ImprisonUnblockEffect(final ImprisonUnblockEffect effect) {
super(effect);
}
@Override
public ImprisonUnblockEffect copy() {
return new ImprisonUnblockEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null) {
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
if (permanent != null) {
if (permanent.isCreature()) {
// Tap the creature
permanent.tap(game);
// Remove it from combat
Effect effect = new RemoveFromCombatTargetEffect();
effect.setTargetPointer(new FixedTarget(permanent.getId()));
effect.apply(game, source);
// Make blocked creatures unblocked
BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName());
if (watcher != null) {
Set<CombatGroup> combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId());
if (combatGroups != null) {
for (CombatGroup combatGroup : combatGroups) {
if (combatGroup != null) {
combatGroup.setBlocked(false);
}
}
}
}
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.i;
import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.PreventAllDamageToAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class Inviolability extends CardImpl {
public Inviolability(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit));
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
// Prevent all damage that would be dealt to enchanted creature.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventAllDamageToAttachedEffect(Duration.WhileOnBattlefield, "enchanted creature", false)));
}
public Inviolability(final Inviolability card) {
super(card);
}
@Override
public Inviolability copy() {
return new Inviolability(this);
}
}

View file

@ -0,0 +1,210 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class RagingRiver extends CardImpl {
public RagingRiver(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{R}");
// Whenever one or more creatures you control attack, each defending player divides all creatures without flying he or she controls into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label.
this.addAbility(new AttacksWithCreaturesTriggeredAbility(new RagingRiverEffect(), 1));
}
public RagingRiver(final RagingRiver card) {
super(card);
}
@Override
public RagingRiver copy() {
return new RagingRiver(this);
}
}
class RagingRiverEffect extends OneShotEffect {
public RagingRiverEffect() {
super(Outcome.Detriment);
staticText = "each defending player divides all creatures without flying he or she controls into a \"left\" pile and a \"right\" pile. Then, for each attacking creature you control, choose \"left\" or \"right.\" That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label";
}
public RagingRiverEffect(final RagingRiverEffect effect) {
super(effect);
}
@Override
public RagingRiverEffect copy() {
return new RagingRiverEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Permanent> left = new ArrayList<>();
List<Permanent> right = new ArrayList<>();
for (UUID defenderId : game.getCombat().getPlayerDefenders(game)) {
Player defender = game.getPlayer(defenderId);
if (defender != null) {
List<Permanent> leftLog = new ArrayList<>();
List<Permanent> rightLog = new ArrayList<>();
FilterControlledCreaturePermanent filterBlockers = new FilterControlledCreaturePermanent("creatures without flying you control to assign to the \"left\" pile (creatures not chosen will be assigned to the \"right\" pile)");
filterBlockers.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filterBlockers, true);
if (target.canChoose(source.getSourceId(), defenderId, game)) {
if (defender.chooseTarget(Outcome.Neutral, target, source, game)) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), defenderId, game)) {
if (target.getTargets().contains(permanent.getId())) {
left.add(permanent);
leftLog.add(permanent);
}
else if (filterBlockers.match(permanent, source.getSourceId(), defenderId, game)) {
right.add(permanent);
rightLog.add(permanent);
}
}
}
// it could be nice to invoke some graphic indicator of which creature is Left or Right in this spot
StringBuilder sb = new StringBuilder("Left pile of ").append(defender.getLogName()).append(": ");
int i = 0;
for (Permanent permanent : leftLog) {
i++;
sb.append(permanent.getLogName());
if (i < leftLog.size()) {
sb.append(", ");
}
}
game.informPlayers(sb.toString());
sb = new StringBuilder("Right pile of ").append(defender.getLogName()).append(": ");
i = 0;
for (Permanent permanent : rightLog) {
i++;
sb.append(permanent.getLogName());
if (i < rightLog.size()) {
sb.append(", ");
}
}
game.informPlayers(sb.toString());
}
}
}
for (UUID attackers : game.getCombat().getAttackers()) {
Permanent attacker = game.getPermanent(attackers);
if (attacker != null && attacker.getControllerId() == controller.getId()) {
CombatGroup combatGroup = game.getCombat().findGroup(attacker.getId());
if (combatGroup != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
Player defender = game.getPlayer(combatGroup.getDefendingPlayerId());
if (defender != null) {
if (left.isEmpty() && right.isEmpty()) {
// shortcut in case of no labeled blockers available
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
} else {
List<Permanent> leftLog = new ArrayList<>();
List<Permanent> rightLog = new ArrayList<>();
for (Permanent permanent : left) {
if (permanent.getControllerId() == defender.getId()) {
leftLog.add(permanent);
}
}
for (Permanent permanent : right) {
if (permanent.getControllerId() == defender.getId()) {
rightLog.add(permanent);
}
}
if (controller.choosePile(outcome, attacker.getName() + ": attacking " + defender.getName(), leftLog, rightLog, game)) {
filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentInListPredicate(left))));
game.informPlayers(attacker.getLogName() + ": attacks left (" + defender.getLogName() + ")");
} else {
filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentInListPredicate(right))));
game.informPlayers(attacker.getLogName() + ": attacks right (" + defender.getLogName() + ")");
}
}
RestrictionEffect effect = new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfCombat);
effect.setTargetPointer(new FixedTarget(attacker.getId()));
game.addEffect(effect, source);
}
}
}
}
return true;
}
return false;
}
}
class PermanentInListPredicate implements Predicate<Permanent> {
private final List<Permanent> permanents;
public PermanentInListPredicate(List<Permanent> permanents) {
this.permanents = permanents;
}
@Override
public boolean apply(Permanent input, Game game) {
return permanents.contains(input);
}
}

View file

@ -0,0 +1,130 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.UUID;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledEnchantmentPermanent;
import mage.filter.predicate.ObjectPlayer;
import mage.filter.predicate.ObjectPlayerPredicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.other.OwnerPredicate;
import mage.filter.predicate.permanent.AttachedToControlledPermanentPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public class RemoveEnchantments extends CardImpl {
private static final FilterPermanent filter1 = new FilterControlledEnchantmentPermanent();
private static final FilterPermanent filter2 = new FilterPermanent();
private static final FilterPermanent filter3 = new FilterPermanent();
private static final FilterPermanent filter4 = new FilterControlledEnchantmentPermanent();
private static final FilterPermanent filter5 = new FilterPermanent();
private static final FilterPermanent filter6 = new FilterPermanent();
static {
// all enchantments you both own and control
filter1.add(new OwnerPredicate(TargetController.YOU));
// all Auras you own attached to permanents you control
filter2.add(new AttachedToControlledPermanentPredicate());
filter2.add(new SubtypePredicate(SubType.AURA));
filter2.add(new OwnerPredicate(TargetController.YOU));
// all Auras you own attached to attacking creatures your opponents control
filter3.add(new AttachedToOpponentControlledAttackingCreaturePredicate());
filter3.add(new SubtypePredicate(SubType.AURA));
filter3.add(new OwnerPredicate(TargetController.YOU));
// all other enchantments you control (i.e. that you don't own)
filter4.add(new OwnerPredicate(TargetController.NOT_YOU));
// all other Auras attached to permanents you control (i.e. that you don't own)
filter5.add(new AttachedToControlledPermanentPredicate());
filter5.add(new SubtypePredicate(SubType.AURA));
filter5.add(new OwnerPredicate(TargetController.NOT_YOU));
// all other Auras attached to attacking creatures your opponents control (i.e. that you don't own)
filter6.add(new AttachedToOpponentControlledAttackingCreaturePredicate());
filter6.add(new SubtypePredicate(SubType.AURA));
filter6.add(new OwnerPredicate(TargetController.NOT_YOU));
}
public RemoveEnchantments(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}");
// Return to your hand all enchantments you both own and control, all Auras you own attached to permanents you control, and all Auras you own attached to attacking creatures your opponents control. Then destroy all other enchantments you control, all other Auras attached to permanents you control, and all other Auras attached to attacking creatures your opponents control.
this.getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(filter1).setText("Return to your hand all enchantments you both own and control,"));
this.getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(filter2).setText(" all Auras you own attached to permanents you control"));
this.getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(filter3).setText("and all Auras you own attached to attacking creatures your opponents control"));
this.getSpellAbility().addEffect(new DestroyAllEffect(filter4).setText("Then destroy all other enchantments you control,"));
this.getSpellAbility().addEffect(new DestroyAllEffect(filter5).setText(" all other Auras attached to permanents you control"));
this.getSpellAbility().addEffect(new DestroyAllEffect(filter6).setText("and all other Auras attached to attacking creatures your opponents control"));
}
public RemoveEnchantments(final RemoveEnchantments card) {
super(card);
}
@Override
public RemoveEnchantments copy() {
return new RemoveEnchantments(this);
}
}
class AttachedToOpponentControlledAttackingCreaturePredicate implements ObjectPlayerPredicate<ObjectPlayer<Permanent>> {
@Override
public boolean apply(ObjectPlayer<Permanent> input, Game game) {
Permanent attachement = input.getObject();
if (attachement != null) {
Permanent permanent = game.getPermanent(attachement.getAttachedTo());
if (permanent != null) {
if (permanent.isCreature()) {
if (permanent.isAttacking()) {
if (!permanent.getControllerId().equals(input.getPlayerId()) &&
game.getPlayer(input.getPlayerId()).hasOpponent(permanent.getControllerId(), game)) {
return true;
}
}
}
}
}
return false;
}
@Override
public String toString() {
return "Attached to attacking creatures your opponents control";
}
}

View file

@ -0,0 +1,102 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
/**
*
* @author L_J
*/
public class Renounce extends CardImpl {
public Renounce(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
// Sacrifice any number of permanents. You gain 2 life for each permanent sacrificed this way.
this.getSpellAbility().addEffect(new RenounceEffect());
}
public Renounce(final Renounce card) {
super(card);
}
@Override
public Renounce copy() {
return new Renounce(this);
}
}
class RenounceEffect extends OneShotEffect {
public RenounceEffect() {
super(Outcome.Neutral);
staticText = "Sacrifice any number of permanents. You gain 2 life for each permanent sacrificed this way";
}
public RenounceEffect(final RenounceEffect effect) {
super(effect);
}
@Override
public RenounceEffect copy() {
return new RenounceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null){
return false;
}
int amount = 0;
TargetControlledPermanent toSacrifice = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledPermanent(), true);
if(player.chooseTarget(Outcome.Sacrifice, toSacrifice, source, game)) {
for(Object uuid : toSacrifice.getTargets()){
Permanent permanent = game.getPermanent((UUID)uuid);
if(permanent != null){
permanent.sacrifice(source.getSourceId(), game);
amount++;
}
}
player.gainLife(amount * 2, game);
}
return true;
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
/**
*
* @author L_J
*/
public class RootwaterShaman extends CardImpl {
private static final FilterCard filter = new FilterCard("Aura spells with enchant creature");
static {
filter.add(new SubtypePredicate(SubType.AURA));
filter.add(new RootwaterShamanAbilityPredicate());
}
public RootwaterShaman(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.MERFOLK);
this.subtype.add(SubType.SHAMAN);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// You may cast Aura spells with enchant creature as though they had flash.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CastAsThoughItHadFlashAllEffect(Duration.WhileOnBattlefield, filter, false)));
}
public RootwaterShaman(final RootwaterShaman card) {
super(card);
}
@Override
public RootwaterShaman copy() {
return new RootwaterShaman(this);
}
}
class RootwaterShamanAbilityPredicate implements Predicate<MageObject> {
public RootwaterShamanAbilityPredicate() {
}
@Override
public boolean apply(MageObject input, Game game) {
Abilities<Ability> abilities = input.getAbilities();
for (int i = 0; i < abilities.size(); i++) {
if (abilities.get(i) instanceof EnchantAbility) {
String enchantText = abilities.get(i).getRule();
if (enchantText.contentEquals("Enchant creature")) {
return true;
}
}
}
return false;
}
@Override
public String toString() {
return "Aura card with enchant creature";
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.combat.CantBeBlockedByAllSourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author L_J
*/
public class SaprazzanBreaker extends CardImpl {
public SaprazzanBreaker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}");
this.subtype.add(SubType.BEAST);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// {U}: Put the top card of your library into your graveyard. If that card is a land card, Saprazzan Breaker can't be blocked this turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SaprazzanBreakerEffect(), new ManaCostsImpl("{U}")));
}
public SaprazzanBreaker(final SaprazzanBreaker card) {
super(card);
}
@Override
public SaprazzanBreaker copy() {
return new SaprazzanBreaker(this);
}
}
class SaprazzanBreakerEffect extends OneShotEffect {
public SaprazzanBreakerEffect() {
super(Outcome.Benefit);
this.staticText = "Put the top card of your library into your graveyard. If that card is a land card, {this} can't be blocked this turn";
}
public SaprazzanBreakerEffect(final SaprazzanBreakerEffect effect) {
super(effect);
}
@Override
public SaprazzanBreakerEffect copy() {
return new SaprazzanBreakerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {
player.moveCards(card, Zone.GRAVEYARD, source, game);
if (card.isLand()) {
game.addEffect(new CantBeBlockedByAllSourceEffect(new FilterCreaturePermanent(), Duration.EndOfCombat), source);
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.AttacksOrBlocksTriggeredAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.PutOnLibrarySourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
/**
*
* @author L_J
*/
public class SaprazzanOutrigger extends CardImpl {
public SaprazzanOutrigger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}");
this.subtype.add(SubType.MERFOLK);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// When Saprazzan Outrigger attacks or blocks, put it on top of its owner's library at end of combat.
DelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new PutOnLibrarySourceEffect(true, "put it on top of its owner's library at end of combat"));
this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(ability, true), false));
}
public SaprazzanOutrigger(final SaprazzanOutrigger card) {
super(card);
}
@Override
public SaprazzanOutrigger copy() {
return new SaprazzanOutrigger(this);
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.DamagePlayerEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public class Scarecrow extends CardImpl {
public Scarecrow(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}");
this.subtype.add(SubType.SCARECROW);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// {6}, {T}: Prevent all damage that would be dealt to you this turn by attacking creatures without flying.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScarecrowEffect(), new GenericManaCost(6));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
public Scarecrow(final Scarecrow card) {
super(card);
}
@Override
public Scarecrow copy() {
return new Scarecrow(this);
}
}
class ScarecrowEffect extends PreventionEffectImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
ScarecrowEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
staticText = "Prevent all damage that would be dealt to you this turn by creatures with flying";
}
ScarecrowEffect(final ScarecrowEffect effect) {
super(effect);
}
@Override
public ScarecrowEffect copy() {
return new ScarecrowEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) {
DamagePlayerEvent damageEvent = (DamagePlayerEvent) event;
if (event.getTargetId().equals(source.getControllerId())) {
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
if (permanent != null && filter.match(permanent, game)) {
return true;
}
}
}
return false;
}
}

View file

@ -53,7 +53,7 @@ import mage.target.common.TargetCardInLibrary;
*/
public class Tallowisp extends CardImpl {
private static final FilterCard filterAura = new FilterCard("Aura card");
private static final FilterCard filterAura = new FilterCard("Aura card with enchant creature");
static {
filterAura.add(new CardTypePredicate(CardType.ENCHANTMENT));
@ -93,7 +93,7 @@ class TallowispAbilityPredicate implements Predicate<MageObject> {
for (int i = 0; i < abilities.size(); i++) {
if (abilities.get(i) instanceof EnchantAbility) {
String enchantText = abilities.get(i).getRule();
if (enchantText.startsWith("Enchant") && enchantText.contains("creature")) {
if (enchantText.contentEquals("Enchant creature")) {
return true;
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class TowerOfCoireall extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Walls");
static {
filter.add(new SubtypePredicate(SubType.WALL));
}
public TowerOfCoireall(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
// {tap}: Target creature can't be blocked by Walls this turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn).setText("Target creature can't be blocked by Walls this turn"), new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public TowerOfCoireall(final TowerOfCoireall card) {
super(card);
}
@Override
public TowerOfCoireall copy() {
return new TowerOfCoireall(this);
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.common.AfterBlockersAreDeclaredCondition;
import mage.abilities.condition.common.IsPhaseCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.TurnPhase;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.filter.predicate.permanent.BlockedPredicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author LevelX2
*/
public class TrapRunner extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature");
static {
filter.add(new AttackingPredicate());
filter.add(Predicates.not(new BlockedPredicate()));
}
public TrapRunner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// {T}: Target unblocked attacking creature becomes blocked. Activate this ability only during combat after blockers are declared.
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new TrapRunnerEffect(), new TapSourceCost(),
new CompoundCondition("during combat after blockers are declared", new IsPhaseCondition(TurnPhase.COMBAT), AfterBlockersAreDeclaredCondition.instance));
ability.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(ability);
}
public TrapRunner(final TrapRunner card) {
super(card);
}
@Override
public TrapRunner copy() {
return new TrapRunner(this);
}
}
class TrapRunnerEffect extends OneShotEffect {
public TrapRunnerEffect() {
super(Outcome.Benefit);
this.staticText = "Target unblocked attacking creature becomes blocked";
}
public TrapRunnerEffect(final TrapRunnerEffect effect) {
super(effect);
}
@Override
public TrapRunnerEffect copy() {
return new TrapRunnerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
CombatGroup combatGroup = game.getCombat().findGroup(permanent.getId());
if (combatGroup != null) {
combatGroup.setBlocked(true);
game.informPlayers(permanent.getLogName() + " has become blocked");
return true;
}
}
return false;
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.cards.y;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
@ -38,13 +39,14 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.watchers.common.BlockedByOnlyOneCreatureThisCombatWatcher;
/**
*
* @author MarcoMarin
* @author MarcoMarin & L_J
*/
public class YdwenEfreet extends CardImpl {
@ -72,7 +74,7 @@ class YdwenEfreetEffect extends OneShotEffect {
public YdwenEfreetEffect() {
super(Outcome.Damage);
staticText = "flip a coin. If you lose the flip, remove {this} from combat and it can't block.";
staticText = "flip a coin. If you lose the flip, remove {this} from combat and it can't block. Creatures it was blocking that had become blocked by only {this} this combat become unblocked";
}
public YdwenEfreetEffect(YdwenEfreetEffect effect) {
@ -84,14 +86,25 @@ class YdwenEfreetEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent creature = game.getPermanent(source.getSourceId());
if (controller != null && creature != null) {
if (controller.flipCoin(game)) {
return true;
} else {
if (!controller.flipCoin(game)) {
creature.removeFromCombat(game);
creature.setMaxBlocks(0);
return true;
// Make blocked creatures unblocked
BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName());
if (watcher != null) {
Set<CombatGroup> combatGroups = watcher.getBlockedOnlyByCreature(creature.getId());
if (combatGroups != null) {
for (CombatGroup combatGroup : combatGroups) {
if (combatGroup != null) {
combatGroup.setBlocked(false);
}
}
}
}
}
return true;
}
return false;
}
@ -99,4 +112,4 @@ class YdwenEfreetEffect extends OneShotEffect {
public YdwenEfreetEffect copy() {
return new YdwenEfreetEffect(this);
}
}
}

View file

@ -150,7 +150,7 @@ public class Exodus extends ExpansionSet {
cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class));
cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class));
cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class));
cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class));
cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class));
cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class));
cards.add(new SetCardInfo("Soltari Visionary", 20, Rarity.COMMON, mage.cards.s.SoltariVisionary.class));
cards.add(new SetCardInfo("Song of Serenity", 125, Rarity.UNCOMMON, mage.cards.s.SongOfSerenity.class));

View file

@ -159,6 +159,7 @@ public class IceAge extends ExpansionSet {
cards.add(new SetCardInfo("Gravebind", 17, Rarity.RARE, mage.cards.g.Gravebind.class));
cards.add(new SetCardInfo("Green Scarab", 252, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class));
cards.add(new SetCardInfo("Hallowed Ground", 253, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class));
cards.add(new SetCardInfo("Halls of Mist", 332, Rarity.RARE, mage.cards.h.HallsOfMist.class));
cards.add(new SetCardInfo("Heal", 254, Rarity.COMMON, mage.cards.h.Heal.class));
cards.add(new SetCardInfo("Hecatomb", 18, Rarity.RARE, mage.cards.h.Hecatomb.class));
cards.add(new SetCardInfo("Hematite Talisman", 295, Rarity.UNCOMMON, mage.cards.h.HematiteTalisman.class));

View file

@ -128,6 +128,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Ghosts of the Damned", 12, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class));
cards.add(new SetCardInfo("Giant Strength", 147, Rarity.COMMON, mage.cards.g.GiantStrength.class));
cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class));
cards.add(new SetCardInfo("Glyph of Destruction", 148, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class));
cards.add(new SetCardInfo("Gravity Sphere", 149, Rarity.RARE, mage.cards.g.GravitySphere.class));
cards.add(new SetCardInfo("Great Defender", 185, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class));
cards.add(new SetCardInfo("Greater Realm of Preservation", 187, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class));
@ -148,6 +149,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Hunding Gjornersen", 271, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class));
cards.add(new SetCardInfo("Hyperion Blacksmith", 150, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class));
cards.add(new SetCardInfo("Immolation", 151, Rarity.COMMON, mage.cards.i.Immolation.class));
cards.add(new SetCardInfo("Imprison", 21, Rarity.RARE, mage.cards.i.Imprison.class));
cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class));
cards.add(new SetCardInfo("Indestructible Aura", 190, Rarity.COMMON, mage.cards.i.IndestructibleAura.class));
cards.add(new SetCardInfo("Infernal Medusa", 22, Rarity.UNCOMMON, mage.cards.i.InfernalMedusa.class));
@ -219,6 +221,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Red Mana Battery", 236, Rarity.UNCOMMON, mage.cards.r.RedManaBattery.class));
cards.add(new SetCardInfo("Reincarnation", 115, Rarity.UNCOMMON, mage.cards.r.Reincarnation.class));
cards.add(new SetCardInfo("Relic Barrier", 237, Rarity.UNCOMMON, mage.cards.r.RelicBarrier.class));
cards.add(new SetCardInfo("Remove Enchantments", 202, Rarity.COMMON, mage.cards.r.RemoveEnchantments.class));
cards.add(new SetCardInfo("Remove Soul", 72, Rarity.COMMON, mage.cards.r.RemoveSoul.class));
cards.add(new SetCardInfo("Reset", 73, Rarity.UNCOMMON, mage.cards.r.Reset.class));
cards.add(new SetCardInfo("Revelation", 116, Rarity.RARE, mage.cards.r.Revelation.class));

View file

@ -211,6 +211,7 @@ public class LimitedEditionAlpha extends ExpansionSet {
cards.add(new SetCardInfo("Psionic Blast", 75, Rarity.UNCOMMON, mage.cards.p.PsionicBlast.class));
cards.add(new SetCardInfo("Psychic Venom", 76, Rarity.COMMON, mage.cards.p.PsychicVenom.class));
cards.add(new SetCardInfo("Purelace", 216, Rarity.RARE, mage.cards.p.Purelace.class));
cards.add(new SetCardInfo("Raging River", 169, Rarity.RARE, mage.cards.r.RagingRiver.class));
cards.add(new SetCardInfo("Raise Dead", 31, Rarity.COMMON, mage.cards.r.RaiseDead.class));
cards.add(new SetCardInfo("Red Elemental Blast", 170, Rarity.COMMON, mage.cards.r.RedElementalBlast.class));
cards.add(new SetCardInfo("Red Ward", 217, Rarity.UNCOMMON, mage.cards.r.RedWard.class));

View file

@ -216,6 +216,7 @@ public class LimitedEditionBeta extends ExpansionSet {
cards.add(new SetCardInfo("Psionic Blast", 75, Rarity.UNCOMMON, mage.cards.p.PsionicBlast.class));
cards.add(new SetCardInfo("Psychic Venom", 76, Rarity.COMMON, mage.cards.p.PsychicVenom.class));
cards.add(new SetCardInfo("Purelace", 218, Rarity.RARE, mage.cards.p.Purelace.class));
cards.add(new SetCardInfo("Raging River", 170, Rarity.RARE, mage.cards.r.RagingRiver.class));
cards.add(new SetCardInfo("Raise Dead", 31, Rarity.COMMON, mage.cards.r.RaiseDead.class));
cards.add(new SetCardInfo("Red Elemental Blast", 171, Rarity.COMMON, mage.cards.r.RedElementalBlast.class));
cards.add(new SetCardInfo("Red Ward", 219, Rarity.UNCOMMON, mage.cards.r.RedWard.class));

View file

@ -93,6 +93,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Ceremonial Guard", 182, Rarity.COMMON, mage.cards.c.CeremonialGuard.class));
cards.add(new SetCardInfo("Chambered Nautilus", 64, Rarity.UNCOMMON, mage.cards.c.ChamberedNautilus.class));
cards.add(new SetCardInfo("Charisma", 66, Rarity.RARE, mage.cards.c.Charisma.class));
cards.add(new SetCardInfo("Charm Peddler", 6, Rarity.COMMON, mage.cards.c.CharmPeddler.class));
cards.add(new SetCardInfo("Charmed Griffin", 7, Rarity.UNCOMMON, mage.cards.c.CharmedGriffin.class));
cards.add(new SetCardInfo("Cho-Arrim Alchemist", 8, Rarity.RARE, mage.cards.c.ChoArrimAlchemist.class));
cards.add(new SetCardInfo("Cho-Arrim Bruiser", 9, Rarity.RARE, mage.cards.c.ChoArrimBruiser.class));
@ -123,7 +124,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Deadly Insect", 238, Rarity.COMMON, mage.cards.d.DeadlyInsect.class));
cards.add(new SetCardInfo("Deathgazer", 130, Rarity.UNCOMMON, mage.cards.d.Deathgazer.class));
cards.add(new SetCardInfo("Deepwood Drummer", 239, Rarity.COMMON, mage.cards.d.DeepwoodDrummer.class));
cards.add(new SetCardInfo("Deepwood Elder", 240, Rarity.RARE, mage.cards.d.DeepwoodElder.class));
cards.add(new SetCardInfo("Deepwood Elder", 240, Rarity.RARE, mage.cards.d.DeepwoodElder.class));
cards.add(new SetCardInfo("Deepwood Ghoul", 131, Rarity.COMMON, mage.cards.d.DeepwoodGhoul.class));
cards.add(new SetCardInfo("Deepwood Legate", 132, Rarity.UNCOMMON, mage.cards.d.DeepwoodLegate.class));
cards.add(new SetCardInfo("Deepwood Tantiv", 241, Rarity.UNCOMMON, mage.cards.d.DeepwoodTantiv.class));
@ -175,6 +176,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("High Market", 320, Rarity.RARE, mage.cards.h.HighMarket.class));
cards.add(new SetCardInfo("High Seas", 83, Rarity.UNCOMMON, mage.cards.h.HighSeas.class));
cards.add(new SetCardInfo("Highway Robber", 139, Rarity.COMMON, mage.cards.h.HighwayRobber.class));
cards.add(new SetCardInfo("Hired Giant", 194, Rarity.UNCOMMON, mage.cards.h.HiredGiant.class));
cards.add(new SetCardInfo("Honor the Fallen", 21, Rarity.RARE, mage.cards.h.HonorTheFallen.class));
cards.add(new SetCardInfo("Hoodwink", 84, Rarity.COMMON, mage.cards.h.Hoodwink.class));
cards.add(new SetCardInfo("Horned Troll", 251, Rarity.COMMON, mage.cards.h.HornedTroll.class));
@ -186,6 +188,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Instigator", 140, Rarity.RARE, mage.cards.i.Instigator.class));
cards.add(new SetCardInfo("Intimidation", 142, Rarity.UNCOMMON, mage.cards.i.Intimidation.class));
cards.add(new SetCardInfo("Invigorate", 254, Rarity.COMMON, mage.cards.i.Invigorate.class));
cards.add(new SetCardInfo("Inviolability", 23, Rarity.COMMON, mage.cards.i.Inviolability.class));
cards.add(new SetCardInfo("Iron Lance", 300, Rarity.UNCOMMON, mage.cards.i.IronLance.class));
cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
@ -259,6 +262,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Rampart Crawler", 156, Rarity.COMMON, mage.cards.r.RampartCrawler.class));
cards.add(new SetCardInfo("Rappelling Scouts", 41, Rarity.RARE, mage.cards.r.RappellingScouts.class));
cards.add(new SetCardInfo("Remote Farm", 323, Rarity.COMMON, mage.cards.r.RemoteFarm.class));
cards.add(new SetCardInfo("Renounce", 42, Rarity.UNCOMMON, mage.cards.r.Renounce.class));
cards.add(new SetCardInfo("Reverent Mantra", 44, Rarity.RARE, mage.cards.r.ReverentMantra.class));
cards.add(new SetCardInfo("Revive", 262, Rarity.UNCOMMON, mage.cards.r.Revive.class));
cards.add(new SetCardInfo("Righteous Aura", 45, Rarity.UNCOMMON, mage.cards.r.RighteousAura.class));
@ -281,9 +285,11 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Sand Squid", 96, Rarity.RARE, mage.cards.s.SandSquid.class));
cards.add(new SetCardInfo("Sandstone Needle", 326, Rarity.COMMON, mage.cards.s.SandstoneNeedle.class));
cards.add(new SetCardInfo("Saprazzan Bailiff", 97, Rarity.RARE, mage.cards.s.SaprazzanBailiff.class));
cards.add(new SetCardInfo("Saprazzan Breaker", 98, Rarity.UNCOMMON, mage.cards.s.SaprazzanBreaker.class));
cards.add(new SetCardInfo("Saprazzan Cove", 327, Rarity.UNCOMMON, mage.cards.s.SaprazzanCove.class));
cards.add(new SetCardInfo("Saprazzan Heir", 99, Rarity.RARE, mage.cards.s.SaprazzanHeir.class));
cards.add(new SetCardInfo("Saprazzan Legate", 100, Rarity.UNCOMMON, mage.cards.s.SaprazzanLegate.class));
cards.add(new SetCardInfo("Saprazzan Outrigger", 101, Rarity.COMMON, mage.cards.s.SaprazzanOutrigger.class));
cards.add(new SetCardInfo("Saprazzan Raider", 102, Rarity.COMMON, mage.cards.s.SaprazzanRaider.class));
cards.add(new SetCardInfo("Saprazzan Skerry", 328, Rarity.COMMON, mage.cards.s.SaprazzanSkerry.class));
cards.add(new SetCardInfo("Scandalmonger", 158, Rarity.UNCOMMON, mage.cards.s.Scandalmonger.class));
@ -341,6 +347,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Toymaker", 314, Rarity.UNCOMMON, mage.cards.t.Toymaker.class));
cards.add(new SetCardInfo("Trade Routes", 112, Rarity.RARE, mage.cards.t.TradeRoutes.class));
cards.add(new SetCardInfo("Tranquility", 280, Rarity.COMMON, mage.cards.t.Tranquility.class));
cards.add(new SetCardInfo("Trap Runner", 55, Rarity.UNCOMMON, mage.cards.t.TrapRunner.class));
cards.add(new SetCardInfo("Tremor", 220, Rarity.COMMON, mage.cards.t.Tremor.class));
cards.add(new SetCardInfo("Two-Headed Dragon", 221, Rarity.RARE, mage.cards.t.TwoHeadedDragon.class));
cards.add(new SetCardInfo("Undertaker", 167, Rarity.COMMON, mage.cards.u.Undertaker.class));

View file

@ -260,6 +260,7 @@ public class Tempest extends ExpansionSet {
cards.add(new SetCardInfo("Rootwater Diver", 81, Rarity.UNCOMMON, mage.cards.r.RootwaterDiver.class));
cards.add(new SetCardInfo("Rootwater Hunter", 82, Rarity.COMMON, mage.cards.r.RootwaterHunter.class));
cards.add(new SetCardInfo("Rootwater Matriarch", 83, Rarity.RARE, mage.cards.r.RootwaterMatriarch.class));
cards.add(new SetCardInfo("Rootwater Shaman", 84, Rarity.RARE, mage.cards.r.RootwaterShaman.class));
cards.add(new SetCardInfo("Ruby Medallion", 295, Rarity.RARE, mage.cards.r.RubyMedallion.class));
cards.add(new SetCardInfo("Sacred Guide", 250, Rarity.RARE, mage.cards.s.SacredGuide.class));
cards.add(new SetCardInfo("Sadistic Glee", 47, Rarity.COMMON, mage.cards.s.SadisticGlee.class));

View file

@ -72,6 +72,7 @@ public class TheDark extends ExpansionSet {
cards.add(new SetCardInfo("Coal Golem", 96, Rarity.UNCOMMON, mage.cards.c.CoalGolem.class));
cards.add(new SetCardInfo("Dance of Many", 21, Rarity.RARE, mage.cards.d.DanceOfMany.class));
cards.add(new SetCardInfo("Dark Heart of the Wood", 117, Rarity.COMMON, mage.cards.d.DarkHeartOfTheWood.class));
cards.add(new SetCardInfo("Dark Sphere", 97, Rarity.RARE, mage.cards.d.DarkSphere.class));
cards.add(new SetCardInfo("Deep Water", 22, Rarity.COMMON, mage.cards.d.DeepWater.class));
cards.add(new SetCardInfo("Diabolic Machine", 98, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class));
cards.add(new SetCardInfo("Drowned", 23, Rarity.COMMON, mage.cards.d.Drowned.class));
@ -120,6 +121,7 @@ public class TheDark extends ExpansionSet {
cards.add(new SetCardInfo("Riptide", 34, Rarity.COMMON, mage.cards.r.Riptide.class));
cards.add(new SetCardInfo("Safe Haven", 115, Rarity.RARE, mage.cards.s.SafeHaven.class));
cards.add(new SetCardInfo("Savaen Elves", 47, Rarity.COMMON, mage.cards.s.SavaenElves.class));
cards.add(new SetCardInfo("Scarecrow", 105, Rarity.RARE, mage.cards.s.Scarecrow.class));
cards.add(new SetCardInfo("Scarwood Bandits", 48, Rarity.RARE, mage.cards.s.ScarwoodBandits.class));
cards.add(new SetCardInfo("Scarwood Goblins", 119, Rarity.COMMON, mage.cards.s.ScarwoodGoblins.class));
cards.add(new SetCardInfo("Scarwood Hag", 49, Rarity.UNCOMMON, mage.cards.s.ScarwoodHag.class));
@ -133,6 +135,7 @@ public class TheDark extends ExpansionSet {
cards.add(new SetCardInfo("Sunken City", 35, Rarity.COMMON, mage.cards.s.SunkenCity.class));
cards.add(new SetCardInfo("Tivadar's Crusade", 91, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class));
cards.add(new SetCardInfo("Tormod's Crypt", 109, Rarity.UNCOMMON, mage.cards.t.TormodsCrypt.class));
cards.add(new SetCardInfo("Tower of Coireall", 110, Rarity.RARE, mage.cards.t.TowerOfCoireall.class));
cards.add(new SetCardInfo("Tracker", 52, Rarity.RARE, mage.cards.t.Tracker.class));
cards.add(new SetCardInfo("Uncle Istvan", 16, Rarity.UNCOMMON, mage.cards.u.UncleIstvan.class));
cards.add(new SetCardInfo("Venom", 53, Rarity.COMMON, mage.cards.v.Venom.class));

View file

@ -216,6 +216,7 @@ public class UnlimitedEdition extends ExpansionSet {
cards.add(new SetCardInfo("Psionic Blast", 75, Rarity.UNCOMMON, mage.cards.p.PsionicBlast.class));
cards.add(new SetCardInfo("Psychic Venom", 76, Rarity.COMMON, mage.cards.p.PsychicVenom.class));
cards.add(new SetCardInfo("Purelace", 217, Rarity.RARE, mage.cards.p.Purelace.class));
cards.add(new SetCardInfo("Raging River", 169, Rarity.RARE, mage.cards.r.RagingRiver.class));
cards.add(new SetCardInfo("Raise Dead", 31, Rarity.COMMON, mage.cards.r.RaiseDead.class));
cards.add(new SetCardInfo("Red Elemental Blast", 170, Rarity.COMMON, mage.cards.r.RedElementalBlast.class));
cards.add(new SetCardInfo("Red Ward", 218, Rarity.UNCOMMON, mage.cards.r.RedWard.class));

View file

@ -118,6 +118,7 @@ public class UrzasSaga extends ExpansionSet {
cards.add(new SetCardInfo("Darkest Hour", 128, Rarity.RARE, mage.cards.d.DarkestHour.class));
cards.add(new SetCardInfo("Dark Hatchling", 126, Rarity.RARE, mage.cards.d.DarkHatchling.class));
cards.add(new SetCardInfo("Dark Ritual", 127, Rarity.COMMON, mage.cards.d.DarkRitual.class));
cards.add(new SetCardInfo("Defensive Formation", 9, Rarity.UNCOMMON, mage.cards.d.DefensiveFormation.class));
cards.add(new SetCardInfo("Despondency", 129, Rarity.COMMON, mage.cards.d.Despondency.class));
cards.add(new SetCardInfo("Destructive Urge", 180, Rarity.UNCOMMON, mage.cards.d.DestructiveUrge.class));
cards.add(new SetCardInfo("Diabolic Servitude", 130, Rarity.UNCOMMON, mage.cards.d.DiabolicServitude.class));
@ -362,7 +363,7 @@ public class UrzasSaga extends ExpansionSet {
cards.add(new SetCardInfo("Vug Lizard", 227, Rarity.UNCOMMON, mage.cards.v.VugLizard.class));
cards.add(new SetCardInfo("War Dance", 282, Rarity.UNCOMMON, mage.cards.w.WarDance.class));
cards.add(new SetCardInfo("Wall of Junk", 315, Rarity.UNCOMMON, mage.cards.w.WallOfJunk.class));
cards.add(new SetCardInfo("Waylay", 56, Rarity.UNCOMMON, mage.cards.w.Waylay.class));
cards.add(new SetCardInfo("Waylay", 56, Rarity.UNCOMMON, mage.cards.w.Waylay.class));
cards.add(new SetCardInfo("Western Paladin", 168, Rarity.RARE, mage.cards.w.WesternPaladin.class));
cards.add(new SetCardInfo("Whetstone", 316, Rarity.RARE, mage.cards.w.Whetstone.class));
cards.add(new SetCardInfo("Whirlwind", 283, Rarity.RARE, mage.cards.w.Whirlwind.class));

View file

@ -0,0 +1,67 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.common;
import mage.abilities.MageSingleton;
import mage.abilities.StaticAbility;
import java.io.ObjectStreamException;
import mage.constants.AbilityType;
import mage.constants.Zone;
/**
* @author L_J
*/
public class ControllerAssignCombatDamageToBlockersAbility extends StaticAbility implements MageSingleton {
private static final ControllerAssignCombatDamageToBlockersAbility instance = new ControllerAssignCombatDamageToBlockersAbility();
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static ControllerAssignCombatDamageToBlockersAbility getInstance() {
return instance;
}
private ControllerAssignCombatDamageToBlockersAbility() {
super(AbilityType.STATIC, Zone.BATTLEFIELD);
}
@Override
public String getRule() {
return "Rather than the attacking player, you assign the combat damage of each creature attacking you. You can divide that creature's combat damage as you choose among any of the creatures blocking it.";
}
@Override
public ControllerAssignCombatDamageToBlockersAbility copy() {
return instance;
}
}

View file

@ -78,6 +78,10 @@ public abstract class RequirementEffect extends ContinuousEffectImpl {
public boolean mustBlockAny(Game game) {
return false;
}
public boolean mustBlockAllAttackers(Game game) {
return false;
}
/**
* Defines the defender a attacker has to attack

View file

@ -16,6 +16,7 @@ import mage.util.CardUtil;
public class DoIfCostPaid extends OneShotEffect {
protected Effects executingEffects = new Effects();
protected Effects otherwiseEffects = new Effects(); // used for Imprison
private final Cost cost;
private String chooseUseText;
private boolean optional;
@ -24,6 +25,11 @@ public class DoIfCostPaid extends OneShotEffect {
this(effect, cost, null);
}
public DoIfCostPaid(Effect effect, Effect effect2, Cost cost) {
this(effect, cost, null, true);
this.otherwiseEffects.add(effect2);
}
public DoIfCostPaid(Effect effect, Cost cost, String chooseUseText) {
this(effect, cost, chooseUseText, true);
}
@ -39,6 +45,7 @@ public class DoIfCostPaid extends OneShotEffect {
public DoIfCostPaid(final DoIfCostPaid effect) {
super(effect);
this.executingEffects = effect.executingEffects.copy();
this.otherwiseEffects = effect.otherwiseEffects.copy();
this.cost = effect.cost.copy();
this.chooseUseText = effect.chooseUseText;
this.optional = effect.optional;
@ -80,6 +87,26 @@ public class DoIfCostPaid extends OneShotEffect {
}
player.resetStoredBookmark(game); // otherwise you can e.g. undo card drawn with Mentor of the Meek
}
else if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
result &= effect.apply(game, source);
} else {
game.addEffect((ContinuousEffect) effect, source);
}
}
}
}
else if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
result &= effect.apply(game, source);
} else {
game.addEffect((ContinuousEffect) effect, source);
}
}
}
return result;
}
@ -99,7 +126,7 @@ public class DoIfCostPaid extends OneShotEffect {
if (!staticText.isEmpty()) {
return staticText;
}
return (optional ? "you may " : "") + getCostText() + ". If you do, " + executingEffects.getText(mode);
return (optional ? "you may " : "") + getCostText() + ". If you do, " + executingEffects.getText(mode) + (!otherwiseEffects.isEmpty() ? " If you don't, " + otherwiseEffects.getText(mode) : "");
}
protected String getCostText() {

View file

@ -1201,6 +1201,7 @@ public class Combat implements Serializable, Copyable<Combat> {
for (CombatGroup group : groups) {
result |= group.remove(creatureId);
}
blockingGroups.remove(creatureId);
if (result && withInfo) {
game.informPlayers(creature.getLogName() + " removed from combat");
}

View file

@ -33,6 +33,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility;
import mage.abilities.common.DamageAsThoughNotBlockedAbility;
import mage.abilities.keyword.CantBlockAloneAbility;
import mage.abilities.keyword.DeathtouchAbility;
@ -244,6 +245,12 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
blocker.markDamage(damage, attacker.getId(), game, true, true);
} else {
Player player = game.getPlayer(attacker.getControllerId());
for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation
if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) {
player = game.getPlayer(defendingPlayerId);
break;
}
}
int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game);
blocker.markDamage(damageAssigned, attacker.getId(), game, true, true);
damage -= damageAssigned;
@ -269,7 +276,15 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
if (attacker == null) {
return;
}
boolean oldRuleDamage = false;
Player player = game.getPlayer(attacker.getControllerId());
for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation
if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) {
player = game.getPlayer(defendingPlayerId);
oldRuleDamage = true;
break;
}
}
int damage = getDamageValueFromPermanent(attacker, game);
if (canDamage(attacker, first)) {
// must be set before attacker damage marking because of effects like Test of Faith
@ -284,6 +299,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
}
Map<UUID, Integer> assigned = new HashMap<>();
if (blocked) {
boolean excessDamageToDefender = true;
for (UUID blockerId : blockerOrder) {
Permanent blocker = game.getPermanent(blockerId);
if (blocker != null) {
@ -298,15 +314,23 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
damage = 0;
break;
}
int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game);
int damageAssigned = 0;
if (!oldRuleDamage) {
damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game);
} else {
damageAssigned = player.getAmount(0, damage, "Assign damage to " + blocker.getName(), game);
if (damageAssigned < lethalDamage) {
excessDamageToDefender = false; // all blockers need to have lethal damage assigned before it can trample over to the defender
}
}
assigned.put(blockerId, damageAssigned);
damage -= damageAssigned;
}
}
if (damage > 0 && hasTrample(attacker)) {
if (damage > 0 && hasTrample(attacker) && excessDamageToDefender) {
defenderDamage(attacker, damage, game);
} else if (!blockerOrder.isEmpty()) {
// Assign the damge left to first blocker
// Assign the damage left to first blocker
assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) + damage);
}
}
@ -382,6 +406,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
}
if (lethalDamage >= damage) {
assigned.put(attackerId, damage);
damage = 0;
break;
}
int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + attacker.getName(), game);
@ -389,6 +414,10 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
damage -= damageAssigned;
}
}
if (damage > 0) {
// Assign the damage left to first attacker
assigned.put(attackerOrder.get(0), assigned.get(attackerOrder.get(0)) + damage);
}
for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) {
Permanent attacker = game.getPermanent(entry.getKey());
@ -463,6 +492,12 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
return;
}
Player player = game.getPlayer(playerId);
for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation
if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) {
player = game.getPlayer(defendingPlayerId);
break;
}
}
List<UUID> blockerList = new ArrayList<>(blockers);
blockerOrder.clear();
while (player.canRespond()) {
@ -532,6 +567,9 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
if (attackers.contains(creatureId)) {
attackers.remove(creatureId);
result = true;
if (attackerOrder.contains(creatureId)) {
attackerOrder.remove(creatureId);
}
} else if (blockers.contains(creatureId)) {
blockers.remove(creatureId);
result = true;

View file

@ -0,0 +1,115 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.watchers.common;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import mage.MageObjectReference;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
/**
*
* @author L_J
*/
public class AttackedLastTurnWatcher extends Watcher {
public final Map<UUID, Set<MageObjectReference>> attackedLastTurnCreatures = new HashMap<>(); // Map<lastTurnOfPlayerId, Set<attackingCreature>>
public final Map<UUID, Set<MageObjectReference>> attackedThisTurnCreatures = new HashMap<>(); // dummy map for beginning of turn iteration purposes
public AttackedLastTurnWatcher() {
super(AttackedLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public AttackedLastTurnWatcher(final AttackedLastTurnWatcher watcher) {
super(watcher);
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedLastTurnCreatures.entrySet()) {
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
allAttackersCopy.addAll(entry.getValue());
attackedLastTurnCreatures.put(entry.getKey(), allAttackersCopy);
}
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedThisTurnCreatures.entrySet()) {
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
allAttackersCopy.addAll(entry.getValue());
attackedThisTurnCreatures.put(entry.getKey(), allAttackersCopy);
}
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.BEGINNING_PHASE_PRE) {
UUID activePlayer = game.getActivePlayerId();
if (attackedThisTurnCreatures.containsKey(activePlayer)) {
if (attackedThisTurnCreatures.get(activePlayer) != null) {
attackedLastTurnCreatures.put(activePlayer, getAttackedThisTurnCreatures(activePlayer));
}
attackedThisTurnCreatures.remove(activePlayer);
} else { // } else if (attackedLastTurnCreatures.containsKey(activePlayer)) {
attackedLastTurnCreatures.remove(activePlayer);
}
}
if (event.getType() == GameEvent.EventType.DECLARED_ATTACKERS) {
UUID attackingPlayer = game.getCombat().getAttackingPlayerId();
Set<MageObjectReference> attackingCreatures = getAttackedThisTurnCreatures(attackingPlayer);
for (UUID attackerId : game.getCombat().getAttackers()) {
Permanent attacker = game.getPermanent(attackerId);
if (attacker != null) {
attackingCreatures.add(new MageObjectReference(attacker, game));
}
}
attackedThisTurnCreatures.put(attackingPlayer, attackingCreatures);
}
}
public Set<MageObjectReference> getAttackedLastTurnCreatures(UUID combatPlayerId) {
if (attackedLastTurnCreatures.get(combatPlayerId) != null) {
return attackedLastTurnCreatures.get(combatPlayerId);
}
return new HashSet<>();
}
public Set<MageObjectReference> getAttackedThisTurnCreatures(UUID combatPlayerId) {
if (attackedThisTurnCreatures.get(combatPlayerId) != null) {
return attackedThisTurnCreatures.get(combatPlayerId);
}
return new HashSet<>();
}
@Override
public AttackedLastTurnWatcher copy() {
return new AttackedLastTurnWatcher(this);
}
}