- Added support for damage prevention shields with effects.

- Added: Candles' Glow, Temper, Test of Faith and Vengeful Archon
This commit is contained in:
moomarc
2013-06-28 16:56:56 +00:00
parent 4d8d51facc
commit 4b71ea18b8
18 changed files with 334 additions and 13 deletions

4
.gitattributes vendored
View File

@@ -707,6 +707,7 @@ res/cardsfolder/a/azors_elocutors.txt -text
res/cardsfolder/a/azure_drake.txt svneol=native#text/plain res/cardsfolder/a/azure_drake.txt svneol=native#text/plain
res/cardsfolder/a/azure_mage.txt svneol=native#text/plain res/cardsfolder/a/azure_mage.txt svneol=native#text/plain
res/cardsfolder/a/azusa_lost_but_seeking.txt svneol=native#text/plain res/cardsfolder/a/azusa_lost_but_seeking.txt svneol=native#text/plain
res/cardsfolder/a/vengeful_archon.txt -text
res/cardsfolder/b/back_from_the_brink.txt -text res/cardsfolder/b/back_from_the_brink.txt -text
res/cardsfolder/b/back_to_basics.txt svneol=native#text/plain res/cardsfolder/b/back_to_basics.txt svneol=native#text/plain
res/cardsfolder/b/back_to_nature.txt svneol=native#text/plain res/cardsfolder/b/back_to_nature.txt svneol=native#text/plain
@@ -1496,6 +1497,7 @@ res/cardsfolder/c/caltrops.txt svneol=native#text/plain
res/cardsfolder/c/camel.txt -text res/cardsfolder/c/camel.txt -text
res/cardsfolder/c/cancel.txt svneol=native#text/plain res/cardsfolder/c/cancel.txt svneol=native#text/plain
res/cardsfolder/c/candelabra_of_tawnos.txt svneol=native#text/plain res/cardsfolder/c/candelabra_of_tawnos.txt svneol=native#text/plain
res/cardsfolder/c/candles_glow.txt -text
res/cardsfolder/c/candles_of_leng.txt -text svneol=unset#text/plain res/cardsfolder/c/candles_of_leng.txt -text svneol=unset#text/plain
res/cardsfolder/c/canker_abomination.txt svneol=native#text/plain res/cardsfolder/c/canker_abomination.txt svneol=native#text/plain
res/cardsfolder/c/cankerous_thirst.txt -text res/cardsfolder/c/cankerous_thirst.txt -text
@@ -11142,6 +11144,7 @@ res/cardsfolder/t/telimtors_edict.txt svneol=native#text/plain
res/cardsfolder/t/teller_of_tales.txt svneol=native#text/plain res/cardsfolder/t/teller_of_tales.txt svneol=native#text/plain
res/cardsfolder/t/telling_time.txt svneol=native#text/plain res/cardsfolder/t/telling_time.txt svneol=native#text/plain
res/cardsfolder/t/tember_city.txt -text res/cardsfolder/t/tember_city.txt -text
res/cardsfolder/t/temper.txt -text
res/cardsfolder/t/tempered_steel.txt svneol=native#text/plain res/cardsfolder/t/tempered_steel.txt svneol=native#text/plain
res/cardsfolder/t/tempest_drake.txt svneol=native#text/plain res/cardsfolder/t/tempest_drake.txt svneol=native#text/plain
res/cardsfolder/t/tempest_of_light.txt svneol=native#text/plain res/cardsfolder/t/tempest_of_light.txt svneol=native#text/plain
@@ -11197,6 +11200,7 @@ res/cardsfolder/t/territorial_dispute.txt -text
res/cardsfolder/t/terror.txt svneol=native#text/plain res/cardsfolder/t/terror.txt svneol=native#text/plain
res/cardsfolder/t/terrus_wurm.txt -text res/cardsfolder/t/terrus_wurm.txt -text
res/cardsfolder/t/test_of_endurance.txt svneol=native#text/plain res/cardsfolder/t/test_of_endurance.txt svneol=native#text/plain
res/cardsfolder/t/test_of_faith.txt -text
res/cardsfolder/t/testament_of_faith.txt svneol=native#text/plain res/cardsfolder/t/testament_of_faith.txt svneol=native#text/plain
res/cardsfolder/t/tethered_griffin.txt svneol=native#text/plain res/cardsfolder/t/tethered_griffin.txt svneol=native#text/plain
res/cardsfolder/t/tethered_skirge.txt svneol=native#text/plain res/cardsfolder/t/tethered_skirge.txt svneol=native#text/plain

