Dealing combat damage at the same time. Fixed Issue 236. Note: implemented only for damage resultings.

This commit is contained in:
magenoxx 2011-09-01 14:14:31 +04:00
parent c207060611
commit 2e97eb38fd
4 changed files with 99 additions and 28 deletions

View file

@ -146,7 +146,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
return perm.getAbilities().containsKey(TrampleAbility.getInstance().getId()); 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 (attackers.size() > 0 && (!first || hasFirstOrDoubleStrike(game))) {
if (blockers.size() == 0) { if (blockers.size() == 0) {
unblockedDamage(first, game); unblockedDamage(first, game);
@ -171,6 +171,21 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
} }
} }
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 * Determines if permanent can damage in current (First Strike or not) combat damage step
* *
@ -218,25 +233,25 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
if (hasTrample(attacker)) { if (hasTrample(attacker)) {
int lethalDamage = blocker.getToughness().getValue() - blocker.getDamage(); int lethalDamage = blocker.getToughness().getValue() - blocker.getDamage();
if (lethalDamage >= damage) { if (lethalDamage >= damage) {
blocker.damage(damage, attacker.getId(), game, true, true); blocker.markDamage(damage, attacker.getId(), game, true, true);
} }
else { else {
Player player = game.getPlayer(attacker.getControllerId()); Player player = game.getPlayer(attacker.getControllerId());
int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); 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; damage -= damageAssigned;
if (damage > 0) if (damage > 0)
defenderDamage(attacker, damage, game); defenderDamage(attacker, damage, game);
} }
} }
else { else {
blocker.damage(damage, attacker.getId(), game, true, true); blocker.markDamage(damage, attacker.getId(), game, true, true);
} }
} }
if (canDamage(blocker, first)) { if (canDamage(blocker, first)) {
if (blocker.getBlocking() == 1) { // blocking several creatures handled separately if (blocker.getBlocking() == 1) { // blocking several creatures handled separately
int blockerDamage = blocker.getPower().getValue(); 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<CombatGroup> {
Permanent blocker = game.getPermanent(blockerId); Permanent blocker = game.getPermanent(blockerId);
if (canDamage(blocker, first)) { if (canDamage(blocker, first)) {
if (blocker.getBlocking() == 1) { // blocking several creatures handled separately 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 // Issue#73
for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) { for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) {
Permanent blocker = game.getPermanent(entry.getKey()); 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 { else {
for (UUID blockerId: blockerOrder) { for (UUID blockerId: blockerOrder) {
Permanent blocker = game.getPermanent(blockerId); Permanent blocker = game.getPermanent(blockerId);
if (canDamage(blocker, first)) { 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<CombatGroup> {
if (blocker != null && attacker != null) { if (blocker != null && attacker != null) {
if (canDamage(blocker, first)) { if (canDamage(blocker, first)) {
int damage = blocker.getPower().getValue(); 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<CombatGroup> {
for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) { for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) {
Permanent attacker = game.getPermanent(entry.getKey()); 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<CombatGroup> {
if (this.defenderIsPlaneswalker) { if (this.defenderIsPlaneswalker) {
Permanent defender = game.getPermanent(defenderId); Permanent defender = game.getPermanent(defenderId);
if (defender != null) { if (defender != null) {
defender.damage(amount, attacker.getId(), game, true, true); defender.markDamage(amount, attacker.getId(), game, true, true);
} }
} }
else { else {

View file

@ -75,6 +75,11 @@ public interface Permanent extends Card {
public boolean hasSummoningSickness(); public boolean hasSummoningSickness();
public int getDamage(); public int getDamage();
public int damage(int damage, UUID sourceId, Game game, boolean preventable, boolean combat); 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 void removeAllDamage(Game game);
public Counters getCounters(); public Counters getCounters();
public void addCounters(String name, int amount, Game game); public void addCounters(String name, int amount, Game game);

View file

@ -44,10 +44,8 @@ import mage.game.events.*;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.players.Player; import mage.players.Player;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import mage.Constants.AsThoughEffectType; import mage.Constants.AsThoughEffectType;
/** /**
@ -78,6 +76,7 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
protected List<UUID> connectedCards = new ArrayList<UUID>(); protected List<UUID> connectedCards = new ArrayList<UUID>();
protected List<UUID> dealtDamageByThisTurn; protected List<UUID> dealtDamageByThisTurn;
protected UUID attachedTo; protected UUID attachedTo;
protected List<Counter> markedDamage;
private static final List<UUID> emptyList = Collections.unmodifiableList(new ArrayList<UUID>()); private static final List<UUID> emptyList = Collections.unmodifiableList(new ArrayList<UUID>());
@ -126,6 +125,12 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
for (UUID sourceId : permanent.dealtDamageByThisTurn) { for (UUID sourceId : permanent.dealtDamageByThisTurn) {
this.dealtDamageByThisTurn.add(sourceId); this.dealtDamageByThisTurn.add(sourceId);
} }
if (permanent.markedDamage != null) {
markedDamage = new ArrayList<Counter>();
for (Counter counter : permanent.markedDamage) {
markedDamage.add(counter.copy());
}
}
} }
this.attachedTo = permanent.attachedTo; this.attachedTo = permanent.attachedTo;
this.minBlockedBy = permanent.minBlockedBy; this.minBlockedBy = permanent.minBlockedBy;
@ -505,12 +510,26 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
@Override @Override
public int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat) { 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; int damageDone = 0;
if (damageAmount > 0 && canDamage(game.getObject(sourceId))) { if (damageAmount > 0 && canDamage(game.getObject(sourceId))) {
if (cardType.contains(CardType.PLANESWALKER)) { if (cardType.contains(CardType.PLANESWALKER)) {
damageDone = damagePlaneswalker(damageAmount, sourceId, game, preventable, combat); damageDone = damagePlaneswalker(damageAmount, sourceId, game, preventable, combat, markDamage);
} else { } else {
damageDone = damageCreature(damageAmount, sourceId, game, preventable, combat); damageDone = damageCreature(damageAmount, sourceId, game, preventable, combat, markDamage);
} }
if (damageDone > 0) { if (damageDone > 0) {
Permanent source = game.getPermanent(sourceId); Permanent source = game.getPermanent(sourceId);
@ -530,13 +549,31 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
return damageDone; 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 @Override
public void removeAllDamage(Game game) { public void removeAllDamage(Game game) {
damage = 0; damage = 0;
deathtouched = false; 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); GameEvent event = new DamagePlaneswalkerEvent(objectId, sourceId, controllerId, damage, preventable, combat);
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
int actualDamage = event.getAmount(); int actualDamage = event.getAmount();
@ -553,23 +590,22 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
return 0; 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); GameEvent event = new DamageCreatureEvent(objectId, sourceId, controllerId, damage, preventable, combat);
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
int actualDamage = event.getAmount(); int actualDamage = event.getAmount();
if (actualDamage > 0) { 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); //Permanent source = game.getPermanent(sourceId);
MageObject source = game.getObject(sourceId); MageObject source = game.getObject(sourceId);
if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId()) if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId())
|| source.getAbilities().containsKey(WitherAbility.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 { } else {
this.damage += actualDamage; this.damage += actualDamage;
} }
@ -580,6 +616,13 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
return 0; return 0;
} }
private void markDamage(Counter counter) {
if (markedDamage == null) {
markedDamage = new ArrayList<Counter>();
}
markedDamage.add(counter);
}
@Override @Override
public void entersBattlefield(UUID sourceId, Game game) { public void entersBattlefield(UUID sourceId, Game game) {
controlledFromStartOfTurn = false; controlledFromStartOfTurn = false;

View file

@ -68,11 +68,19 @@ public class CombatDamageStep extends Step<CombatDamageStep> {
public void beginStep(Game game, UUID activePlayerId) { public void beginStep(Game game, UUID activePlayerId) {
super.beginStep(game, activePlayerId); super.beginStep(game, activePlayerId);
for (CombatGroup group: game.getCombat().getGroups()) { for (CombatGroup group: game.getCombat().getGroups()) {
group.assignDamage(first, game); group.assignDamageToBlockers(first, game);
} }
for (CombatGroup group : game.getCombat().getBlockingGroups()) { for (CombatGroup group : game.getCombat().getBlockingGroups()) {
group.assignDamageToAttackers(first, game); 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() { public boolean getFirst() {