diff --git a/.gitattributes b/.gitattributes index 43f5cc4585e..3ad787b3b16 100644 --- a/.gitattributes +++ b/.gitattributes @@ -655,6 +655,7 @@ forge-game/src/main/java/forge/game/trigger/TriggerCounterRemoved.java -text forge-game/src/main/java/forge/game/trigger/TriggerCountered.java -text forge-game/src/main/java/forge/game/trigger/TriggerCycled.java svneol=native#text/plain forge-game/src/main/java/forge/game/trigger/TriggerDamageDone.java svneol=native#text/plain +forge-game/src/main/java/forge/game/trigger/TriggerDealtCombatDamageOnce.java -text forge-game/src/main/java/forge/game/trigger/TriggerDestroyed.java -text forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java -text forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java svneol=native#text/plain @@ -1844,6 +1845,7 @@ forge-gui/res/cardsfolder/a/arachnus_spinner.txt -text forge-gui/res/cardsfolder/a/arachnus_web.txt -text forge-gui/res/cardsfolder/a/arashi_the_sky_asunder.txt svneol=native#text/plain forge-gui/res/cardsfolder/a/arashin_cleric.txt -text +forge-gui/res/cardsfolder/a/arashin_war_beast.txt -text forge-gui/res/cardsfolder/a/arbalest_elite.txt svneol=native#text/plain forge-gui/res/cardsfolder/a/arbiter_of_knollridge.txt svneol=native#text/plain forge-gui/res/cardsfolder/a/arbiter_of_the_ideal.txt -text diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index daaded1f21b..cb3d2953254 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5615,6 +5615,9 @@ public class Card extends GameEntity implements Comparable { addReceivedDamageFromThisTurn(source, damageToAdd); source.addDealtDamageToThisTurn(this, damageToAdd); + if (isCombat) { + game.getCombat().addDealtDamageTo(source, this); + } if (source.hasKeyword("Lifelink")) { source.getController().gainLife(damageToAdd, source); diff --git a/forge-game/src/main/java/forge/game/combat/Combat.java b/forge-game/src/main/java/forge/game/combat/Combat.java index 17bb6365ac3..e09da0d6ba6 100644 --- a/forge-game/src/main/java/forge/game/combat/Combat.java +++ b/forge-game/src/main/java/forge/game/combat/Combat.java @@ -28,12 +28,12 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.base.Function; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; - import forge.game.GameEntity; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -66,6 +66,8 @@ public class Combat { private Map attackersOrderedForDamageAssignment = new HashMap(); private Map blockersOrderedForDamageAssignment = new HashMap(); private Map lkiCache = new HashMap(); + private Multimap dealtDamageTo = HashMultimap.create(); + private Multimap dealtDamageToThisCombat = HashMultimap.create(); // 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(); @@ -95,6 +97,7 @@ public class Combat { blockersOrderedForDamageAssignment.clear(); lkiCache.clear(); combatantsThatDealtFirstStrikeDamage.clear(); + dealtDamageToThisCombat.clear(); //update view for all attackers and blockers for (Card c : attackers) { @@ -644,6 +647,10 @@ public class Combat { return assignedDamage; } + public final void addDealtDamageTo(final Card source, final GameEntity ge) { + dealtDamageTo.put(source, ge); + } + public void dealAssignedDamage() { // This function handles both Regular and First Strike combat assignment final HashMap defMap = defendingDamageMap; @@ -713,6 +720,16 @@ public class Combat { ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false); } // This was deeper before, but that resulted in the stack entry acting like before. + + // when ... deals combat damage to one or more + for (final Card damageSource : dealtDamageTo.keySet()) { + final HashMap runParams = new HashMap(); + runParams.put("DamageSource", damageSource); + runParams.put("DamageTargets", dealtDamageTo.get(damageSource)); + damageSource.getGame().getTriggerHandler().runTrigger(TriggerType.DealtCombatDamageOnce, runParams, false); + } + dealtDamageToThisCombat.putAll(dealtDamageTo); + dealtDamageTo.clear(); } public final boolean isUnblocked(final Card att) { diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 11f62fbad9f..c5ecd426e59 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -486,6 +486,9 @@ public class Player extends GameEntity implements Comparable { } //String additionalLog = ""; source.addDealtDamageToPlayerThisTurn(getName(), amount); + if (isCombat) { + game.getCombat().addDealtDamageTo(source, this); + } boolean infect = source.hasKeyword("Infect") || hasKeyword("All damage is dealt to you as though its source had infect."); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDealtCombatDamageOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerDealtCombatDamageOnce.java new file mode 100644 index 00000000000..952638d3f55 --- /dev/null +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDealtCombatDamageOnce.java @@ -0,0 +1,86 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.game.trigger; + +import forge.game.GameEntity; +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; + +import java.util.Set; + +/** + *

