diff --git a/Mage/src/mage/game/combat/CombatGroup.java b/Mage/src/mage/game/combat/CombatGroup.java index 00e5f65e91..82e8d1209a 100644 --- a/Mage/src/mage/game/combat/CombatGroup.java +++ b/Mage/src/mage/game/combat/CombatGroup.java @@ -146,7 +146,7 @@ public class CombatGroup implements Serializable, Copyable { return perm.getAbilities().containsKey(TrampleAbility.getInstance().getId()); } - public void assignDamage(boolean first, Game game) { + public void assignDamageToBlockers(boolean first, Game game) { if (attackers.size() > 0 && (!first || hasFirstOrDoubleStrike(game))) { if (blockers.size() == 0) { unblockedDamage(first, game); @@ -171,6 +171,21 @@ public class CombatGroup implements Serializable, Copyable { } } + public void applyDamage(Game game) { + for (UUID uuid : attackers) { + Permanent permanent = game.getPermanent(uuid); + if (permanent != null) { + permanent.applyDamage(game); + } + } + for (UUID uuid : blockers) { + Permanent permanent = game.getPermanent(uuid); + if (permanent != null) { + permanent.applyDamage(game); + } + } + } + /** * Determines if permanent can damage in current (First Strike or not) combat damage step * @@ -218,25 +233,25 @@ public class CombatGroup implements Serializable, Copyable { if (hasTrample(attacker)) { int lethalDamage = blocker.getToughness().getValue() - blocker.getDamage(); if (lethalDamage >= damage) { - blocker.damage(damage, attacker.getId(), game, true, true); + blocker.markDamage(damage, attacker.getId(), game, true, true); } else { Player player = game.getPlayer(attacker.getControllerId()); int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); - blocker.damage(damageAssigned, attacker.getId(), game, true, true); + blocker.markDamage(damageAssigned, attacker.getId(), game, true, true); damage -= damageAssigned; if (damage > 0) defenderDamage(attacker, damage, game); } } else { - blocker.damage(damage, attacker.getId(), game, true, true); + blocker.markDamage(damage, attacker.getId(), game, true, true); } } if (canDamage(blocker, first)) { if (blocker.getBlocking() == 1) { // blocking several creatures handled separately int blockerDamage = blocker.getPower().getValue(); - attacker.damage(blockerDamage, blocker.getId(), game, true, true); + attacker.markDamage(blockerDamage, blocker.getId(), game, true, true); } } } @@ -279,21 +294,21 @@ public class CombatGroup implements Serializable, Copyable { Permanent blocker = game.getPermanent(blockerId); if (canDamage(blocker, first)) { if (blocker.getBlocking() == 1) { // blocking several creatures handled separately - attacker.damage(blocker.getPower().getValue(), blocker.getId(), game, true, true); + attacker.markDamage(blocker.getPower().getValue(), blocker.getId(), game, true, true); } } } // Issue#73 for (Map.Entry entry : assigned.entrySet()) { Permanent blocker = game.getPermanent(entry.getKey()); - blocker.damage(entry.getValue(), attacker.getId(), game, true, true); + blocker.markDamage(entry.getValue(), attacker.getId(), game, true, true); } } else { for (UUID blockerId: blockerOrder) { Permanent blocker = game.getPermanent(blockerId); if (canDamage(blocker, first)) { - attacker.damage(blocker.getPower().getValue(), blocker.getId(), game, true, true); + attacker.markDamage(blocker.getPower().getValue(), blocker.getId(), game, true, true); } } } @@ -314,7 +329,7 @@ public class CombatGroup implements Serializable, Copyable { if (blocker != null && attacker != null) { if (canDamage(blocker, first)) { int damage = blocker.getPower().getValue(); - attacker.damage(damage, blocker.getId(), game, true, true); + attacker.markDamage(damage, blocker.getId(), game, true, true); } } } @@ -357,7 +372,7 @@ public class CombatGroup implements Serializable, Copyable { for (Map.Entry entry : assigned.entrySet()) { Permanent attacker = game.getPermanent(entry.getKey()); - attacker.damage(entry.getValue(), blocker.getId(), game, true, true); + attacker.markDamage(entry.getValue(), blocker.getId(), game, true, true); } } } @@ -366,7 +381,7 @@ public class CombatGroup implements Serializable, Copyable { if (this.defenderIsPlaneswalker) { Permanent defender = game.getPermanent(defenderId); if (defender != null) { - defender.damage(amount, attacker.getId(), game, true, true); + defender.markDamage(amount, attacker.getId(), game, true, true); } } else { diff --git a/Mage/src/mage/game/permanent/Permanent.java b/Mage/src/mage/game/permanent/Permanent.java index 45024072b8..2141aa46d1 100644 --- a/Mage/src/mage/game/permanent/Permanent.java +++ b/Mage/src/mage/game/permanent/Permanent.java @@ -75,6 +75,11 @@ public interface Permanent extends Card { public boolean hasSummoningSickness(); public int getDamage(); public int damage(int damage, UUID sourceId, Game game, boolean preventable, boolean combat); + + // used in combat only to deal damage at the same time + public int markDamage(int damage, UUID sourceId, Game game, boolean preventable, boolean combat); + public int applyDamage(Game game); + public void removeAllDamage(Game game); public Counters getCounters(); public void addCounters(String name, int amount, Game game); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index d8d26c6ecb..0e4a4284ed 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -44,10 +44,8 @@ import mage.game.events.*; import mage.game.events.GameEvent.EventType; import mage.players.Player; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; +import java.util.*; + import mage.Constants.AsThoughEffectType; /** @@ -78,6 +76,7 @@ public abstract class PermanentImpl> extends CardImpl protected List connectedCards = new ArrayList(); protected List dealtDamageByThisTurn; protected UUID attachedTo; + protected List markedDamage; private static final List emptyList = Collections.unmodifiableList(new ArrayList()); @@ -126,6 +125,12 @@ public abstract class PermanentImpl> extends CardImpl for (UUID sourceId : permanent.dealtDamageByThisTurn) { this.dealtDamageByThisTurn.add(sourceId); } + if (permanent.markedDamage != null) { + markedDamage = new ArrayList(); + for (Counter counter : permanent.markedDamage) { + markedDamage.add(counter.copy()); + } + } } this.attachedTo = permanent.attachedTo; this.minBlockedBy = permanent.minBlockedBy; @@ -505,12 +510,26 @@ public abstract class PermanentImpl> extends CardImpl @Override public int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat) { + return damage(damageAmount, sourceId, game, preventable, combat, false); + } + + /** + * + * @param damageAmount + * @param sourceId + * @param game + * @param preventable + * @param combat + * @param markDamage If true, damage will be dealt later in applyDamage method + * @return + */ + private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage) { int damageDone = 0; if (damageAmount > 0 && canDamage(game.getObject(sourceId))) { if (cardType.contains(CardType.PLANESWALKER)) { - damageDone = damagePlaneswalker(damageAmount, sourceId, game, preventable, combat); + damageDone = damagePlaneswalker(damageAmount, sourceId, game, preventable, combat, markDamage); } else { - damageDone = damageCreature(damageAmount, sourceId, game, preventable, combat); + damageDone = damageCreature(damageAmount, sourceId, game, preventable, combat, markDamage); } if (damageDone > 0) { Permanent source = game.getPermanent(sourceId); @@ -530,13 +549,31 @@ public abstract class PermanentImpl> extends CardImpl return damageDone; } + @Override + public int markDamage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat) { + return damage(damageAmount, sourceId, game, preventable, combat, true); + } + + @Override + public int applyDamage(Game game) { + if (markedDamage == null) { + return 0; + } + for (Counter counter : markedDamage) { + addCounters(counter, game); + } + markedDamage.clear(); + return 0; + } + + @Override public void removeAllDamage(Game game) { damage = 0; deathtouched = false; } - protected int damagePlaneswalker(int damage, UUID sourceId, Game game, boolean preventable, boolean combat) { + protected int damagePlaneswalker(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage) { GameEvent event = new DamagePlaneswalkerEvent(objectId, sourceId, controllerId, damage, preventable, combat); if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); @@ -553,23 +590,22 @@ public abstract class PermanentImpl> extends CardImpl return 0; } - protected int damageCreature(int damage, UUID sourceId, Game game, boolean preventable, boolean combat) { + protected int damageCreature(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage) { GameEvent event = new DamageCreatureEvent(objectId, sourceId, controllerId, damage, preventable, combat); if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); if (actualDamage > 0) { - // this is not correct - // from rules: The amount of damage dealt to a creature is not bounded by its toughness, - // and the amount of damage dealt to a player is not bounded by that player's life total. - // For example, if Corrupt deals 6 damage to a 2/2 creature, you'll gain 6 life. - /*if (this.damage + event.getAmount() > this.toughness.getValue()) { - actualDamage = this.toughness.getValue() - this.damage; - }*/ //Permanent source = game.getPermanent(sourceId); MageObject source = game.getObject(sourceId); if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId()) || source.getAbilities().containsKey(WitherAbility.getInstance().getId()))) { - addCounters(CounterType.M1M1.createInstance(actualDamage), game); + if (markDamage) { + // mark damage only + markDamage(CounterType.M1M1.createInstance(actualDamage)); + } else { + // deal damage immediately + addCounters(CounterType.M1M1.createInstance(actualDamage), game); + } } else { this.damage += actualDamage; } @@ -580,6 +616,13 @@ public abstract class PermanentImpl> extends CardImpl return 0; } + private void markDamage(Counter counter) { + if (markedDamage == null) { + markedDamage = new ArrayList(); + } + markedDamage.add(counter); + } + @Override public void entersBattlefield(UUID sourceId, Game game) { controlledFromStartOfTurn = false; diff --git a/Mage/src/mage/game/turn/CombatDamageStep.java b/Mage/src/mage/game/turn/CombatDamageStep.java index 7a72be5596..c733d5b715 100644 --- a/Mage/src/mage/game/turn/CombatDamageStep.java +++ b/Mage/src/mage/game/turn/CombatDamageStep.java @@ -68,11 +68,19 @@ public class CombatDamageStep extends Step { public void beginStep(Game game, UUID activePlayerId) { super.beginStep(game, activePlayerId); for (CombatGroup group: game.getCombat().getGroups()) { - group.assignDamage(first, game); + group.assignDamageToBlockers(first, game); } for (CombatGroup group : game.getCombat().getBlockingGroups()) { group.assignDamageToAttackers(first, game); } + + for (CombatGroup group: game.getCombat().getGroups()) { + group.applyDamage(game); + } + + for (CombatGroup group : game.getCombat().getBlockingGroups()) { + group.applyDamage(game); + } } public boolean getFirst() {