diff --git a/Mage.Sets/src/mage/sets/magic2012/StormbloodBerserker.java b/Mage.Sets/src/mage/sets/magic2012/StormbloodBerserker.java new file mode 100644 index 00000000000..3289b96bc17 --- /dev/null +++ b/Mage.Sets/src/mage/sets/magic2012/StormbloodBerserker.java @@ -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.sets.magic2012; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.BloodthirstAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author nantuko + */ +public class StormbloodBerserker extends CardImpl { + + public StormbloodBerserker(UUID ownerId) { + super(ownerId, 156, "Stormblood Berserker", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "M12"; + this.subtype.add("Human"); + this.subtype.add("Berserker"); + + this.color.setRed(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + this.addAbility(new BloodthirstAbility(2)); + // Stormblood Berserker can't be blocked except by two or more creatures. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new StormbloodBerserkerEffect())); + } + + public StormbloodBerserker(final StormbloodBerserker card) { + super(card); + } + + @Override + public StormbloodBerserker copy() { + return new StormbloodBerserker(this); + } +} + +class StormbloodBerserkerEffect extends ContinuousEffectImpl { + + public StormbloodBerserkerEffect() { + super(Constants.Duration.WhileOnBattlefield, Constants.Outcome.Benefit); + staticText = "{this} can't be blocked except by two or more creatures"; + } + + public StormbloodBerserkerEffect(final StormbloodBerserkerEffect effect) { + super(effect); + } + + @Override + public StormbloodBerserkerEffect copy() { + return new StormbloodBerserkerEffect(this); + } + + @Override + public boolean apply(Constants.Layer layer, Constants.SubLayer sublayer, Ability source, Game game) { + Permanent perm = game.getPermanent(source.getSourceId()); + if (perm != null) { + switch (layer) { + case RulesEffects: + perm.setMinBlockedBy(2); + break; + } + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Constants.Layer layer) { + return layer == Constants.Layer.RulesEffects; + } + +} diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index 98a20f72c02..8de701cb637 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -189,6 +189,12 @@ public class Combat implements Serializable, Copyable { } } + public void checkBlockRestrictions(Game game) { + for (CombatGroup group : groups) { + group.checkBlockRestrictions(game); + } + } + public void setDefenders(Game game) { Set opponents = game.getOpponents(attackerId); PlayerList players; diff --git a/Mage/src/mage/game/combat/CombatGroup.java b/Mage/src/mage/game/combat/CombatGroup.java index e42917b9e28..00e5f65e919 100644 --- a/Mage/src/mage/game/combat/CombatGroup.java +++ b/Mage/src/mage/game/combat/CombatGroup.java @@ -53,6 +53,7 @@ public class CombatGroup implements Serializable, Copyable { protected List blockers = new ArrayList(); protected List blockerOrder = new ArrayList(); protected List attackerOrder = new ArrayList(); + protected Map players = new HashMap(); protected boolean blocked; protected UUID defenderId; protected boolean defenderIsPlaneswalker; @@ -78,6 +79,9 @@ public class CombatGroup implements Serializable, Copyable { for (UUID orderId: group.attackerOrder) { this.attackerOrder.add(orderId); } + for (Map.Entry entry : group.players.entrySet()) { + players.put(entry.getKey(), entry.getValue()); + } } protected String getValue(Game game) { @@ -391,9 +395,7 @@ public class CombatGroup implements Serializable, Copyable { blockers.add(blockerId); blockerOrder.add(blockerId); this.blocked = true; - for (UUID attackerId: attackers) { - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, attackerId, blockerId, playerId)); - } + this.players.put(blockerId, playerId); } } @@ -467,6 +469,33 @@ public class CombatGroup implements Serializable, Copyable { } } + public void checkBlockRestrictions(Game game) { + if (attackers.isEmpty()) { + return; + } + for (UUID uuid : attackers) { + Permanent attacker = game.getPermanent(uuid); + if (attacker != null && this.blocked && attacker.getMinBlockedBy() > 1 && blockers.size() > 0 && blockers.size() < attacker.getMinBlockedBy()) { + for (UUID blockerId : blockers) { + Permanent blocker = game.getPermanent(blockerId); + if (blocker != null) { + blocker.setBlocking(blocker.getBlocking() - 1); + } + } + blockers.clear(); + blockerOrder.clear(); + this.blocked = false; + game.informPlayers(attacker.getName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded."); + return; + } + } + for (UUID blockerId : blockers) { + for (UUID attackerId: attackers) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, attackerId, blockerId, players.get(blockerId))); + } + } + } + @Override public CombatGroup copy() { return new CombatGroup(this); diff --git a/Mage/src/mage/game/permanent/Permanent.java b/Mage/src/mage/game/permanent/Permanent.java index e106e42c949..45024072b8e 100644 --- a/Mage/src/mage/game/permanent/Permanent.java +++ b/Mage/src/mage/game/permanent/Permanent.java @@ -107,6 +107,8 @@ public interface Permanent extends Card { public void setBlocking(int blocking); public int getMaxBlocks(); public void setMaxBlocks(int maxBlocks); + public int getMinBlockedBy(); + public void setMinBlockedBy(int minBlockedBy); public boolean canAttack(Game game); public boolean canBlock(UUID attackerId, Game game); public boolean removeFromCombat(Game game); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 9a16fddb265..ed4e830beb3 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -68,6 +68,7 @@ public abstract class PermanentImpl> extends CardImpl protected boolean attacking; protected int blocking; protected int maxBlocks = 1; + protected int minBlockedBy = 1; protected boolean loyaltyUsed; protected boolean deathtouched; protected Counters counters; @@ -126,6 +127,7 @@ public abstract class PermanentImpl> extends CardImpl } } this.attachedTo = permanent.attachedTo; + this.minBlockedBy = permanent.minBlockedBy; } @Override @@ -142,6 +144,7 @@ public abstract class PermanentImpl> extends CardImpl else controllerChanged = false; this.maxBlocks = 1; + this.minBlockedBy = 1; } @Override @@ -378,6 +381,11 @@ public abstract class PermanentImpl> extends CardImpl return maxBlocks; } + @Override + public int getMinBlockedBy() { + return minBlockedBy; + } + @Override public UUID getControllerId() { return this.controllerId; @@ -701,6 +709,11 @@ public abstract class PermanentImpl> extends CardImpl this.maxBlocks = maxBlocks; } + @Override + public void setMinBlockedBy(int minBlockedBy) { + this.minBlockedBy = minBlockedBy; + } + @Override public boolean removeFromCombat(Game game) { game.getCombat().removeFromCombat(objectId, game); diff --git a/Mage/src/mage/game/turn/DeclareBlockersStep.java b/Mage/src/mage/game/turn/DeclareBlockersStep.java index 117cd588dfd..02bf01d72d7 100644 --- a/Mage/src/mage/game/turn/DeclareBlockersStep.java +++ b/Mage/src/mage/game/turn/DeclareBlockersStep.java @@ -61,6 +61,7 @@ public class DeclareBlockersStep extends Step { public void beginStep(Game game, UUID activePlayerId) { super.beginStep(game, activePlayerId); game.getCombat().selectBlockers(game); + game.getCombat().checkBlockRestrictions(game); game.getCombat().damageAssignmentOrder(game); }