diff --git a/.gitattributes b/.gitattributes index e83b7e0bbed..bba9eb89a68 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8316,6 +8316,7 @@ res/cardsfolder/p/pyre_charger.txt svneol=native#text/plain res/cardsfolder/p/pyre_zombie.txt svneol=native#text/plain res/cardsfolder/p/pyreheart_wolf.txt -text res/cardsfolder/p/pyretic_ritual.txt svneol=native#text/plain +res/cardsfolder/p/pyrewild_shaman.txt -text res/cardsfolder/p/pyric_salamander.txt svneol=native#text/plain res/cardsfolder/p/pyrite_spellbomb.txt svneol=native#text/plain res/cardsfolder/p/pyroblast.txt -text @@ -14050,6 +14051,7 @@ src/main/java/forge/card/trigger/TriggerChampioned.java svneol=native#text/plain src/main/java/forge/card/trigger/TriggerChangesController.java -text src/main/java/forge/card/trigger/TriggerChangesZone.java svneol=native#text/plain src/main/java/forge/card/trigger/TriggerClashed.java svneol=native#text/plain +src/main/java/forge/card/trigger/TriggerCombatDamageDoneOnce.java -text src/main/java/forge/card/trigger/TriggerCounterAdded.java svneol=native#text/plain src/main/java/forge/card/trigger/TriggerCounterRemoved.java -text src/main/java/forge/card/trigger/TriggerCountered.java -text diff --git a/res/cardsfolder/p/pyrewild_shaman.txt b/res/cardsfolder/p/pyrewild_shaman.txt new file mode 100644 index 00000000000..c1596ac7261 --- /dev/null +++ b/res/cardsfolder/p/pyrewild_shaman.txt @@ -0,0 +1,10 @@ +Name:Pyrewild Shaman +ManaCost:2 R +Types:Creature Goblin Shaman +PT:3/1 +A:AB$ Pump | Cost$ 1 R Discard<1/CARDNAME> | ActivationZone$ Hand | PrecostDesc$ Bloodrush | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | NumAtt$ +3 | NumDef$ +1 | SpellDescription$ Target attacking creature gets +3/+1 until end of turn. +T:Mode$ CombatDamageDoneOnce | ValidSource$ Creature.YouCtrl | TriggerZones$ Graveyard | ValidTarget$ Player | Execute$ TrigChange | TriggerDescription$ Whenever one or more creatures you control deal combat damage to a player, you may pay 3. If you do, return CARDNAME from your graveyard to your hand. +SVar:TrigChange:AB$ ChangeZone | Cost$ 3 | Origin$ Graveyard | Destination$ Hand +SVar:Picture:http://www.wizards.com/global/images/magic/general/pyrewild_shaman.jpg +Oracle:Bloodrush - {1}{R}, Discard Pyrewild Shaman: Target attacking creature gets +3/+1 until end of turn.\nWhenever one or more creatures you control deal combat damage to a player, if Pyrewild Shaman is in your graveyard, you may pay {3}. If you do, return Pyrewild Shaman to your hand. +SetInfo:DGM Rare \ No newline at end of file diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 3ac09c18ade..fe0e094668d 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -8268,6 +8268,7 @@ public class Card extends GameEntity implements Comparable { /** * Fetch GameState for this card from references to players who may own or control this card. */ + @Override public GameState getGame() { Player controller = getController(); diff --git a/src/main/java/forge/GameEntity.java b/src/main/java/forge/GameEntity.java index 8952b10b9d8..4afe219448d 100644 --- a/src/main/java/forge/GameEntity.java +++ b/src/main/java/forge/GameEntity.java @@ -20,6 +20,7 @@ package forge; import java.util.ArrayList; import forge.card.spellability.SpellAbility; +import forge.game.GameState; import forge.game.player.Player; import forge.util.MyObservable; @@ -424,4 +425,8 @@ public abstract class GameEntity extends MyObservable { public String toString() { return this.name; } + + public GameState getGame() { + return null; + } } diff --git a/src/main/java/forge/card/trigger/TriggerCombatDamageDoneOnce.java b/src/main/java/forge/card/trigger/TriggerCombatDamageDoneOnce.java new file mode 100644 index 00000000000..9b7e4d6af73 --- /dev/null +++ b/src/main/java/forge/card/trigger/TriggerCombatDamageDoneOnce.java @@ -0,0 +1,98 @@ +/* + * 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.card.trigger; + +import java.util.List; + +import forge.Card; +import forge.GameEntity; +import forge.card.spellability.SpellAbility; + +/** + *

+ * Trigger_DamageDone class. + *

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

+ * Constructor for TriggerCombatDamageDoneOnc. + *