View File

@@ -0,0 +1,13 @@
Name:Vengeful Archon
ManaCost:4 W W W
Types:Creature Archon
PT:7/7
K:Flying
A:AB$ Pump | Cost$ X | ValidTgts$ Player | TgtPrompt$ Select target player damaged by shield effect | IsCurse$ True | References$ X | RememberObjects$ Targeted | SubAbility$ ArchonPrevention | StackDescription$ none | SpellDescription$ Prevent the next X damage that would be dealt to you this turn. If damage is prevented this way, CARDNAME deals that much damage to target player.
SVar:ArchonPrevention:DB$ PreventDamage | Defined$ You | Amount$ X | References$ X | PreventionSubAbility$ ArchonsVengeance | ShieldEffectTarget$ Remembered | SubAbility$ DBCleanup
SVar:ArchonsVengeance:AB$ DealDamage | Cost$ 0 | Defined$ ShieldEffectTarget | NumDmg$ PreventedDamage | SpellDescription$ CARDNAME deals damage to target player for each damage prevented this way.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$xPaid
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/vengeful_archon.jpg
Oracle:Flying\n{X}: Prevent the next X damage that would be dealt to you this turn. If damage is prevented this way, Vengeful Archon deals that much damage to target player.

View File

@@ -0,0 +1,8 @@
Name:Candles' Glow
ManaCost:1 W
Types:Instant Arcane
A:SP$ PreventDamage | Cost$ 1 W | ValidTgts$ Player,Creature | Amount$ 3 | PreventionSubAbility$ GlowOfLife | References$ GlowOfLife | ShieldEffectTarget$ You | TgtPrompt$ Select target creature or player | SpellDescription$ Prevent the next 3 damage that would be dealt to target creature or player this turn. You gain life equal to the damage prevented this way.
SVar:GlowOfLife:AB$ GainLife | Cost$ 0 | Defined$ ShieldEffectTarget | LifeAmount$ PreventedDamage | SpellDescription$ You gain life equal to the damage prevented this way.
K:Splice onto Arcane 1 W
SVar:Picture:http://www.wizards.com/global/images/magic/general/candles_glow.jpg
Oracle:Prevent the next 3 damage that would be dealt to target creature or player this turn. You gain life equal to the damage prevented this way.\nSplice onto Arcane {1}{W} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)

View File

@@ -0,0 +1,8 @@
Name:Temper
ManaCost:X 1 W
Types:Instant
A:SP$ PreventDamage | Cost$ X 1 W | ValidTgts$ Creature | Amount$ X | References$ X | PreventionSubAbility$ EvenTemper | ShieldEffectTarget$ Targeted | TgtPrompt$ Select target creature | SpellDescription$ Prevent the next X damage that would be dealt to target creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature.
SVar:EvenTemper:AB$ PutCounter | Cost$ 0 | Defined$ ShieldEffectTarget | CounterType$ P1P1 | CounterNum$ PreventedDamage | SpellDescription$ Put a +1/+1 counter on this creature for each 1 damage prevented this way.
SVar:X:Count$xPaid
SVar:Picture:http://www.wizards.com/global/images/magic/general/temper.jpg
Oracle:Prevent the next X damage that would be dealt to target creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature.

View File

