mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Big Damage Rewrite Part 2: now use CombatDamageMap everywhere
This commit is contained in:
@@ -20,6 +20,7 @@ package forge.game;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.event.GameEventCardAttachment;
|
import forge.game.event.GameEventCardAttachment;
|
||||||
import forge.game.event.GameEventCardAttachment.AttachMethod;
|
import forge.game.event.GameEventCardAttachment.AttachMethod;
|
||||||
@@ -55,22 +56,51 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
getView().updateName(this);
|
getView().updateName(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int addDamage(final int damage, final Card source) {
|
public int addDamage(final int damage, final Card source, final CardDamageMap damageMap) {
|
||||||
int damageToDo = damage;
|
int damageToDo = damage;
|
||||||
|
|
||||||
damageToDo = replaceDamage(damageToDo, source, false);
|
damageToDo = replaceDamage(damageToDo, source, false, true, damageMap);
|
||||||
damageToDo = preventDamage(damageToDo, source, false);
|
damageToDo = preventDamage(damageToDo, source, false);
|
||||||
|
|
||||||
return addDamageAfterPrevention(damageToDo, source, false);
|
return addDamageAfterPrevention(damageToDo, source, false, damageMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int addDamageWithoutPrevention(final int damage, final Card source) {
|
public int addDamageWithoutPrevention(final int damage, final Card source, final CardDamageMap damageMap) {
|
||||||
int damageToDo = replaceDamage(damage, source, false);
|
int damageToDo = replaceDamage(damage, source, false, false, damageMap);
|
||||||
return addDamageAfterPrevention(damageToDo, source, false);
|
return addDamageAfterPrevention(damageToDo, source, false, damageMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int replaceDamage(final int damage, final Card source, final boolean isCombat, final boolean prevention, final CardDamageMap damageMap) {
|
||||||
|
// Replacement effects
|
||||||
|
final Map<String, Object> repParams = Maps.newHashMap();
|
||||||
|
repParams.put("Event", "DamageDone");
|
||||||
|
repParams.put("Affected", this);
|
||||||
|
repParams.put("DamageSource", source);
|
||||||
|
repParams.put("DamageAmount", damage);
|
||||||
|
repParams.put("IsCombat", isCombat);
|
||||||
|
|
||||||
|
switch (getGame().getReplacementHandler().run(repParams)) {
|
||||||
|
case NotReplaced:
|
||||||
|
return damage;
|
||||||
|
case Updated:
|
||||||
|
int newDamage = (int) repParams.get("DamageAmount");
|
||||||
|
GameEntity newTarget = (GameEntity)repParams.get("Affected");
|
||||||
|
// check if this is still the affected card or player
|
||||||
|
if (this.equals(newTarget)) {
|
||||||
|
return newDamage;
|
||||||
|
} else {
|
||||||
|
if (prevention) {
|
||||||
|
newDamage = newTarget.preventDamage(newDamage, source, isCombat);
|
||||||
|
}
|
||||||
|
newTarget.addDamageAfterPrevention(newDamage, source, isCombat, damageMap);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function handles damage after replacement and prevention effects are applied
|
// This function handles damage after replacement and prevention effects are applied
|
||||||
public abstract int addDamageAfterPrevention(final int damage, final Card source, final boolean isCombat);
|
public abstract int addDamageAfterPrevention(final int damage, final Card source, final boolean isCombat, CardDamageMap damageMap);
|
||||||
|
|
||||||
// This should be also usable by the AI to forecast an effect (so it must
|
// This should be also usable by the AI to forecast an effect (so it must
|
||||||
// not change the game state)
|
// not change the game state)
|
||||||
@@ -80,8 +110,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
// not change the game state)
|
// not change the game state)
|
||||||
public abstract int staticReplaceDamage(final int damage, final Card source, final boolean isCombat);
|
public abstract int staticReplaceDamage(final int damage, final Card source, final boolean isCombat);
|
||||||
|
|
||||||
public abstract int replaceDamage(final int damage, final Card source, final boolean isCombat);
|
|
||||||
|
|
||||||
public abstract int preventDamage(final int damage, final Card source, final boolean isCombat);
|
public abstract int preventDamage(final int damage, final Card source, final boolean isCombat);
|
||||||
|
|
||||||
public int getPreventNextDamage() {
|
public int getPreventNextDamage() {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.GameEntity;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
@@ -26,19 +28,20 @@ public class DamageAllEffect extends SpellAbilityEffect {
|
|||||||
final String damage = sa.getParam("NumDmg");
|
final String damage = sa.getParam("NumDmg");
|
||||||
final int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
|
final int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
|
||||||
|
|
||||||
|
final String definedStr = sa.getParam("DamageSource");
|
||||||
|
final List<Card> definedSources = AbilityUtils.getDefinedCards(sa.getHostCard(), definedStr, sa);
|
||||||
|
|
||||||
final List<Card> definedSources = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DamageSource"), sa);
|
if (!definedSources.isEmpty() && definedSources.get(0) != sa.getHostCard()) {
|
||||||
final Card source = definedSources.get(0);
|
sb.append(definedSources.get(0).toString()).append(" deals");
|
||||||
|
} else if ("ParentTarget".equals(definedStr)){
|
||||||
if (source != sa.getHostCard()) {
|
sb.append("Target creature deals");
|
||||||
sb.append(source.toString()).append(" deals");
|
|
||||||
} else {
|
} else {
|
||||||
sb.append("Deals");
|
sb.append("Deals");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(" ").append(dmg).append(" damage to ").append(desc);
|
sb.append(" ").append(dmg).append(" damage to ").append(desc);
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -77,28 +80,30 @@ public class DamageAllEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
list = AbilityUtils.filterListByType(list, sa.getParam("ValidCards"), sa);
|
list = AbilityUtils.filterListByType(list, sa.getParam("ValidCards"), sa);
|
||||||
|
|
||||||
int damageSum = 0;
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
|
|
||||||
for (final Card c : list) {
|
for (final Card c : list) {
|
||||||
int cardDamage = c.addDamage(dmg, sourceLKI);
|
c.addDamage(dmg, sourceLKI, damageMap);
|
||||||
damageSum += cardDamage;
|
|
||||||
if (cardDamage > 0 && rememberCard) {
|
|
||||||
source.addRemembered(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!players.equals("")) {
|
if (!players.equals("")) {
|
||||||
final List<Player> playerList = AbilityUtils.getDefinedPlayers(card, players, sa);
|
final List<Player> playerList = AbilityUtils.getDefinedPlayers(card, players, sa);
|
||||||
for (final Player p : playerList) {
|
for (final Player p : playerList) {
|
||||||
int playerDamage = p.addDamage(dmg, sourceLKI);
|
p.addDamage(dmg, sourceLKI, damageMap);
|
||||||
damageSum += playerDamage;
|
}
|
||||||
if (playerDamage > 0 && rememberPlayer) {
|
}
|
||||||
source.addRemembered(p);
|
|
||||||
|
// do Remember there
|
||||||
|
if (rememberCard || rememberPlayer) {
|
||||||
|
for (GameEntity e : damageMap.row(sourceLKI).keySet()) {
|
||||||
|
if (e instanceof Card && rememberCard) {
|
||||||
|
source.addRemembered(e);
|
||||||
|
} else if (e instanceof Player && rememberPlayer) {
|
||||||
|
source.addRemembered(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damageSum > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
damageMap.dealLifelinkDamage();
|
||||||
source.getController().gainLife(damageSum, sourceLKI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import forge.game.Game;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.util.Lang;
|
import forge.util.Lang;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -35,10 +36,9 @@ public class DamageDealEffect extends SpellAbilityEffect {
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
final List<Card> definedSources = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DamageSource"), sa);
|
final List<Card> definedSources = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DamageSource"), sa);
|
||||||
Card source = definedSources.isEmpty() ? new Card(-1, sa.getHostCard().getGame()) : definedSources.get(0);
|
|
||||||
|
|
||||||
if (source != sa.getHostCard()) {
|
if (!definedSources.isEmpty() && definedSources.get(0) != sa.getHostCard()) {
|
||||||
sb.append(source.toString()).append(" deals");
|
sb.append(definedSources.get(0).toString()).append(" deals");
|
||||||
} else {
|
} else {
|
||||||
sb.append("Deals");
|
sb.append("Deals");
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,9 @@ public class DamageDealEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
|
final Card hostCard = sa.getHostCard();
|
||||||
|
final Game game = hostCard.getGame();
|
||||||
|
|
||||||
final String damage = sa.getParam("NumDmg");
|
final String damage = sa.getParam("NumDmg");
|
||||||
int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
|
int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
|
||||||
|
|
||||||
@@ -120,7 +123,8 @@ public class DamageDealEffect extends SpellAbilityEffect {
|
|||||||
final Card source = definedSources.get(0);
|
final Card source = definedSources.get(0);
|
||||||
final Card sourceLKI = sa.getHostCard().getGame().getChangeZoneLKIInfo(definedSources.get(0));
|
final Card sourceLKI = sa.getHostCard().getGame().getChangeZoneLKIInfo(definedSources.get(0));
|
||||||
|
|
||||||
int damageSum = 0;
|
// make a new damage map, combat damage will be applied later into combat map
|
||||||
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
|
|
||||||
if (divideOnResolution) {
|
if (divideOnResolution) {
|
||||||
// Dividing Damage up to multiple targets using combat damage box
|
// Dividing Damage up to multiple targets using combat damage box
|
||||||
@@ -141,12 +145,15 @@ public class DamageDealEffect extends SpellAbilityEffect {
|
|||||||
Player assigningPlayer = players.get(0);
|
Player assigningPlayer = players.get(0);
|
||||||
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(sourceLKI, assigneeCards, dmg, null, true);
|
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(sourceLKI, assigneeCards, dmg, null, true);
|
||||||
for (Entry<Card, Integer> dt : map.entrySet()) {
|
for (Entry<Card, Integer> dt : map.entrySet()) {
|
||||||
damageSum += dt.getKey().addDamage(dt.getValue(), sourceLKI);
|
dt.getKey().addDamage(dt.getValue(), sourceLKI, damageMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// non combat damage cause lifegain there
|
// transport combat damage back into combat damage map
|
||||||
if (!combatDmg && damageSum > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
if (combatDmg) {
|
||||||
sourceLKI.getController().gainLife(damageSum, sourceLKI);
|
game.getCombat().getDamageMap().putAll(damageMap);
|
||||||
|
} else {
|
||||||
|
// non combat damage cause lifegain there
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,55 +169,39 @@ public class DamageDealEffect extends SpellAbilityEffect {
|
|||||||
c.clearAssignedDamage();
|
c.clearAssignedDamage();
|
||||||
}
|
}
|
||||||
else if (noPrevention) {
|
else if (noPrevention) {
|
||||||
int damagePrev = c.addDamageWithoutPrevention(dmg, sourceLKI);
|
c.addDamageWithoutPrevention(dmg, sourceLKI, damageMap);
|
||||||
damageSum += damagePrev;
|
|
||||||
if (damagePrev > 0 && remember) {
|
|
||||||
source.addRemembered(c);
|
|
||||||
}
|
|
||||||
} else if (combatDmg) {
|
} else if (combatDmg) {
|
||||||
HashMap<Card, Integer> combatmap = Maps.newHashMap();
|
Map<Card, Integer> combatmap = Maps.newHashMap();
|
||||||
combatmap.put(sourceLKI, dmg);
|
combatmap.put(sourceLKI, dmg);
|
||||||
c.addCombatDamage(combatmap);
|
c.addCombatDamage(combatmap, damageMap);
|
||||||
if (remember) {
|
|
||||||
source.addRemembered(c);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
int damageDealt = c.addDamage(dmg, sourceLKI);
|
c.addDamage(dmg, sourceLKI, damageMap);
|
||||||
damageSum += damageDealt;
|
|
||||||
if (damageDealt > 0 && remember) {
|
|
||||||
source.addRemembered(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (o instanceof Player) {
|
} else if (o instanceof Player) {
|
||||||
final Player p = (Player) o;
|
final Player p = (Player) o;
|
||||||
if (!targeted || p.canBeTargetedBy(sa)) {
|
if (!targeted || p.canBeTargetedBy(sa)) {
|
||||||
if (noPrevention) {
|
if (noPrevention) {
|
||||||
int damagePrev = p.addDamageWithoutPrevention(dmg, sourceLKI);
|
p.addDamageWithoutPrevention(dmg, sourceLKI, damageMap);
|
||||||
damageSum += damagePrev;
|
|
||||||
if (damagePrev > 0 && remember) {
|
|
||||||
source.addRemembered(p);
|
|
||||||
}
|
|
||||||
} else if (combatDmg) {
|
} else if (combatDmg) {
|
||||||
p.addCombatDamage(dmg, sourceLKI);
|
p.addCombatDamage(dmg, sourceLKI, damageMap);
|
||||||
if (remember) {
|
|
||||||
source.addRemembered(p);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
int damageDealt = p.addDamage(dmg, sourceLKI);
|
p.addDamage(dmg, sourceLKI, damageMap);
|
||||||
damageSum += damageDealt;
|
|
||||||
if (damageDealt > 0 && remember) {
|
|
||||||
source.addRemembered(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// non combat damage cause lifegain there
|
if (remember) {
|
||||||
if (!combatDmg && damageSum > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
source.addRemembered(damageMap.row(sourceLKI).keySet());
|
||||||
sourceLKI.getController().gainLife(damageSum, sourceLKI);
|
}
|
||||||
|
|
||||||
|
// transport combat damage back into combat damage map
|
||||||
|
if (combatDmg) {
|
||||||
|
game.getCombat().getDamageMap().putAll(damageMap);
|
||||||
|
} else {
|
||||||
|
// non combat damage cause lifegain there
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import forge.game.GameObject;
|
|||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.card.CardFactoryUtil;
|
import forge.game.card.CardFactoryUtil;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -69,29 +70,27 @@ public class DamageEachEffect extends SpellAbilityEffect {
|
|||||||
final List<GameObject> tgts = getTargets(sa, "DefinedPlayers");
|
final List<GameObject> tgts = getTargets(sa, "DefinedPlayers");
|
||||||
|
|
||||||
final boolean targeted = (sa.usesTargeting());
|
final boolean targeted = (sa.usesTargeting());
|
||||||
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
|
|
||||||
for (final Object o : tgts) {
|
for (final Object o : tgts) {
|
||||||
for (final Card source : sources) {
|
for (final Card source : sources) {
|
||||||
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
|
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
|
||||||
|
|
||||||
final int dmg = CardFactoryUtil.xCount(source, sa.getSVar("X"));
|
final int dmg = CardFactoryUtil.xCount(source, sa.getSVar("X"));
|
||||||
int damageSum = 0;
|
|
||||||
// System.out.println(source+" deals "+dmg+" damage to "+o.toString());
|
// System.out.println(source+" deals "+dmg+" damage to "+o.toString());
|
||||||
if (o instanceof Card) {
|
if (o instanceof Card) {
|
||||||
final Card c = (Card) o;
|
final Card c = (Card) o;
|
||||||
if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) {
|
if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) {
|
||||||
damageSum += c.addDamage(dmg, sourceLKI);
|
c.addDamage(dmg, sourceLKI, damageMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (o instanceof Player) {
|
} else if (o instanceof Player) {
|
||||||
final Player p = (Player) o;
|
final Player p = (Player) o;
|
||||||
if (!targeted || p.canBeTargetedBy(sa)) {
|
if (!targeted || p.canBeTargetedBy(sa)) {
|
||||||
damageSum += p.addDamage(dmg, sourceLKI);
|
p.addDamage(dmg, sourceLKI, damageMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (damageSum > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
|
||||||
sourceLKI.getController().gainLife(damageSum, sourceLKI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +101,7 @@ public class DamageEachEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
|
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
|
||||||
// System.out.println(source+" deals "+dmg+" damage to "+source);
|
// System.out.println(source+" deals "+dmg+" damage to "+source);
|
||||||
int damage = source.addDamage(dmg, sourceLKI);
|
source.addDamage(dmg, sourceLKI, damageMap);
|
||||||
if (damage > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
|
||||||
sourceLKI.getController().gainLife(damage, sourceLKI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sa.getParam("DefinedCards").equals("Remembered")) {
|
if (sa.getParam("DefinedCards").equals("Remembered")) {
|
||||||
@@ -113,20 +109,17 @@ public class DamageEachEffect extends SpellAbilityEffect {
|
|||||||
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
|
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
|
||||||
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
|
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
|
||||||
|
|
||||||
Card rememberedcard;
|
|
||||||
int damageSum = 0;
|
|
||||||
for (final Object o : sa.getHostCard().getRemembered()) {
|
for (final Object o : sa.getHostCard().getRemembered()) {
|
||||||
if (o instanceof Card) {
|
if (o instanceof Card) {
|
||||||
rememberedcard = (Card) o;
|
Card rememberedcard = (Card) o;
|
||||||
// System.out.println(source + " deals " + dmg + " damage to " + rememberedcard);
|
// System.out.println(source + " deals " + dmg + " damage to " + rememberedcard);
|
||||||
damageSum += rememberedcard.addDamage(dmg, sourceLKI);
|
rememberedcard.addDamage(dmg, sourceLKI, damageMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (damageSum > 0 && sourceLKI.hasKeyword("Lifelink")) {
|
|
||||||
sourceLKI.getController().gainLife(damageSum, sourceLKI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ import forge.game.Game;
|
|||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class FightEffect extends SpellAbilityEffect {
|
public class FightEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@@ -52,14 +53,17 @@ public class FightEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean fightToughness = sa.hasParam("FightWithToughness");
|
boolean fightToughness = sa.hasParam("FightWithToughness");
|
||||||
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
|
|
||||||
dealDamage(fighters.get(0), fighters.get(1), fightToughness);
|
dealDamage(fighters.get(0), fighters.get(1), fightToughness, damageMap);
|
||||||
dealDamage(fighters.get(1), fighters.get(0), fightToughness);
|
dealDamage(fighters.get(1), fighters.get(0), fightToughness, damageMap);
|
||||||
|
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
|
|
||||||
for (Card c : fighters) {
|
for (Card c : fighters) {
|
||||||
final HashMap<String, Object> runParams = Maps.newHashMap();
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
runParams.put("Fighter", c);
|
runParams.put("Fighter", c);
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.Fight, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.Fight, runParams, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,14 +110,10 @@ public class FightEffect extends SpellAbilityEffect {
|
|||||||
return fighterList;
|
return fighterList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dealDamage(Card source, Card target, boolean fightToughness) {
|
private void dealDamage(Card source, Card target, boolean fightToughness, CardDamageMap damageMap) {
|
||||||
final int dmg = fightToughness ? source.getNetToughness() : source.getNetPower();
|
final int dmg = fightToughness ? source.getNetToughness() : source.getNetPower();
|
||||||
|
|
||||||
int damageDealt = target.addDamage(dmg, source);
|
target.addDamage(dmg, source, damageMap);
|
||||||
|
|
||||||
if (damageDealt > 0 && source.hasKeyword("Lifelink")) {
|
|
||||||
source.getController().gainLife(damageDealt, source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5844,12 +5844,12 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void addCombatDamage(final Map<Card, Integer> map) {
|
public final void addCombatDamage(final Map<Card, Integer> map, CardDamageMap damageMap) {
|
||||||
for (final Entry<Card, Integer> entry : map.entrySet()) {
|
for (final Entry<Card, Integer> entry : map.entrySet()) {
|
||||||
final Card source = entry.getKey();
|
final Card source = entry.getKey();
|
||||||
int damageToAdd = entry.getValue();
|
int damageToAdd = entry.getValue();
|
||||||
|
|
||||||
damageToAdd = replaceDamage(damageToAdd, source, true);
|
damageToAdd = replaceDamage(damageToAdd, source, true, true, damageMap);
|
||||||
damageToAdd = preventDamage(damageToAdd, source, true);
|
damageToAdd = preventDamage(damageToAdd, source, true);
|
||||||
|
|
||||||
if (damageToAdd > 0) {
|
if (damageToAdd > 0) {
|
||||||
@@ -5859,7 +5859,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isInPlay()) {
|
if (isInPlay()) {
|
||||||
addDamage(map);
|
addDamage(map, damageMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6142,33 +6142,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return restDamage;
|
return restDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public final void addDamage(final Map<Card, Integer> sourcesMap, CardDamageMap damageMap) {
|
||||||
public final int replaceDamage(final int damageIn, final Card source, final boolean isCombat) {
|
|
||||||
// Replacement effects
|
|
||||||
final Map<String, Object> repParams = Maps.newHashMap();
|
|
||||||
repParams.put("Event", "DamageDone");
|
|
||||||
repParams.put("Affected", this);
|
|
||||||
repParams.put("DamageSource", source);
|
|
||||||
repParams.put("DamageAmount", damageIn);
|
|
||||||
repParams.put("IsCombat", isCombat);
|
|
||||||
|
|
||||||
switch (getGame().getReplacementHandler().run(repParams)) {
|
|
||||||
case NotReplaced:
|
|
||||||
return damageIn;
|
|
||||||
case Updated:
|
|
||||||
// check if this is still the affected card
|
|
||||||
if (this.equals(repParams.get("Affected"))) {
|
|
||||||
return (int) repParams.get("DamageAmount");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void addDamage(final Map<Card, Integer> sourcesMap) {
|
|
||||||
for (final Entry<Card, Integer> entry : sourcesMap.entrySet()) {
|
for (final Entry<Card, Integer> entry : sourcesMap.entrySet()) {
|
||||||
// damage prevention is already checked!
|
// damage prevention is already checked!
|
||||||
addDamageAfterPrevention(entry.getValue(), entry.getKey(), true);
|
addDamageAfterPrevention(entry.getValue(), entry.getKey(), true, damageMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6177,7 +6154,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
* applied.
|
* applied.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final int addDamageAfterPrevention(final int damageIn, final Card source, final boolean isCombat) {
|
public final int addDamageAfterPrevention(final int damageIn, final Card source, final boolean isCombat, CardDamageMap damageMap) {
|
||||||
|
|
||||||
if (damageIn == 0) {
|
if (damageIn == 0) {
|
||||||
return 0; // Rule 119.8
|
return 0; // Rule 119.8
|
||||||
@@ -6185,9 +6162,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
|
|
||||||
addReceivedDamageFromThisTurn(source, damageIn);
|
addReceivedDamageFromThisTurn(source, damageIn);
|
||||||
source.addDealtDamageToThisTurn(this, damageIn);
|
source.addDealtDamageToThisTurn(this, damageIn);
|
||||||
if (isCombat) {
|
|
||||||
game.getCombat().addDealtDamageTo(source, this, damageIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
final Map<String, Object> runParams = Maps.newTreeMap();
|
final Map<String, Object> runParams = Maps.newTreeMap();
|
||||||
@@ -6231,6 +6205,11 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
// Play the Damage sound
|
// Play the Damage sound
|
||||||
game.fireEvent(new GameEventCardDamaged(this, source, damageIn, damageType));
|
game.fireEvent(new GameEventCardDamaged(this, source, damageIn, damageType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (damageIn > 0) {
|
||||||
|
damageMap.put(source, this, damageIn);
|
||||||
|
}
|
||||||
|
|
||||||
return damageIn;
|
return damageIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.HashBasedTable;
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
@@ -40,6 +39,7 @@ import forge.game.GameObjectMap;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
@@ -68,7 +68,7 @@ public class Combat {
|
|||||||
private Map<Card, CardCollection> attackersOrderedForDamageAssignment = Maps.newHashMap();
|
private Map<Card, CardCollection> attackersOrderedForDamageAssignment = Maps.newHashMap();
|
||||||
private Map<Card, CardCollection> blockersOrderedForDamageAssignment = Maps.newHashMap();
|
private Map<Card, CardCollection> blockersOrderedForDamageAssignment = Maps.newHashMap();
|
||||||
private Map<GameEntity, CombatLki> lkiCache = Maps.newHashMap();
|
private Map<GameEntity, CombatLki> lkiCache = Maps.newHashMap();
|
||||||
private Table<Card, GameEntity, Integer> dealtDamageTo = HashBasedTable.create();
|
private CardDamageMap dealtDamageTo = new CardDamageMap();
|
||||||
|
|
||||||
// List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW)
|
// List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW)
|
||||||
private CardCollection combatantsThatDealtFirstStrikeDamage = new CardCollection();
|
private CardCollection combatantsThatDealtFirstStrikeDamage = new CardCollection();
|
||||||
@@ -716,45 +716,21 @@ public class Combat {
|
|||||||
return assignedDamage;
|
return assignedDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void addDealtDamageTo(final Card source, final GameEntity ge, final int dmg) {
|
public final CardDamageMap getDamageMap() {
|
||||||
int old = dealtDamageTo.contains(source, ge) ? dealtDamageTo.get(source, ge) : 0;
|
return dealtDamageTo;
|
||||||
dealtDamageTo.put(source, ge, dmg + old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dealAssignedDamage() {
|
public void dealAssignedDamage() {
|
||||||
playerWhoAttacks.getGame().copyLastState();
|
playerWhoAttacks.getGame().copyLastState();
|
||||||
|
|
||||||
// This function handles both Regular and First Strike combat assignment
|
// This function handles both Regular and First Strike combat assignment
|
||||||
final Map<Card, Integer> defMap = defendingDamageMap;
|
for (final Entry<Card, Integer> entry : defendingDamageMap.entrySet()) {
|
||||||
final Map<GameEntity, CardCollection> wasDamaged = Maps.newHashMap();
|
|
||||||
|
|
||||||
for (final Entry<Card, Integer> entry : defMap.entrySet()) {
|
|
||||||
GameEntity defender = getDefenderByAttacker(entry.getKey());
|
GameEntity defender = getDefenderByAttacker(entry.getKey());
|
||||||
if (defender instanceof Player) { // player
|
if (defender instanceof Player) { // player
|
||||||
int dmg = ((Player) defender).addCombatDamage(entry.getValue(), entry.getKey());
|
((Player) defender).addCombatDamage(entry.getValue(), entry.getKey(), dealtDamageTo);
|
||||||
if (dmg > 0) {
|
|
||||||
if (wasDamaged.containsKey(defender)) {
|
|
||||||
wasDamaged.get(defender).add(entry.getKey());
|
|
||||||
} else {
|
|
||||||
CardCollection l = new CardCollection();
|
|
||||||
l.add(entry.getKey());
|
|
||||||
wasDamaged.put(defender, l);
|
|
||||||
}
|
|
||||||
this.addDealtDamageTo(entry.getKey(), defender, entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (defender instanceof Card) { // planeswalker
|
else if (defender instanceof Card) { // planeswalker
|
||||||
int dmg = ((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey());
|
((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey(), dealtDamageTo);
|
||||||
if (dmg > 0) {
|
|
||||||
if (wasDamaged.containsKey(defender)) {
|
|
||||||
wasDamaged.get(defender).add(entry.getKey());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CardCollection l = new CardCollection();
|
|
||||||
l.add(entry.getKey());
|
|
||||||
wasDamaged.put(defender, l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,41 +741,39 @@ public class Combat {
|
|||||||
combatants.addAll(getAllBlockers());
|
combatants.addAll(getAllBlockers());
|
||||||
combatants.addAll(getDefendingPlaneswalkers());
|
combatants.addAll(getDefendingPlaneswalkers());
|
||||||
|
|
||||||
Card c;
|
for (final Card c : combatants) {
|
||||||
for (int i = 0; i < combatants.size(); i++) {
|
|
||||||
c = combatants.get(i);
|
|
||||||
|
|
||||||
// if no assigned damage to resolve, move to next
|
// if no assigned damage to resolve, move to next
|
||||||
if (c.getTotalAssignedDamage() == 0) {
|
if (c.getTotalAssignedDamage() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.addCombatDamage(c.getAssignedDamageMap());
|
c.addCombatDamage(c.getAssignedDamageMap(), dealtDamageTo);
|
||||||
c.clearAssignedDamage();
|
c.clearAssignedDamage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
for (final GameEntity ge : wasDamaged.keySet()) {
|
for (final GameEntity ge : dealtDamageTo.columnKeySet()) {
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
runParams.put("DamageSources", wasDamaged.get(ge));
|
runParams.put("DamageSources", dealtDamageTo.column(ge).keySet());
|
||||||
runParams.put("DamageTarget", ge);
|
runParams.put("DamageTarget", ge);
|
||||||
ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false);
|
ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false);
|
||||||
}
|
}
|
||||||
// This was deeper before, but that resulted in the stack entry acting like before.
|
// This was deeper before, but that resulted in the stack entry acting like before.
|
||||||
|
|
||||||
|
// LifeLink for Combat Damage at this place
|
||||||
|
dealtDamageTo.dealLifelinkDamage();
|
||||||
|
|
||||||
// when ... deals combat damage to one or more
|
// when ... deals combat damage to one or more
|
||||||
for (final Card damageSource : dealtDamageTo.rowKeySet()) {
|
for (final Card damageSource : dealtDamageTo.rowKeySet()) {
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
Map<GameEntity, Integer> row = dealtDamageTo.row(damageSource);
|
Map<GameEntity, Integer> row = dealtDamageTo.row(damageSource);
|
||||||
|
|
||||||
|
// TODO find better way to get the sum
|
||||||
int dealtDamage = 0;
|
int dealtDamage = 0;
|
||||||
for (Map.Entry<GameEntity, Integer> e : row.entrySet()) {
|
for (Integer i : row.values()) {
|
||||||
dealtDamage += e.getValue();
|
dealtDamage += i;
|
||||||
}
|
|
||||||
// LifeLink for Combat Damage at this place
|
|
||||||
if (dealtDamage > 0 && damageSource.hasKeyword("Lifelink")) {
|
|
||||||
damageSource.getController().gainLife(dealtDamage, damageSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runParams.put("DamageSource", damageSource);
|
runParams.put("DamageSource", damageSource);
|
||||||
runParams.put("DamageTargets", row.keySet());
|
runParams.put("DamageTargets", row.keySet());
|
||||||
runParams.put("DamageAmount", dealtDamage);
|
runParams.put("DamageAmount", dealtDamage);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package forge.game.cost;
|
package forge.game.cost;
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
@@ -60,10 +61,12 @@ public class CostDamage extends CostPart {
|
|||||||
@Override
|
@Override
|
||||||
public boolean payAsDecided(Player payer, PaymentDecision decision, SpellAbility sa) {
|
public boolean payAsDecided(Player payer, PaymentDecision decision, SpellAbility sa) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
int dmg = payer.addDamage(decision.c, source);
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
if (dmg > 0 && source.hasKeyword("Lifelink")) {
|
|
||||||
source.getController().gainLife(dmg, source);
|
payer.addDamage(decision.c, source, damageMap);
|
||||||
}
|
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
|
|
||||||
return decision.c > 0;
|
return decision.c > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -534,15 +534,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
// This function handles damage after replacement and prevention effects are applied
|
// This function handles damage after replacement and prevention effects are applied
|
||||||
@Override
|
@Override
|
||||||
public final int addDamageAfterPrevention(final int amount, final Card source, final boolean isCombat) {
|
public final int addDamageAfterPrevention(final int amount, final Card source, final boolean isCombat, CardDamageMap damageMap) {
|
||||||
if (amount <= 0) {
|
if (amount <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//String additionalLog = "";
|
//String additionalLog = "";
|
||||||
source.addDealtDamageToPlayerThisTurn(getName(), amount);
|
source.addDealtDamageToPlayerThisTurn(getName(), amount);
|
||||||
if (isCombat) {
|
|
||||||
game.getCombat().addDealtDamageTo(source, this, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean infect = source.hasKeyword("Infect")
|
boolean infect = source.hasKeyword("Infect")
|
||||||
|| hasKeyword("All damage is dealt to you as though its source had infect.");
|
|| hasKeyword("All damage is dealt to you as though its source had infect.");
|
||||||
@@ -553,8 +550,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
else {
|
else {
|
||||||
// Worship does not reduce the damage dealt but changes the effect
|
// Worship does not reduce the damage dealt but changes the effect
|
||||||
// of the damage
|
// of the damage
|
||||||
if (hasKeyword("Damage that would reduce your life total to less than 1 reduces it to 1 instead.")
|
if (hasKeyword("DamageLifeThreshold:7") && life - 7 <= amount) {
|
||||||
&& life <= amount) {
|
// only active if life is over 7, so no bad thing
|
||||||
|
loseLife(Math.min(amount, life - 7));
|
||||||
|
} else if (hasKeyword("DamageLifeThreshold:1") && life <= amount) {
|
||||||
loseLife(Math.min(amount, life - 1));
|
loseLife(Math.min(amount, life - 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -589,6 +588,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
game.getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
|
||||||
|
|
||||||
game.fireEvent(new GameEventPlayerDamaged(this, source, amount, isCombat, infect));
|
game.fireEvent(new GameEventPlayerDamaged(this, source, amount, isCombat, infect));
|
||||||
|
|
||||||
|
if (amount > 0) {
|
||||||
|
damageMap.put(source, this, amount);
|
||||||
|
}
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +651,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
public final int staticReplaceDamage(final int damage, final Card source, final boolean isCombat) {
|
public final int staticReplaceDamage(final int damage, final Card source, final boolean isCombat) {
|
||||||
int restDamage = damage;
|
int restDamage = damage;
|
||||||
|
|
||||||
if (hasKeyword("Damage that would reduce your life total to less than 1 reduces it to 1 instead.")) {
|
if (hasKeyword("DamageLifeThreshold:7")) {
|
||||||
|
restDamage = Math.min(restDamage, life - 7);
|
||||||
|
} else if (hasKeyword("DamageLifeThreshold:1")) {
|
||||||
restDamage = Math.min(restDamage, life - 1);
|
restDamage = Math.min(restDamage, life - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,29 +721,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return restDamage;
|
return restDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int replaceDamage(final int damage, final Card source, final boolean isCombat) {
|
|
||||||
// Replacement effects
|
|
||||||
final Map<String, Object> repParams = Maps.newHashMap();
|
|
||||||
repParams.put("Event", "DamageDone");
|
|
||||||
repParams.put("Affected", this);
|
|
||||||
repParams.put("DamageSource", source);
|
|
||||||
repParams.put("DamageAmount", damage);
|
|
||||||
repParams.put("IsCombat", isCombat);
|
|
||||||
|
|
||||||
switch (getGame().getReplacementHandler().run(repParams)) {
|
|
||||||
case NotReplaced:
|
|
||||||
return damage;
|
|
||||||
case Updated:
|
|
||||||
// check if this is still the affected player
|
|
||||||
if (this.equals(repParams.get("Affected"))) {
|
|
||||||
return (int) repParams.get("DamageAmount");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int preventDamage(final int damage, final Card source, final boolean isCombat) {
|
public final int preventDamage(final int damage, final Card source, final boolean isCombat) {
|
||||||
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noPrevention)
|
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noPrevention)
|
||||||
@@ -885,13 +867,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return Aggregates.max(getOpponents(), Accessors.FN_GET_ASSIGNED_DAMAGE);
|
return Aggregates.max(getOpponents(), Accessors.FN_GET_ASSIGNED_DAMAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int addCombatDamage(final int damage, final Card source) {
|
public final int addCombatDamage(final int damage, final Card source, CardDamageMap damageMap) {
|
||||||
int damageToDo = damage;
|
int damageToDo = damage;
|
||||||
|
|
||||||
damageToDo = replaceDamage(damageToDo, source, true);
|
damageToDo = replaceDamage(damageToDo, source, true, true, damageMap);
|
||||||
damageToDo = preventDamage(damageToDo, source, true);
|
damageToDo = preventDamage(damageToDo, source, true);
|
||||||
|
|
||||||
addDamageAfterPrevention(damageToDo, source, true); // damage prevention is already checked
|
damageToDo = addDamageAfterPrevention(damageToDo, source, true, damageMap); // damage prevention is already checked
|
||||||
|
|
||||||
if (damageToDo > 0) {
|
if (damageToDo > 0) {
|
||||||
source.getDamageHistory().registerCombatDamage(this);
|
source.getDamageHistory().registerCombatDamage(this);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import forge.game.GameEntity;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -53,7 +53,7 @@ public class TriggerCombatDamageDoneOnce extends Trigger {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public final boolean performTest(final java.util.Map<String, Object> runParams2) {
|
public final boolean performTest(final java.util.Map<String, Object> runParams2) {
|
||||||
final List<Card> srcs = (List<Card>) runParams2.get("DamageSources");
|
final Set<Card> srcs = (Set<Card>) runParams2.get("DamageSources");
|
||||||
final GameEntity tgt = (GameEntity) runParams2.get("DamageTarget");
|
final GameEntity tgt = (GameEntity) runParams2.get("DamageTarget");
|
||||||
|
|
||||||
if (this.mapParams.containsKey("ValidSource")) {
|
if (this.mapParams.containsKey("ValidSource")) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import forge.game.ability.effects.FlipCoinEffect;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardDamageMap;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates;
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
@@ -385,8 +386,11 @@ public class HumanPlay {
|
|||||||
if (!p.getController().confirmPayment(part, "Do you want " + source + " to deal " + amount + " damage to you?")) {
|
if (!p.getController().confirmPayment(part, "Do you want " + source + " to deal " + amount + " damage to you?")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
CardDamageMap damageMap = new CardDamageMap();
|
||||||
|
|
||||||
p.addDamage(amount, source);
|
p.addDamage(amount, source, damageMap);
|
||||||
|
|
||||||
|
damageMap.dealLifelinkDamage();
|
||||||
}
|
}
|
||||||
else if (part instanceof CostPutCounter) {
|
else if (part instanceof CostPutCounter) {
|
||||||
CounterType counterType = ((CostPutCounter) part).getCounter();
|
CounterType counterType = ((CostPutCounter) part).getCounter();
|
||||||
|
|||||||
Reference in New Issue
Block a user