+ * + * @param params + * a {@link java.util.HashMap} object. + * @param host + * a {@link forge.Card} object. + * @param intrinsic + * the intrinsic + */ + public TriggerCombatDamageDoneOnce(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 List srcs = (List) runParams2.get("DamageSources"); + final GameEntity tgt = (GameEntity) runParams2.get("DamageTarget"); + + if (this.mapParams.containsKey("ValidSource")) { + boolean valid = false; + for (Card c : srcs) { + if (c.isValid(this.mapParams.get("ValidSource").split(","), this.getHostCard().getController(),this.getHostCard())) { + valid = true; + } + } + if (!valid) { + return false; + } + } + + if (this.mapParams.containsKey("ValidTarget")) { + if (!matchesValid(tgt, this.mapParams.get("ValidTarget").split(","), this.getHostCard())) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public final Trigger getCopy() { + final Trigger copy = new TriggerCombatDamageDoneOnce(this.mapParams, this.getHostCard(), this.isIntrinsic()); + if (this.getOverridingAbility() != null) { + copy.setOverridingAbility(this.getOverridingAbility()); + } + + copyFieldsTo(copy); + return copy; + } + + /** {@inheritDoc} */ + @Override + public final void setTriggeringObjects(final SpellAbility sa) { + sa.setTriggeringObject("Sources", this.getRunParams().get("DamageSources")); + sa.setTriggeringObject("Target", this.getRunParams().get("DamageTarget")); + } +} diff --git a/src/main/java/forge/card/trigger/TriggerType.java b/src/main/java/forge/card/trigger/TriggerType.java index 4b1e1180b91..6671f28e116 100644 --- a/src/main/java/forge/card/trigger/TriggerType.java +++ b/src/main/java/forge/card/trigger/TriggerType.java @@ -30,6 +30,7 @@ public enum TriggerType { CounterRemoved(TriggerCounterRemoved.class), Evolved(TriggerEvolved.class), Unequip(TriggerUnequip.class), + CombatDamageDoneOnce(TriggerCombatDamageDoneOnce.class), DamageDone(TriggerDamageDone.class), Championed(TriggerChampioned.class), TurnFaceUp(TriggerTurnFaceUp.class), diff --git a/src/main/java/forge/game/phase/Combat.java b/src/main/java/forge/game/phase/Combat.java index 25eecaa8668..8f27f32f6ec 100644 --- a/src/main/java/forge/game/phase/Combat.java +++ b/src/main/java/forge/game/phase/Combat.java @@ -685,13 +685,30 @@ public class Combat { // This function handles both Regular and First Strike combat assignment final HashMap defMap = this.getDefendingDamageMap(); + final HashMap> wasDamaged = new HashMap>(); for (final Entry entry : defMap.entrySet()) { GameEntity defender = getDefendingEntity(entry.getKey()); if (defender instanceof Player) { // player - ((Player) defender).addCombatDamage(entry.getValue(), entry.getKey()); + if (((Player) defender).addCombatDamage(entry.getValue(), entry.getKey())) { + if (wasDamaged.containsKey(defender)) { + wasDamaged.get(defender).add(entry.getKey()); + } else { + List l = new ArrayList(); + l.add(entry.getKey()); + wasDamaged.put(defender, l); + } + } } else if (defender instanceof Card) { // planeswalker - ((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey()); + if (((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey())) { + if (wasDamaged.containsKey(defender)) { + wasDamaged.get(defender).add(entry.getKey()); + } else { + List l = new ArrayList(); + l.add(entry.getKey()); + wasDamaged.put(defender, l); + } + } } } @@ -723,6 +740,14 @@ public class Combat { damageMap.clear(); c.clearAssignedDamage(); } + + // Run triggers + for (final GameEntity ge : wasDamaged.keySet()) { + final HashMap runParams = new HashMap(); + runParams.put("DamageSources", wasDamaged.get(ge)); + runParams.put("DamageTarget", ge); + ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false); + } // This was deeper before, but that resulted in the stack entry acting // like before. diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index 0a2300d33b0..7ef92491925 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -196,6 +196,7 @@ public abstract class Player extends GameEntity implements Comparable { this.setName(name); } + @Override public GameState getGame() { // I'll probably regret about this return game; } @@ -976,7 +977,7 @@ public abstract class Player extends GameEntity implements Comparable { * @param source * a {@link forge.Card} object. */ - public final void addCombatDamage(final int damage, final Card source) { + public final boolean addCombatDamage(final int damage, final Card source) { int damageToDo = damage; @@ -990,7 +991,9 @@ public abstract class Player extends GameEntity implements Comparable { if (damageToDo > 0) { GameActionUtil.executeCombatDamageToPlayerEffects(this, source, damageToDo); + return true; } + return false; } // ////////////////////////