+ * Trigger_DamageDone class. + *

+ * + * @author Forge + * @version $Id: TriggerDamageDone.java 21390 2013-05-08 07:44:50Z Max mtg $ + */ +public class TriggerDealtCombatDamageOnce extends Trigger { + + /** + *

+ * Constructor for TriggerCombatDamageDoneOnc. + *

+ * + * @param params + * a {@link java.util.HashMap} object. + * @param host + * a {@link forge.game.card.Card} object. + * @param intrinsic + * the intrinsic + */ + public TriggerDealtCombatDamageOnce(final java.util.Map params, final Card host, final boolean intrinsic) { + super(params, host, intrinsic); + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public final boolean performTest(final java.util.Map runParams2) { + final Card srcs = (Card) runParams2.get("DamageSource"); + final Set tgt = (Set) runParams2.get("DamageTargets"); + + if (this.mapParams.containsKey("ValidTarget")) { + boolean valid = false; + for (GameEntity c : tgt) { + if (c.isValid(this.mapParams.get("ValidTarget").split(","), this.getHostCard().getController(),this.getHostCard())) { + valid = true; + } + } + if (!valid) { + return false; + } + } + + if (this.mapParams.containsKey("ValidSource")) { + if (!matchesValid(srcs, this.mapParams.get("ValidSource").split(","), this.getHostCard())) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public final void setTriggeringObjects(final SpellAbility sa) { + sa.setTriggeringObject("Source", this.getRunParams().get("DamageSource")); + sa.setTriggeringObject("Targets", this.getRunParams().get("DamageTargets")); + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index 26afb65fb76..6593f2de15b 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -34,6 +34,7 @@ public enum TriggerType { CounterRemoved(TriggerCounterRemoved.class), Cycled(TriggerCycled.class), DamageDone(TriggerDamageDone.class), + DealtCombatDamageOnce(TriggerDealtCombatDamageOnce.class), Destroyed(TriggerDestroyed.class), Devoured(TriggerDevoured.class), Discarded(TriggerDiscarded.class), diff --git a/forge-gui/res/cardsfolder/a/arashin_war_beast.txt b/forge-gui/res/cardsfolder/a/arashin_war_beast.txt new file mode 100644 index 00000000000..43d97e585f9 --- /dev/null +++ b/forge-gui/res/cardsfolder/a/arashin_war_beast.txt @@ -0,0 +1,8 @@ +Name:Arashin War Beast +ManaCost:5 G G +Types:Creature Beast +PT:6/6 +T:Mode$ DealtCombatDamageOnce | ValidSource$ Card.Self | ValidTarget$ Creature.blocking | TriggerZones$ Battlefield | Execute$ TrigManifest | TriggerDescription$ Whenever CARDNAME deals combat damage to one or more blocking creatures, manifest the top card of your library. (Put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.) +SVar:TrigManifest:AB$ Manifest | Cost$ 0 | Amount$ 1 | Defined$ TopOfLibrary +SVar:Picture:http://www.wizards.com/global/images/magic/general/arashin_war_beast.jpg +Oracle:Whenever Arashin War Beast deals combat damage to one or more blocking creatures, manifest the top card of your library. (Put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.) diff --git a/forge-gui/res/cardsfolder/m/maelstrom_wanderer.txt b/forge-gui/res/cardsfolder/m/maelstrom_wanderer.txt index 6ec036b22b5..4e6e965d8bb 100644 --- a/forge-gui/res/cardsfolder/m/maelstrom_wanderer.txt +++ b/forge-gui/res/cardsfolder/m/maelstrom_wanderer.txt @@ -5,5 +5,6 @@ PT:7/5 K:Cascade K:Cascade S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddKeyword$ Haste | Description$ Creatures you control have haste. +SVar:PlayMain1:True SVar:Picture:http://www.wizards.com/global/images/magic/general/maelstrom_wanderer.jpg Oracle:Creatures you control have haste.\nCascade, cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order. Then do it again.)