@@ -0,0 +1,7 @@
Name:Test of Faith
ManaCost:1 W
Types:Instant
A:SP$ PreventDamage | Cost$ 1 W | ValidTgts$ Creature | Amount$ 3 | PreventionSubAbility$ FaithsReward | ShieldEffectTarget$ Targeted | TgtPrompt$ Select target creature | SpellDescription$ Prevent the next 3 damage that would be dealt to target creature this turn, and put a +1/+1 counter on that creature for each 1 damage prevented this way.
SVar:FaithsReward:AB$ PutCounter | Cost$ 0 | Defined$ ShieldEffectTarget | CounterType$ P1P1 | CounterNum$ PreventedDamage | SpellDescription$ Put a +1/+1 counter on this creature for each 1 damage prevented this way.
SVar:Picture:http://www.wizards.com/global/images/magic/general/test_of_faith.jpg
Oracle:Prevent the next 3 damage that would be dealt to target creature this turn, and put a +1/+1 counter on that creature for each 1 damage prevented this way.

View File

@@ -48,6 +48,7 @@ import forge.card.CardRarity;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.ability.AbilityFactory;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.ApiType; import forge.card.ability.ApiType;
import forge.card.cardfactory.CardFactoryUtil; import forge.card.cardfactory.CardFactoryUtil;
@@ -7341,6 +7342,66 @@ public class Card extends GameEntity implements Comparable<Card> {
int restDamage = damage; int restDamage = damage;
boolean DEBUGShieldsWithEffects = false;
while (!this.getPreventNextDamageWithEffect().isEmpty() && restDamage != 0) {
TreeMap<Card, Map<String, String>> shieldMap = this.getPreventNextDamageWithEffect();
List<Card> preventionEffectSources = new ArrayList<Card>(shieldMap.keySet());
Card shieldSource = preventionEffectSources.get(0);
if (preventionEffectSources.size() > 1) {
Map<String, Card> choiceMap = new TreeMap<String, Card>();
List<String> choices = new ArrayList<String>();
for (final Card key : preventionEffectSources) {
String effDesc = shieldMap.get(key).get("EffectString");
int descIndex = effDesc.indexOf("SpellDescription");
effDesc = effDesc.substring(descIndex + 18);
String shieldDescription = key.toString() + " - " + shieldMap.get(key).get("ShieldAmount")
+ " shields - " + effDesc;
choices.add(shieldDescription);
choiceMap.put(shieldDescription, key);
}
shieldSource = this.getController().getController().chooseProtectionShield(this, choices, choiceMap);
}
if (DEBUGShieldsWithEffects) {
System.out.println("Prevention shield source: " + shieldSource);
}
int shieldAmount = Integer.valueOf(shieldMap.get(shieldSource).get("ShieldAmount"));
int dmgToBePrevented = Math.min(restDamage, shieldAmount);
if (DEBUGShieldsWithEffects) {
System.out.println("Selected source initial shield amount: " + shieldAmount);
System.out.println("Incoming damage: " + restDamage);
System.out.println("Damage to be prevented: " + dmgToBePrevented);
}
//Set up ability
SpellAbility shieldSA = null;
String effectAbString = shieldMap.get(shieldSource).get("EffectString");
effectAbString = effectAbString.replace("PreventedDamage", Integer.toString(dmgToBePrevented));
effectAbString = effectAbString.replace("ShieldEffectTarget", shieldMap.get(shieldSource).get("ShieldEffectTarget"));
if (DEBUGShieldsWithEffects) {
System.out.println("Final shield ability string: " + effectAbString);
}
shieldSA = AbilityFactory.getAbility(effectAbString, shieldSource);
if (shieldSA.usesTargeting()) {
System.err.println(shieldSource + " - Targeting for prevention shield's effect should be done with initial spell");
}
if (restDamage >= shieldAmount) {
this.getController().getController().playSpellAbilityNoStack(this.getController(), shieldSA);
this.subtractPreventNextDamageWithEffect(shieldSource, restDamage);
restDamage = restDamage - shieldAmount;
} else {
this.subtractPreventNextDamageWithEffect(shieldSource, restDamage);
this.getController().getController().playSpellAbilityNoStack(this.getController(), shieldSA);
restDamage = 0;
}
if (DEBUGShieldsWithEffects) {
System.out.println("Remaining shields: "
+ (shieldMap.containsKey(shieldSource) ? shieldMap.get(shieldSource).get("ShieldAmount") : "all shields used"));
System.out.println("Remaining damage: " + restDamage);
}
}
if (this.getName().equals("Swans of Bryn Argoll")) { if (this.getName().equals("Swans of Bryn Argoll")) {
source.getController().drawCards(restDamage); source.getController().drawCards(restDamage);
return 0; return 0;
@@ -8228,6 +8289,7 @@ public class Card extends GameEntity implements Comparable<Card> {
public void onCleanupPhase(final Player turn) { public void onCleanupPhase(final Player turn) {
setDamage(0); setDamage(0);
resetPreventNextDamage(); resetPreventNextDamage();
resetPreventNextDamageWithEffect();
resetReceivedDamageFromThisTurn(); resetReceivedDamageFromThisTurn();
resetDealtDamageToThisTurn(); resetDealtDamageToThisTurn();
resetDealtDamageToPlayerThisTurn(); resetDealtDamageToPlayerThisTurn();

View File

@@ -18,6 +18,8 @@
package forge; package forge;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import forge.game.Game; import forge.game.Game;
import forge.game.player.Player; import forge.game.player.Player;
@@ -34,6 +36,7 @@ import forge.util.MyObservable;
public abstract class GameEntity extends MyObservable implements ITargetable { public abstract class GameEntity extends MyObservable implements ITargetable {
private String name = ""; private String name = "";
private int preventNextDamage = 0; private int preventNextDamage = 0;
private TreeMap<Card, Map<String, String>> preventionShieldsWithEffects = new TreeMap<Card, Map<String, String>>();
/** The enchanted by. */ /** The enchanted by. */
private ArrayList<Card> enchantedBy = new ArrayList<Card>(); private ArrayList<Card> enchantedBy = new ArrayList<Card>();
@@ -255,6 +258,78 @@ public abstract class GameEntity extends MyObservable implements ITargetable {
this.preventNextDamage = 0; this.preventNextDamage = 0;
} }
// PreventNextDamageWithEffect
/**
* <p>
* Gets the map of damage prevention shields with effects.
* </p>
*
* @return the map of damage prevention shields with effects.
*/
public TreeMap<Card, Map<String, String>> getPreventNextDamageWithEffect() {
return this.preventionShieldsWithEffects;
}
/**
* <p>
* Adds a damage prevention shield with an effect that happens at time of prevention.
* </p>
*
* @param shieldSource The source card which generated the shield
* @param effectMap A map of the effect occurring with the damage prevention
*/
public void addPreventNextDamageWithEffect(final Card shieldSource, TreeMap<String, String> effectMap) {
if (this.preventionShieldsWithEffects.containsKey(shieldSource)) {
int currentShields = Integer.valueOf(this.preventionShieldsWithEffects.get(shieldSource).get("ShieldAmount"));
currentShields += Integer.valueOf(effectMap.get("ShieldAmount"));
effectMap.put("ShieldAmount", Integer.toString(currentShields));
this.preventionShieldsWithEffects.put(shieldSource, effectMap);
} else {
this.preventionShieldsWithEffects.put(shieldSource, effectMap);
}
}
/**
* <p>
* subtractPreventNextDamageWithEffect.
* </p>
*
* @param shieldSource The source card which generated the shield
* @param n The number of shields to remove originating from shieldSource
*/
public void subtractPreventNextDamageWithEffect(final Card shieldSource, final int n) {
int currentShields = Integer.valueOf(this.preventionShieldsWithEffects.get(shieldSource).get("ShieldAmount"));
if (currentShields > n) {
this.preventionShieldsWithEffects.get(shieldSource).put("ShieldAmount", String.valueOf(currentShields - n));
} else {
this.preventionShieldsWithEffects.remove(shieldSource);
}
}
/**
* <p>
* resetPreventNextDamageWithEffect.
* </p>
*/
public void resetPreventNextDamageWithEffect() {
this.preventionShieldsWithEffects = new TreeMap<Card, Map<String, String>>();
}
/**
* <p>
* Gets the total amount of damage prevention shields.
* </p>
*
* @return the number of damage prevention shields with and without effects.
*/
public int getPreventNextDamageTotalShields() {
int shields = this.preventNextDamage;
for (final Map<String, String> value : this.preventionShieldsWithEffects.values()) {
shields += Integer.valueOf(value.get("ShieldAmount"));
}
return shields;
}
/** /**
* Checks for keyword. * Checks for keyword.
* *

View File

@@ -166,6 +166,10 @@ public final class AbilityFactory {
} }
} }
if (mapParams.containsKey("PreventionSubAbility")) {
spellAbility.setSVar(mapParams.get("PreventionSubAbility"), hostCard.getSVar(mapParams.get("PreventionSubAbility")));
}
if (mapParams.containsKey("SubAbility")) { if (mapParams.containsKey("SubAbility")) {
spellAbility.setSubAbility(getSubAbility(hostCard, hostCard.getSVar(mapParams.get("SubAbility")))); spellAbility.setSubAbility(getSubAbility(hostCard, hostCard.getSVar(mapParams.get("SubAbility"))));
} }

View File

@@ -204,6 +204,14 @@ public class AbilityUtils {
for (final Card chosen : hostCard.getChosenCard()) { for (final Card chosen : hostCard.getChosenCard()) {
cards.add(game.getCardState(chosen)); cards.add(game.getCardState(chosen));
} }
}
else if (defined.startsWith("CardUID_")) {
String idString = defined.substring(8);
for (final Card cardByID : game.getCardsInGame()) {
if (cardByID.getUniqueNumber() == Integer.valueOf(idString)) {
cards.add(game.getCardState(cardByID));
}
}
} else { } else {
List<Card> list = null; List<Card> list = null;
if (defined.startsWith("Sacrificed")) { if (defined.startsWith("Sacrificed")) {
@@ -905,6 +913,13 @@ public class AbilityUtils {
if (!players.contains(p)) { if (!players.contains(p)) {
players.add(p); players.add(p);
} }
} else if (defined.startsWith("PlayerNamed_")) {
for (Player p : game.getPlayers()) {
System.out.println("Named player " + defined.substring(12));
if (p.getName().equals(defined.substring(12))) {
players.add(p);
}
}
} else if (defined.startsWith("Flipped")) { } else if (defined.startsWith("Flipped")) {
for (Player p : game.getPlayers()) { for (Player p : game.getPlayers()) {
if (null != sa.getSourceCard().getFlipResult(p)) { if (null != sa.getSourceCard().getFlipResult(p)) {

View File

@@ -2,6 +2,7 @@ package forge.card.ability.effects;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.TreeMap;
import forge.Card; import forge.Card;
import forge.CardUtil; import forge.CardUtil;
@@ -86,22 +87,65 @@ public class DamagePreventEffect extends SpellAbilityEffect {
} }
final boolean targeted = (sa.usesTargeting()); final boolean targeted = (sa.usesTargeting());
final boolean preventionWithEffect = sa.hasParam("PreventionSubAbility");
for (final Object o : tgts) { for (final Object o : tgts) {
numDam = (sa.usesTargeting() && sa.hasParam("DividedAsYouChoose")) ? sa.getTargetRestrictions().getDividedValue(o) : numDam; numDam = (sa.usesTargeting() && sa.hasParam("DividedAsYouChoose")) ? sa.getTargetRestrictions().getDividedValue(o) : numDam;
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))) {
if (preventionWithEffect) {
TreeMap<String, String> effectMap = new TreeMap<String, String>();
effectMap.put("EffectString", sa.getSVar(sa.getParam("PreventionSubAbility")));
effectMap.put("ShieldAmount", String.valueOf(numDam));
if (sa.hasParam("ShieldEffectTarget")) {
String effTgtString = "";
List<ITargetable> effTgts = new ArrayList<ITargetable>();
effTgts = AbilityUtils.getDefinedObjects(host, sa.getParam("ShieldEffectTarget"), sa);
for (final Object effTgt : effTgts) {
if (effTgt instanceof Card) {
effTgtString = String.valueOf(((Card) effTgt).getUniqueNumber());
effectMap.put("ShieldEffectTarget", "CardUID_" + effTgtString);
} else if (effTgt instanceof Player) {
effTgtString = ((Player) effTgt).getName();
effectMap.put("ShieldEffectTarget", "PlayerNamed_" + effTgtString);
}
}
}
c.addPreventNextDamageWithEffect(host, effectMap);
} else {
c.addPreventNextDamage(numDam); c.addPreventNextDamage(numDam);
} }
}
} 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 (preventionWithEffect) {
TreeMap<String, String> effectMap = new TreeMap<String, String>();
effectMap.put("EffectString", sa.getSVar(sa.getParam("PreventionSubAbility")));
effectMap.put("ShieldAmount", String.valueOf(numDam));
if (sa.hasParam("ShieldEffectTarget")) {
String effTgtString = "";
List<ITargetable> effTgts = new ArrayList<ITargetable>();
effTgts = AbilityUtils.getDefinedObjects(host, sa.getParam("ShieldEffectTarget"), sa);
for (final Object effTgt : effTgts) {
if (effTgt instanceof Card) {
effTgtString = String.valueOf(((Card) effTgt).getUniqueNumber());
effectMap.put("ShieldEffectTarget", "CardUID_" + effTgtString);
} else if (effTgt instanceof Player) {
effTgtString = ((Player) effTgt).getName();
effectMap.put("ShieldEffectTarget", "PlayerNamed_" + effTgtString);
}
}
}
p.addPreventNextDamageWithEffect(host, effectMap);
} else {
p.addPreventNextDamage(numDam); p.addPreventNextDamage(numDam);
} }
} }
} }
}
for (final Card c : untargetedCards) { for (final Card c : untargetedCards) {
if (c.isInPlay()) { if (c.isInPlay()) {

View File

@@ -240,12 +240,7 @@ public class ReplacementHandler {
} }
Player player = replacementEffect.getHostCard().getController(); Player player = replacementEffect.getHostCard().getController();
//player.getController().playNoStack() player.getController().playSpellAbilityNoStack(player, effectSA);
if (player.isHuman()) {
HumanPlay.playSpellAbilityNoStack(player, effectSA);
} else {
ComputerUtil.playNoStack(player, effectSA, game);
}
return ReplacementResult.Replaced; return ReplacementResult.Replaced;
} }

View File

@@ -1828,10 +1828,10 @@ public class ComputerUtilCombat {
* @return a int. * @return a int.
*/ */
public final static int getDamageToKill(final Card c) { public final static int getDamageToKill(final Card c) {
int killDamage = c.getLethalDamage() + c.getPreventNextDamage(); int killDamage = c.getLethalDamage() + c.getPreventNextDamageTotalShields();
if ((killDamage > c.getPreventNextDamage()) if ((killDamage > c.getPreventNextDamageTotalShields())
&& c.hasStartOfKeyword("When CARDNAME is dealt damage, destroy it.")) { && c.hasStartOfKeyword("When CARDNAME is dealt damage, destroy it.")) {
killDamage = 1 + c.getPreventNextDamage(); killDamage = 1 + c.getPreventNextDamageTotalShields();
} }
return killDamage; return killDamage;

View File

@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.TreeMap;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@@ -887,6 +888,66 @@ public class Player extends GameEntity implements Comparable<Player> {
int restDamage = damage; int restDamage = damage;
boolean DEBUGShieldsWithEffects = false;
while (!this.getPreventNextDamageWithEffect().isEmpty() && restDamage != 0) {
TreeMap<Card, Map<String, String>> shieldMap = this.getPreventNextDamageWithEffect();
List<Card> preventionEffectSources = new ArrayList<Card>(shieldMap.keySet());
Card shieldSource = preventionEffectSources.get(0);
if (preventionEffectSources.size() > 1) {
Map<String, Card> choiceMap = new TreeMap<String, Card>();
List<String> choices = new ArrayList<String>();
for (final Card key : preventionEffectSources) {
String effDesc = shieldMap.get(key).get("EffectString");
int descIndex = effDesc.indexOf("SpellDescription");
effDesc = effDesc.substring(descIndex + 18);
String shieldDescription = key.toString() + " - " + shieldMap.get(shieldSource).get("ShieldAmount")
+ " shields - " + effDesc;
choices.add(shieldDescription);
choiceMap.put(shieldDescription, key);
}
shieldSource = this.getController().chooseProtectionShield(this, choices, choiceMap);
}
if (DEBUGShieldsWithEffects) {
System.out.println("Prevention shield source: " + shieldSource);
}
int shieldAmount = Integer.valueOf(shieldMap.get(shieldSource).get("ShieldAmount"));
int dmgToBePrevented = Math.min(restDamage, shieldAmount);
if (DEBUGShieldsWithEffects) {
System.out.println("Selected source initial shield amount: " + shieldAmount);
System.out.println("Incoming damage: " + restDamage);
System.out.println("Damage to be prevented: " + dmgToBePrevented);
}
//Set up ability
SpellAbility shieldSA = null;
String effectAbString = shieldMap.get(shieldSource).get("EffectString");
effectAbString = effectAbString.replace("PreventedDamage", Integer.toString(dmgToBePrevented));
effectAbString = effectAbString.replace("ShieldEffectTarget", shieldMap.get(shieldSource).get("ShieldEffectTarget"));
if (DEBUGShieldsWithEffects) {
System.out.println("Final shield ability string: " + effectAbString);
}
shieldSA = AbilityFactory.getAbility(effectAbString, shieldSource);
if (shieldSA.usesTargeting()) {
System.err.println(shieldSource + " - Targeting for prevention shield's effect should be done with initial spell");
}
if (restDamage >= shieldAmount) {
this.getController().playSpellAbilityNoStack(this, shieldSA);
this.subtractPreventNextDamageWithEffect(shieldSource, restDamage);
restDamage = restDamage - shieldAmount;
} else {
this.subtractPreventNextDamageWithEffect(shieldSource, restDamage);
this.getController().playSpellAbilityNoStack(this, shieldSA);
restDamage = 0;
}
if (DEBUGShieldsWithEffects) {
System.out.println("Remaining shields: "
+ (shieldMap.containsKey(shieldSource) ? shieldMap.get(shieldSource).get("ShieldAmount") : "all shields used"));
System.out.println("Remaining damage: " + restDamage);
}
}
final HashMap<String, Object> repParams = new HashMap<String, Object>(); final HashMap<String, Object> repParams = new HashMap<String, Object>();
repParams.put("Event", "DamageDone"); repParams.put("Event", "DamageDone");
repParams.put("Affected", this); repParams.put("Affected", this);
@@ -2757,6 +2818,7 @@ public class Player extends GameEntity implements Comparable<Player> {
c.setDrawnThisTurn(false); c.setDrawnThisTurn(false);
} }
resetPreventNextDamage(); resetPreventNextDamage();
resetPreventNextDamageWithEffect();
resetNumDrawnThisTurn(); resetNumDrawnThisTurn();
resetNumDiscardedThisTurn(); resetNumDiscardedThisTurn();
setAttackedWithCreatureThisTurn(false); setAttackedWithCreatureThisTurn(false);

View File

@@ -96,6 +96,7 @@ public abstract class PlayerController {
//public abstract void playFromSuspend(Card c); //public abstract void playFromSuspend(Card c);
public abstract boolean playCascade(Card cascadedCard, Card sourceCard); public abstract boolean playCascade(Card cascadedCard, Card sourceCard);
public abstract void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets); public abstract void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets);
public abstract void playSpellAbilityNoStack(Player player, SpellAbility effectSA);
public abstract Deck sideboard(final Deck deck, GameType gameType); public abstract Deck sideboard(final Deck deck, GameType gameType);
@@ -157,5 +158,6 @@ public abstract class PlayerController {
public abstract boolean chooseBinary(SpellAbility sa, String question, boolean isCoin); public abstract boolean chooseBinary(SpellAbility sa, String question, boolean isCoin);
public abstract boolean chooseFilpResult(SpellAbility sa, Player flipper, boolean[] results, boolean call); public abstract boolean chooseFilpResult(SpellAbility sa, Player flipper, boolean[] results, boolean call);
public abstract Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap);
} }

View File

@@ -248,6 +248,11 @@ public class PlayerControllerAi extends PlayerController {
ComputerUtil.playSpellAbilityForFree(player, copySA); ComputerUtil.playSpellAbilityForFree(player, copySA);
} }
@Override
public void playSpellAbilityNoStack(Player player, SpellAbility effectSA) {
ComputerUtil.playNoStack(player, effectSA, game);
}
@Override @Override
public void playMiracle(SpellAbility miracle, Card card) { public void playMiracle(SpellAbility miracle, Card card) {
getAi().chooseAndPlaySa(false, false, miracle); getAi().chooseAndPlaySa(false, false, miracle);
@@ -412,4 +417,10 @@ public class PlayerControllerAi extends PlayerController {
public boolean chooseBinary(SpellAbility sa, String question, boolean isCoin) { public boolean chooseBinary(SpellAbility sa, String question, boolean isCoin) {
return MyRandom.getRandom().nextBoolean(); return MyRandom.getRandom().nextBoolean();
} }
@Override
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
int i = MyRandom.getRandom().nextInt(options.size());
return choiceMap.get(options.get(i));
}
} }

View File

@@ -121,6 +121,11 @@ public class PlayerControllerHuman extends PlayerController {
HumanPlay.playSaWithoutPayingManaCost(player.getGame(), copySA, mayChoseNewTargets); HumanPlay.playSaWithoutPayingManaCost(player.getGame(), copySA, mayChoseNewTargets);
} }
@Override
public void playSpellAbilityNoStack(Player player, SpellAbility effectSA) {
HumanPlay.playSpellAbilityNoStack(player, effectSA);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.game.player.PlayerController#sideboard(forge.deck.Deck) * @see forge.game.player.PlayerController#sideboard(forge.deck.Deck)
*/ */
@@ -645,6 +650,12 @@ public class PlayerControllerHuman extends PlayerController {
return GuiChoose.one(sa.getSourceCard().getName() + " - Choose a result", strResults) == labelsSrc[0]; return GuiChoose.one(sa.getSourceCard().getName() + " - Choose a result", strResults) == labelsSrc[0];
} }
@Override
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
String title = entityBeingDamaged + " - select which prevention shield to use";
return choiceMap.get(GuiChoose.one(title, options));
}
@Override @Override
public Pair<SpellAbilityStackInstance, ITargetable> chooseTarget(SpellAbility saSpellskite, List<Pair<SpellAbilityStackInstance, ITargetable>> allTargets) { public Pair<SpellAbilityStackInstance, ITargetable> chooseTarget(SpellAbility saSpellskite, List<Pair<SpellAbilityStackInstance, ITargetable>> allTargets) {

View File

@@ -400,7 +400,7 @@ public class CardDetailPanel extends FPanel {
} }
// Damage Prevention // Damage Prevention
final int preventNextDamage = card.getPreventNextDamage(); final int preventNextDamage = card.getPreventNextDamageTotalShields();
if (preventNextDamage > 0) { if (preventNextDamage > 0) {
area.append("\n"); area.append("\n");
area.append("Prevent the next ").append(preventNextDamage).append(" damage that would be dealt to "); area.append("Prevent the next ").append(preventNextDamage).append(" damage that would be dealt to ");

View File

@@ -152,7 +152,7 @@ public enum VPlayers implements IVDoc<CPlayers> {
+ String.valueOf(p0.getPoisonCounters())); + String.valueOf(p0.getPoisonCounters()));
temp[2].setText("Maximum hand size: " + String.valueOf(p0.getMaxHandSize())); temp[2].setText("Maximum hand size: " + String.valueOf(p0.getMaxHandSize()));
temp[3].setText("Cards drawn this turn: " + String.valueOf(p0.getNumDrawnThisTurn())); temp[3].setText("Cards drawn this turn: " + String.valueOf(p0.getNumDrawnThisTurn()));
temp[4].setText("Damage Prevention: " + String.valueOf(p0.getPreventNextDamage())); temp[4].setText("Damage Prevention: " + String.valueOf(p0.getPreventNextDamageTotalShields()));
if (!p0.getKeywords().isEmpty()) { if (!p0.getKeywords().isEmpty()) {
temp[5].setText(p0.getKeywords().toString()); temp[5].setText(p0.getKeywords().toString());
} else { } else {