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());
}
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<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
*
@ -218,25 +233,25 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
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<CombatGroup> {
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<UUID, Integer> 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<CombatGroup> {
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<CombatGroup> {
for (Map.Entry<UUID, Integer> 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<CombatGroup> {
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 {

View file

@ -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);

View file

@ -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<T extends PermanentImpl<T>> extends CardImpl
protected List<UUID> connectedCards = new ArrayList<UUID>();
protected List<UUID> dealtDamageByThisTurn;
protected UUID attachedTo;
protected List<Counter> markedDamage;
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) {
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.minBlockedBy = permanent.minBlockedBy;
@ -505,12 +510,26 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> 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<T extends PermanentImpl<T>> 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<T extends PermanentImpl<T>> 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()))) {
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<T extends PermanentImpl<T>> extends CardImpl
return 0;
}
private void markDamage(Counter counter) {
if (markedDamage == null) {
markedDamage = new ArrayList<Counter>();
}
markedDamage.add(counter);
}
@Override
public void entersBattlefield(UUID sourceId, Game game) {
controlledFromStartOfTurn = false;

View file

@ -68,11 +68,19 @@ public class CombatDamageStep extends Step<CombatDamageStep> {
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() {