diff --git a/.gitattributes b/.gitattributes index ff416ed6b24..504555a4f10 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1999,6 +1999,7 @@ forge-gui/res/cardsfolder/a/assassins_strike.txt -text forge-gui/res/cardsfolder/a/assault_battery.txt -text forge-gui/res/cardsfolder/a/assault_griffin.txt svneol=native#text/plain forge-gui/res/cardsfolder/a/assault_strobe.txt svneol=native#text/plain +forge-gui/res/cardsfolder/a/assault_suit.txt -text forge-gui/res/cardsfolder/a/assault_zeppelid.txt svneol=native#text/plain forge-gui/res/cardsfolder/a/assemble_the_legion.txt -text forge-gui/res/cardsfolder/a/assembly_hall.txt -text diff --git a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java index 11c6c3f5e81..4ffbd520905 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java @@ -53,6 +53,7 @@ public class BalanceEffect extends SpellAbilityEffect { p.discard(card, sa); } } else { // Battlefield + // TODO: "can'e be sacrificed" for(Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) { if ( null == card ) continue; game.getAction().sacrifice(card, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java index 89278721eea..1de100e58c9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java @@ -151,7 +151,7 @@ public class ManaEffect extends SpellAbilityEffect { // Only clear express choice after mana has been produced abMana.clearExpressChoice(); - // convert these to SubAbilities when appropriate + // TODO: convert these to SubAbilities when appropriate if (sa.hasParam("Stuck")) { sa.setUndoable(false); card.addHiddenExtrinsicKeyword("This card doesn't untap during your next untap step."); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java index 68fe5c0bafb..be9958b0cfe 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java @@ -6,6 +6,7 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; import forge.game.card.CardUtil; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -54,6 +55,7 @@ public class SacrificeAllEffect extends SpellAbilityEffect { if (sa.hasParam("Controller")) { list = CardLists.filterControlledBy(list, AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Controller"), sa)); } + list = CardLists.filter(list, CardPredicates.canBeSacrificedBy(sa)); final boolean remSacrificed = sa.hasParam("RememberSacrificed"); if (remSacrificed) { 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 7f6a8aba4a6..83a829ef97a 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5850,6 +5850,10 @@ public class Card extends GameEntity implements Comparable, IIdentifiable return isInPlay() && (!hasKeyword("Indestructible") || (isCreature() && getNetToughness() <= 0)); } + public final boolean canBeSacrificed() { + return isInPlay() && !this.isPhasedOut() && !hasKeyword("CARDNAME can't be sacrificed."); + } + @Override public final boolean canBeTargetedBy(final SpellAbility sa) { if (sa == null) { @@ -6170,7 +6174,7 @@ public class Card extends GameEntity implements Comparable, IIdentifiable System.out.println("Trying to sacrifice immutables: " + this); return false; } - if (isPhasedOut()) { + if (!canBeSacrificed()) { return false; } if (source != null && getController().isOpponentOf(source.getActivatingPlayer()) diff --git a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java index b7cb23f61e1..b04a28b8e1c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java +++ b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java @@ -20,6 +20,7 @@ package forge.game.cost; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; @@ -92,6 +93,7 @@ public class CostSacrifice extends CostPartWithList { if (activator.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { typeList = CardLists.getNotType(typeList, "Creature"); } + typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability)); if (!needsAnnoucement && (amount != null) && (typeList.size() < amount)) { return false; @@ -102,7 +104,7 @@ public class CostSacrifice extends CostPartWithList { // choice, it can be Paid even if it's 0 } else { - if (!source.isInPlay()) { + if (!source.canBeSacrificed()) { return false; } else if (source.isCreature() && activator.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { diff --git a/forge-game/src/main/java/forge/game/mana/ManaCostAdjustment.java b/forge-game/src/main/java/forge/game/mana/ManaCostAdjustment.java index 182e71de795..c2bd62ce05c 100644 --- a/forge-game/src/main/java/forge/game/mana/ManaCostAdjustment.java +++ b/forge-game/src/main/java/forge/game/mana/ManaCostAdjustment.java @@ -174,7 +174,7 @@ public class ManaCostAdjustment { Card toSac = null; CardCollectionView canOffer = CardLists.filter(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), - CardPredicates.isType(offeringType)); + CardPredicates.isType(offeringType), CardPredicates.canBeSacrificedBy(sa)); final CardCollectionView toSacList = sa.getHostCard().getController().getController().choosePermanentsToSacrifice(sa, 0, 1, canOffer, offeringType); diff --git a/forge-game/src/main/java/forge/game/phase/Upkeep.java b/forge-game/src/main/java/forge/game/phase/Upkeep.java index fc061511e5f..b5fee76094e 100644 --- a/forge-game/src/main/java/forge/game/phase/Upkeep.java +++ b/forge-game/src/main/java/forge/game/phase/Upkeep.java @@ -154,7 +154,7 @@ public class Upkeep extends Phase { runParams.put("PayingMana", StringUtils.join(this.getPayingMana(), "")); game.getTriggerHandler().runTrigger(TriggerType.PayCumulativeUpkeep, runParams, false); if (!isPaid) { - game.getAction().sacrifice(c, null); + game.getAction().sacrifice(c, this); } } }; diff --git a/forge-gui/res/cardsfolder/a/assault_suit.txt b/forge-gui/res/cardsfolder/a/assault_suit.txt new file mode 100644 index 00000000000..3198b595c78 --- /dev/null +++ b/forge-gui/res/cardsfolder/a/assault_suit.txt @@ -0,0 +1,13 @@ +Name:Assault Suit +ManaCost:4 +Types:Artifact Equipment +K:Equip 3 +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Haste | AddHiddenKeyword$ CARDNAME can't be sacrificed. | AddPower$ 2 | AddToughness$ 2 | Description$ Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed. +S:Mode$ CantAttack | ValidCard$ Creature.EquippedBy | Target$ You,Planeswalker.YouCtrl +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Opponent | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigGainControl | TriggerDescription$ At the beginning of each opponent's upkeep, you may have that player gain control of equipped creature until end of turn. If you do, untap it. +SVar:TrigGainControl:AB$ GainControl | Cost$ 0 | Defined$ Equipped | NewController$ TriggeredPlayer | LoseControl$ EOT | RememberControlled$ True | SubAbility$ DBUntap +SVar:DBUntap:DB$ Untap | Defined$ Equipped | ConditionDefined$ Rememebered | ConditionPresent$ Creature | ConditionCompare$ GE1 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/assault_suit.jpg +Oracle:Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed.\nAt the beginning of each opponent's upkeep, you may have that player gain control of equipped creature until end of turn. If you do, untap it.\nEquip {3} diff --git a/forge-gui/res/cardsfolder/t/twisted_justice.txt b/forge-gui/res/cardsfolder/t/twisted_justice.txt index 2cdbb166a68..f25aa609ef6 100644 --- a/forge-gui/res/cardsfolder/t/twisted_justice.txt +++ b/forge-gui/res/cardsfolder/t/twisted_justice.txt @@ -2,7 +2,7 @@ Name:Twisted Justice ManaCost:4 U B Types:Sorcery A:SP$ Sacrifice | Cost$ 4 U B | ValidTgts$ Player | SacValid$ Creature | SacMessage$ Creature | RememberSacrificed$ True | SubAbility$ DBDraw | SpellDescription$ Target player sacrifices a creature. You draw cards equal to that creature's power. -SVar:DBDraw:DB$ Draw | NumCards$ X +SVar:DBDraw:DB$ Draw | NumCards$ X | References$ X SVar:X:RememberedLKI$CardPower SVar:Picture:http://www.wizards.com/global/images/magic/general/twisted_justice.jpg Oracle:Target player sacrifices a creature. You draw cards equal to that creature's power. diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 61c4426a133..dd1d2be370c 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -963,7 +963,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { final String amount = cost.getAmount(); final String type = cost.getType(); - CardCollectionView list = player.getCardsIn(ZoneType.Battlefield); + CardCollectionView list = CardLists.filter(player.getCardsIn(ZoneType.Battlefield), CardPredicates.canBeSacrificedBy(ability)); list = CardLists.getValidCards(list, type.split(";"), player, source); if (player.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { list = CardLists.getNotType(list, "Creature");