mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch 'playTriggerChangesZoneAll' into 'master'
Update PhaseHandler for Trigger ChangesZoneAll See merge request core-developers/forge!1214
This commit is contained in:
@@ -1514,7 +1514,7 @@ public class ComputerUtilMana {
|
|||||||
final Card offering = sa.getSacrificedAsOffering();
|
final Card offering = sa.getSacrificedAsOffering();
|
||||||
offering.setUsedToPay(false);
|
offering.setUsedToPay(false);
|
||||||
if (costIsPaid && !test) {
|
if (costIsPaid && !test) {
|
||||||
sa.getHostCard().getController().getGame().getAction().sacrifice(offering, sa);
|
sa.getHostCard().getGame().getAction().sacrifice(offering, sa, null);
|
||||||
}
|
}
|
||||||
sa.resetSacrificedAsOffering();
|
sa.resetSacrificedAsOffering();
|
||||||
}
|
}
|
||||||
@@ -1522,7 +1522,7 @@ public class ComputerUtilMana {
|
|||||||
final Card emerge = sa.getSacrificedAsEmerge();
|
final Card emerge = sa.getSacrificedAsEmerge();
|
||||||
emerge.setUsedToPay(false);
|
emerge.setUsedToPay(false);
|
||||||
if (costIsPaid && !test) {
|
if (costIsPaid && !test) {
|
||||||
sa.getHostCard().getController().getGame().getAction().sacrifice(emerge, sa);
|
sa.getHostCard().getGame().getAction().sacrifice(emerge, sa, null);
|
||||||
}
|
}
|
||||||
sa.resetSacrificedAsEmerge();
|
sa.resetSacrificedAsEmerge();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ public class MustBlockAi extends SpellAbilityAi {
|
|||||||
return chance;
|
return chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Card> determineGoodBlockers(final Card attacker,final Player ai,final Player defender, SpellAbility sa, final boolean onlyLethal, final boolean testTapped) {
|
private List<Card> determineGoodBlockers(final Card attacker, final Player ai, Player defender, SpellAbility sa,
|
||||||
|
final boolean onlyLethal, final boolean testTapped) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final TargetRestrictions abTgt = sa.getTargetRestrictions();
|
final TargetRestrictions abTgt = sa.getTargetRestrictions();
|
||||||
|
|
||||||
|
|||||||
@@ -926,6 +926,8 @@ public class GameAction {
|
|||||||
checkStaticAbilities(false, affectedCards, CardCollection.EMPTY);
|
checkStaticAbilities(false, affectedCards, CardCollection.EMPTY);
|
||||||
boolean checkAgain = false;
|
boolean checkAgain = false;
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
|
|
||||||
for (final Player p : game.getPlayers()) {
|
for (final Player p : game.getPlayers()) {
|
||||||
for (final ZoneType zt : ZoneType.values()) {
|
for (final ZoneType zt : ZoneType.values()) {
|
||||||
if (zt == ZoneType.Battlefield) {
|
if (zt == ZoneType.Battlefield) {
|
||||||
@@ -973,8 +975,8 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAgain |= stateBasedAction_Saga(c);
|
checkAgain |= stateBasedAction_Saga(c, table);
|
||||||
checkAgain |= stateBasedAction704_attach(c); // Attachment
|
checkAgain |= stateBasedAction704_attach(c, table); // Attachment
|
||||||
|
|
||||||
if (c.isCreature() && c.isAttachedToEntity()) { // Rule 704.5q - Creature attached to an object or player, becomes unattached
|
if (c.isCreature() && c.isAttachedToEntity()) { // Rule 704.5q - Creature attached to an object or player, becomes unattached
|
||||||
c.unattachFromEntity(c.getEntityAttachedTo());
|
c.unattachFromEntity(c.getEntityAttachedTo());
|
||||||
@@ -999,24 +1001,19 @@ public class GameAction {
|
|||||||
orderedNoRegCreats = true;
|
orderedNoRegCreats = true;
|
||||||
}
|
}
|
||||||
for (Card c : noRegCreats) {
|
for (Card c : noRegCreats) {
|
||||||
sacrificeDestroy(c, null);
|
sacrificeDestroy(c, null, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (desCreats != null) {
|
if (desCreats != null) {
|
||||||
if (desCreats.size() > 1 && !orderedDesCreats) {
|
if (desCreats.size() > 1 && !orderedDesCreats) {
|
||||||
desCreats = CardLists.filter(desCreats, new Predicate<Card>() {
|
desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED);
|
||||||
@Override
|
|
||||||
public boolean apply(Card card) {
|
|
||||||
return card.canBeDestroyed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!desCreats.isEmpty()) {
|
if (!desCreats.isEmpty()) {
|
||||||
desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard);
|
desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard);
|
||||||
}
|
}
|
||||||
orderedDesCreats = true;
|
orderedDesCreats = true;
|
||||||
}
|
}
|
||||||
for (Card c : desCreats) {
|
for (Card c : desCreats) {
|
||||||
destroy(c, null);
|
destroy(c, null, true, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setHoldCheckingStaticAbilities(false);
|
setHoldCheckingStaticAbilities(false);
|
||||||
@@ -1026,20 +1023,21 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Player p : game.getPlayers()) {
|
for (Player p : game.getPlayers()) {
|
||||||
if (handleLegendRule(p)) {
|
if (handleLegendRule(p, table)) {
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlePlaneswalkerRule(p)) {
|
if (handlePlaneswalkerRule(p, table)) {
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 704.5m World rule
|
// 704.5m World rule
|
||||||
checkAgain |= handleWorldRule();
|
checkAgain |= handleWorldRule(table);
|
||||||
|
|
||||||
if (game.getCombat() != null) {
|
if (game.getCombat() != null) {
|
||||||
game.getCombat().removeAbsentCombatants();
|
game.getCombat().removeAbsentCombatants();
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
if (!checkAgain) {
|
if (!checkAgain) {
|
||||||
break; // do not continue the loop
|
break; // do not continue the loop
|
||||||
}
|
}
|
||||||
@@ -1072,7 +1070,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean stateBasedAction_Saga(Card c) {
|
private boolean stateBasedAction_Saga(Card c, CardZoneTable table) {
|
||||||
boolean checkAgain = false;
|
boolean checkAgain = false;
|
||||||
if (!c.getType().hasSubtype("Saga")) {
|
if (!c.getType().hasSubtype("Saga")) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1085,13 +1083,13 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
if (!game.getStack().hasSimultaneousStackEntries() &&
|
if (!game.getStack().hasSimultaneousStackEntries() &&
|
||||||
!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
|
!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
|
||||||
sacrifice(c, null);
|
sacrifice(c, null, table);
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
return checkAgain;
|
return checkAgain;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean stateBasedAction704_attach(Card c) {
|
private boolean stateBasedAction704_attach(Card c, CardZoneTable table) {
|
||||||
boolean checkAgain = false;
|
boolean checkAgain = false;
|
||||||
|
|
||||||
if (c.isAttachedToEntity()) {
|
if (c.isAttachedToEntity()) {
|
||||||
@@ -1113,7 +1111,7 @@ public class GameAction {
|
|||||||
|
|
||||||
// cleanup aura
|
// cleanup aura
|
||||||
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
|
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
|
||||||
moveToGraveyard(c, null, null);
|
sacrificeDestroy(c, null, table);
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
return checkAgain;
|
return checkAgain;
|
||||||
@@ -1243,7 +1241,7 @@ public class GameAction {
|
|||||||
game.getStack().clearSimultaneousStack();
|
game.getStack().clearSimultaneousStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handlePlaneswalkerRule(Player p) {
|
private boolean handlePlaneswalkerRule(Player p, CardZoneTable table) {
|
||||||
// get all Planeswalkers
|
// get all Planeswalkers
|
||||||
final List<Card> list = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.PLANESWALKERS);
|
final List<Card> list = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.PLANESWALKERS);
|
||||||
boolean recheck = false;
|
boolean recheck = false;
|
||||||
@@ -1252,7 +1250,7 @@ public class GameAction {
|
|||||||
|
|
||||||
for (Card c : list) {
|
for (Card c : list) {
|
||||||
if (c.getCounters(CounterType.LOYALTY) <= 0) {
|
if (c.getCounters(CounterType.LOYALTY) <= 0) {
|
||||||
moveToGraveyard(c, null, null);
|
sacrificeDestroy(c, null, table);
|
||||||
// Play the Destroy sound
|
// Play the Destroy sound
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
game.fireEvent(new GameEventCardDestroyed());
|
||||||
recheck = true;
|
recheck = true;
|
||||||
@@ -1286,7 +1284,7 @@ public class GameAction {
|
|||||||
return recheck;
|
return recheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleLegendRule(Player p) {
|
private boolean handleLegendRule(Player p, CardZoneTable table) {
|
||||||
final List<Card> a = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), "Legendary");
|
final List<Card> a = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), "Legendary");
|
||||||
if (a.isEmpty() || game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
if (a.isEmpty() || game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1314,7 +1312,7 @@ public class GameAction {
|
|||||||
Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(cc), new AbilitySub(ApiType.InternalLegendaryRule, null, null, null), "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)");
|
Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(cc), new AbilitySub(ApiType.InternalLegendaryRule, null, null, null), "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)");
|
||||||
for (Card c: cc) {
|
for (Card c: cc) {
|
||||||
if (c != toKeep) {
|
if (c != toKeep) {
|
||||||
sacrificeDestroy(c, null);
|
sacrificeDestroy(c, null, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
game.fireEvent(new GameEventCardDestroyed());
|
||||||
@@ -1323,7 +1321,7 @@ public class GameAction {
|
|||||||
return recheck;
|
return recheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleWorldRule() {
|
private boolean handleWorldRule(CardZoneTable table) {
|
||||||
final List<Card> worlds = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "World");
|
final List<Card> worlds = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "World");
|
||||||
if (worlds.size() <= 1) {
|
if (worlds.size() <= 1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1348,35 +1346,28 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Card c : worlds) {
|
for (Card c : worlds) {
|
||||||
sacrificeDestroy(c, null);
|
sacrificeDestroy(c, null, table);
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
game.fireEvent(new GameEventCardDestroyed());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public final Card sacrifice(final Card c, final SpellAbility source) {
|
public final Card sacrifice(final Card c, final SpellAbility source) {
|
||||||
|
return sacrifice(c, source, null);
|
||||||
|
}
|
||||||
|
public final Card sacrifice(final Card c, final SpellAbility source, CardZoneTable table) {
|
||||||
if (!c.canBeSacrificedBy(source)) {
|
if (!c.canBeSacrificedBy(source)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.getController().addSacrificedThisTurn(c, source);
|
c.getController().addSacrificedThisTurn(c, source);
|
||||||
|
|
||||||
return sacrificeDestroy(c, source);
|
return sacrificeDestroy(c, source, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean destroy(final Card c, final SpellAbility sa) {
|
public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate, CardZoneTable table) {
|
||||||
if (!c.canBeDestroyed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return destroy(c, sa, true);
|
|
||||||
}
|
|
||||||
public final boolean destroyNoRegeneration(final Card c, final SpellAbility sa) {
|
|
||||||
return destroy(c, sa, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate) {
|
|
||||||
Player activator = null;
|
Player activator = null;
|
||||||
if (!c.canBeDestroyed()) {
|
if (!c.canBeDestroyed()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1408,7 +1399,7 @@ public class GameAction {
|
|||||||
runParams.put("Causer", activator);
|
runParams.put("Causer", activator);
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false);
|
||||||
|
|
||||||
final Card sacrificed = sacrificeDestroy(c, sa);
|
final Card sacrificed = sacrificeDestroy(c, sa, table);
|
||||||
return sacrificed != null;
|
return sacrificed != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1416,12 +1407,15 @@ public class GameAction {
|
|||||||
* @return the sacrificed Card in its new location, or {@code null} if the
|
* @return the sacrificed Card in its new location, or {@code null} if the
|
||||||
* sacrifice wasn't successful.
|
* sacrifice wasn't successful.
|
||||||
*/
|
*/
|
||||||
public final Card sacrificeDestroy(final Card c, SpellAbility cause) {
|
protected final Card sacrificeDestroy(final Card c, SpellAbility cause, CardZoneTable table) {
|
||||||
if (!c.isInPlay()) {
|
if (!c.isInPlay()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Card newCard = moveToGraveyard(c, cause, null);
|
final Card newCard = moveToGraveyard(c, cause, null);
|
||||||
|
if (table != null) {
|
||||||
|
table.put(ZoneType.Battlefield, newCard.getZone().getZoneType(), newCard);
|
||||||
|
}
|
||||||
|
|
||||||
return newCard;
|
return newCard;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class ActivateAbilityEffect extends SpellAbilityEffect {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(
|
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(
|
||||||
possibleAb, sa, "Choose a mana ability:", ImmutableMap.of());
|
possibleAb, sa, "Choose a mana ability:", ImmutableMap.<String, Object>of());
|
||||||
p.getController().playChosenSpellAbility(manaAb);
|
p.getController().playChosenSpellAbility(manaAb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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.CardLists;
|
import forge.game.card.CardLists;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
@@ -41,6 +42,7 @@ public class BalanceEffect extends SpellAbilityEffect {
|
|||||||
min = Math.min(min, validCards.get(i).size());
|
min = Math.min(min, validCards.get(i).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
for(int i = 0; i < players.size(); i++) {
|
for(int i = 0; i < players.size(); i++) {
|
||||||
Player p = players.get(i);
|
Player p = players.get(i);
|
||||||
int numToBalance = validCards.get(i).size() - min;
|
int numToBalance = validCards.get(i).size() - min;
|
||||||
@@ -50,15 +52,16 @@ public class BalanceEffect extends SpellAbilityEffect {
|
|||||||
if (zone.equals(ZoneType.Hand)) {
|
if (zone.equals(ZoneType.Hand)) {
|
||||||
for (Card card : p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance)) {
|
for (Card card : p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance)) {
|
||||||
if ( null == card ) continue;
|
if ( null == card ) continue;
|
||||||
p.discard(card, sa);
|
p.discard(card, sa, table);
|
||||||
}
|
}
|
||||||
} else { // Battlefield
|
} else { // Battlefield
|
||||||
// TODO: "can'e be sacrificed"
|
// TODO: "can'e be sacrificed"
|
||||||
for(Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
|
for(Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
|
||||||
if ( null == card ) continue;
|
if ( null == card ) continue;
|
||||||
game.getAction().sacrifice(card, sa);
|
game.getAction().sacrifice(card, sa, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
// movedCards should have same timestamp
|
// movedCards should have same timestamp
|
||||||
long ts = game.getNextTimestamp();
|
long ts = game.getNextTimestamp();
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
final CardZoneTable triggerList = new CardZoneTable();
|
||||||
for (final Card c : cards) {
|
for (final Card c : cards) {
|
||||||
final Zone originZone = game.getZoneOf(c);
|
final Zone originZone = game.getZoneOf(c);
|
||||||
|
|
||||||
@@ -209,21 +209,13 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!movedCard.getZone().equals(originZone)) {
|
if (!movedCard.getZone().equals(originZone)) {
|
||||||
if (!triggerList.containsKey(originZone.getZoneType())) {
|
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), movedCard);
|
||||||
triggerList.put(originZone.getZoneType(), new CardCollection());
|
|
||||||
}
|
|
||||||
triggerList.get(originZone.getZoneType()).add(movedCard);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().resetActiveTriggers(false);
|
game.getTriggerHandler().resetActiveTriggers(false);
|
||||||
|
|
||||||
if (!triggerList.isEmpty()) {
|
triggerList.triggerChangesZoneAll(game);
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", destination);
|
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if Shuffle parameter exists, and any amount of cards were owned by
|
// if Shuffle parameter exists, and any amount of cards were owned by
|
||||||
// that player, then shuffle that library
|
// that player, then shuffle that library
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
final boolean optional = sa.hasParam("Optional");
|
final boolean optional = sa.hasParam("Optional");
|
||||||
final long ts = game.getNextTimestamp();
|
final long ts = game.getNextTimestamp();
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
final CardZoneTable triggerList = new CardZoneTable();
|
||||||
|
|
||||||
for (final Card tgtC : tgtCards) {
|
for (final Card tgtC : tgtCards) {
|
||||||
if (tgt != null && tgtC.isInPlay() && !tgtC.canBeTargetedBy(sa)) {
|
if (tgt != null && tgtC.isInPlay() && !tgtC.canBeTargetedBy(sa)) {
|
||||||
@@ -602,10 +602,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!movedCard.getZone().equals(originZone)) {
|
if (!movedCard.getZone().equals(originZone)) {
|
||||||
if (!triggerList.containsKey(originZone.getZoneType())) {
|
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), movedCard);
|
||||||
triggerList.put(originZone.getZoneType(), new CardCollection());
|
|
||||||
}
|
|
||||||
triggerList.get(originZone.getZoneType()).add(movedCard);
|
|
||||||
|
|
||||||
if (remember != null) {
|
if (remember != null) {
|
||||||
hostCard.addRemembered(movedCard);
|
hostCard.addRemembered(movedCard);
|
||||||
@@ -619,12 +616,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!triggerList.isEmpty()) {
|
triggerList.triggerChangesZoneAll(game);
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", destination);
|
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for things like Gaea's Blessing
|
// for things like Gaea's Blessing
|
||||||
if (destination.equals(ZoneType.Library) && sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle"))) {
|
if (destination.equals(ZoneType.Library) && sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle"))) {
|
||||||
@@ -951,8 +943,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
CardCollection movedCards = new CardCollection();
|
CardCollection movedCards = new CardCollection();
|
||||||
long ts = game.getNextTimestamp();
|
long ts = game.getNextTimestamp();
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
final CardZoneTable triggerList = new CardZoneTable();
|
||||||
for (Card c : chosenCards) {
|
for (final Card c : chosenCards) {
|
||||||
Card movedCard = null;
|
Card movedCard = null;
|
||||||
final Zone originZone = game.getZoneOf(c);
|
final Zone originZone = game.getZoneOf(c);
|
||||||
if (destination.equals(ZoneType.Library)) {
|
if (destination.equals(ZoneType.Library)) {
|
||||||
@@ -1117,10 +1109,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
movedCards.add(movedCard);
|
movedCards.add(movedCard);
|
||||||
|
|
||||||
if (originZone != null) {
|
if (originZone != null) {
|
||||||
if (!triggerList.containsKey(originZone.getZoneType())) {
|
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), movedCard);
|
||||||
triggerList.put(originZone.getZoneType(), new CardCollection());
|
|
||||||
}
|
|
||||||
triggerList.get(originZone.getZoneType()).add(movedCard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (champion) {
|
if (champion) {
|
||||||
@@ -1152,13 +1141,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
player.shuffle(sa);
|
player.shuffle(sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!triggerList.isEmpty()) {
|
triggerList.triggerChangesZoneAll(game);
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", destination);
|
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean allowMultiSelect(Player decider, SpellAbility sa) {
|
private static boolean allowMultiSelect(Player decider, SpellAbility sa) {
|
||||||
@@ -1231,24 +1214,4 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkCanIndirectlyAttachTo(final Card source, final Card target) {
|
|
||||||
final SpellAbility attachEff = source.getFirstAttachSpell();
|
|
||||||
|
|
||||||
if (attachEff == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Game game = source.getGame();
|
|
||||||
final TargetRestrictions tgt = attachEff.getTargetRestrictions();
|
|
||||||
|
|
||||||
Player attachEffCtrl = attachEff.getActivatingPlayer();
|
|
||||||
if (attachEffCtrl == null && attachEff.getHostCard() != null) {
|
|
||||||
attachEffCtrl = attachEff.getHostCard().getController();
|
|
||||||
}
|
|
||||||
|
|
||||||
CardCollectionView list = game.getCardsIn(tgt.getZone());
|
|
||||||
list = CardLists.getValidCards(list, tgt.getValidTgts(), attachEffCtrl, source, attachEff);
|
|
||||||
return list.contains(target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,12 +206,7 @@ public class ControlGainEffect extends SpellAbilityEffect {
|
|||||||
final Ability ability = new Ability(hostCard, ManaCost.ZERO) {
|
final Ability ability = new Ability(hostCard, ManaCost.ZERO) {
|
||||||
@Override
|
@Override
|
||||||
public void resolve() {
|
public void resolve() {
|
||||||
|
game.getAction().destroy(c, null, !bNoRegen, null);
|
||||||
if (bNoRegen) {
|
|
||||||
game.getAction().destroyNoRegeneration(c, null);
|
|
||||||
} else {
|
|
||||||
game.getAction().destroy(c, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
// Destroy Permanent may be able to be turned into a SubAbility
|
// Destroy Permanent may be able to be turned into a SubAbility
|
||||||
if (tgtSA.isAbility() && sa.hasParam("DestroyPermanent")) {
|
if (tgtSA.isAbility() && sa.hasParam("DestroyPermanent")) {
|
||||||
game.getAction().destroy(tgtSACard, sa);
|
game.getAction().destroy(tgtSACard, sa, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sa.hasParam("RememberCountered")) {
|
if (sa.hasParam("RememberCountered")) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -8,7 +7,9 @@ import forge.game.ability.SpellAbilityEffect;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
@@ -78,30 +79,20 @@ public class DestroyAllEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// exclude cards that can't be destroyed at this moment
|
// exclude cards that can't be destroyed at this moment
|
||||||
list = CardLists.filter(list, new Predicate<Card>() {
|
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED);
|
||||||
@Override
|
|
||||||
public boolean apply(Card card) {
|
|
||||||
return card.canBeDestroyed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (list.size() > 1) {
|
if (list.size() > 1) {
|
||||||
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
|
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noRegen) {
|
CardZoneTable table = new CardZoneTable();
|
||||||
for (Card c : list) {
|
|
||||||
if (game.getAction().destroyNoRegeneration(c, sa) && remDestroyed) {
|
for (Card c : list) {
|
||||||
card.addRemembered(CardUtil.getLKICopy(c));
|
if (game.getAction().destroy(c, sa, !noRegen, table) && remDestroyed) {
|
||||||
}
|
card.addRemembered(CardUtil.getLKICopy(c));
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (Card c : list) {
|
|
||||||
if (game.getAction().destroy(c, sa) && remDestroyed) {
|
|
||||||
card.addRemembered(CardUtil.getLKICopy(c));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ 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.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -77,8 +77,6 @@ public class DestroyEffect extends SpellAbilityEffect {
|
|||||||
CardCollection tgtCards = getTargetCards(sa);
|
CardCollection tgtCards = getTargetCards(sa);
|
||||||
CardCollection untargetedCards = new CardCollection();
|
CardCollection untargetedCards = new CardCollection();
|
||||||
|
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
|
|
||||||
if (sa.hasParam("Radiance")) {
|
if (sa.hasParam("Radiance")) {
|
||||||
for (final Card c : CardUtil.getRadiance(card, tgtCards.get(0),
|
for (final Card c : CardUtil.getRadiance(card, tgtCards.get(0),
|
||||||
sa.getParam("ValidTgts").split(","))) {
|
sa.getParam("ValidTgts").split(","))) {
|
||||||
@@ -90,19 +88,18 @@ public class DestroyEffect extends SpellAbilityEffect {
|
|||||||
tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard);
|
tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
for (final Card tgtC : tgtCards) {
|
for (final Card tgtC : tgtCards) {
|
||||||
if (tgtC.isInPlay() && ((tgt == null) || tgtC.canBeTargetedBy(sa))) {
|
if (tgtC.isInPlay() && (!sa.usesTargeting() || tgtC.canBeTargetedBy(sa))) {
|
||||||
boolean destroyed = false;
|
boolean destroyed = false;
|
||||||
final Card lki = CardUtil.getLKICopy(tgtC);
|
final Card lki = CardUtil.getLKICopy(tgtC);
|
||||||
if (remAttached) {
|
if (remAttached) {
|
||||||
card.addRemembered(tgtC.getAttachedCards());
|
card.addRemembered(tgtC.getAttachedCards());
|
||||||
}
|
}
|
||||||
if (sac) {
|
if (sac) {
|
||||||
destroyed = game.getAction().sacrifice(tgtC, sa) != null;
|
destroyed = game.getAction().sacrifice(tgtC, sa, table) != null;
|
||||||
} else if (noRegen) {
|
|
||||||
destroyed = game.getAction().destroyNoRegeneration(tgtC, sa);
|
|
||||||
} else {
|
} else {
|
||||||
destroyed = game.getAction().destroy(tgtC, sa);
|
destroyed = game.getAction().destroy(tgtC, sa, !noRegen, table);
|
||||||
}
|
}
|
||||||
if (destroyed && remDestroyed) {
|
if (destroyed && remDestroyed) {
|
||||||
card.addRemembered(tgtC);
|
card.addRemembered(tgtC);
|
||||||
@@ -121,16 +118,16 @@ public class DestroyEffect extends SpellAbilityEffect {
|
|||||||
if (unTgtC.isInPlay()) {
|
if (unTgtC.isInPlay()) {
|
||||||
boolean destroyed = false;
|
boolean destroyed = false;
|
||||||
if (sac) {
|
if (sac) {
|
||||||
destroyed = game.getAction().sacrifice(unTgtC, sa) != null;
|
destroyed = game.getAction().sacrifice(unTgtC, sa, table) != null;
|
||||||
} else if (noRegen) {
|
|
||||||
destroyed = game.getAction().destroyNoRegeneration(unTgtC, sa);
|
|
||||||
} else {
|
} else {
|
||||||
destroyed = game.getAction().destroy(unTgtC, sa);
|
destroyed = game.getAction().destroy(unTgtC, sa, !noRegen, table);
|
||||||
} if (destroyed && remDestroyed) {
|
} if (destroyed && remDestroyed) {
|
||||||
card.addRemembered(unTgtC);
|
card.addRemembered(unTgtC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ 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.CardLists;
|
import forge.game.card.CardLists;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -109,6 +110,7 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
for (final Player p : tgtPlayers) {
|
for (final Player p : tgtPlayers) {
|
||||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -301,6 +303,7 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
effectHost = sa.getHostCard();
|
effectHost = sa.getHostCard();
|
||||||
}
|
}
|
||||||
for (Card c : movedCards) {
|
for (Card c : movedCards) {
|
||||||
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
final PlayerZone zone = c.getOwner().getZone(destZone1);
|
final PlayerZone zone = c.getOwner().getZone(destZone1);
|
||||||
|
|
||||||
if (zone.is(ZoneType.Library) || zone.is(ZoneType.PlanarDeck) || zone.is(ZoneType.SchemeDeck)) {
|
if (zone.is(ZoneType.Library) || zone.is(ZoneType.PlanarDeck) || zone.is(ZoneType.SchemeDeck)) {
|
||||||
@@ -322,6 +325,9 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
c.setExiledWith(effectHost);
|
c.setExiledWith(effectHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!origin.equals(c.getZone().getZoneType())) {
|
||||||
|
table.put(origin, c.getZone().getZoneType(), c);
|
||||||
|
}
|
||||||
|
|
||||||
if (sa.hasParam("ExileFaceDown")) {
|
if (sa.hasParam("ExileFaceDown")) {
|
||||||
c.setState(CardStateName.FaceDown, true);
|
c.setState(CardStateName.FaceDown, true);
|
||||||
@@ -357,11 +363,16 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
Collections.reverse(afterOrder);
|
Collections.reverse(afterOrder);
|
||||||
}
|
}
|
||||||
for (final Card c : afterOrder) {
|
for (final Card c : afterOrder) {
|
||||||
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
|
Card m;
|
||||||
if (destZone2 == ZoneType.Library) {
|
if (destZone2 == ZoneType.Library) {
|
||||||
game.getAction().moveToLibrary(c, libraryPosition2, sa);
|
m = game.getAction().moveToLibrary(c, libraryPosition2, sa);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
game.getAction().moveToVariantDeck(c, destZone2, libraryPosition2, sa);
|
m = game.getAction().moveToVariantDeck(c, destZone2, libraryPosition2, sa);
|
||||||
|
}
|
||||||
|
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||||
|
table.put(origin, m.getZone().getZoneType(), m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,8 +380,12 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
// just move them randomly
|
// just move them randomly
|
||||||
for (int i = 0; i < rest.size(); i++) {
|
for (int i = 0; i < rest.size(); i++) {
|
||||||
Card c = rest.get(i);
|
Card c = rest.get(i);
|
||||||
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
final PlayerZone toZone = c.getOwner().getZone(destZone2);
|
final PlayerZone toZone = c.getOwner().getZone(destZone2);
|
||||||
c = game.getAction().moveTo(toZone, c, sa);
|
c = game.getAction().moveTo(toZone, c, sa);
|
||||||
|
if (!origin.equals(c.getZone().getZoneType())) {
|
||||||
|
table.put(origin, c.getZone().getZoneType(), c);
|
||||||
|
}
|
||||||
if (destZone2 == ZoneType.Battlefield && !keywords.isEmpty()) {
|
if (destZone2 == ZoneType.Battlefield && !keywords.isEmpty()) {
|
||||||
for (final String kw : keywords) {
|
for (final String kw : keywords) {
|
||||||
c.addExtrinsicKeyword(kw);
|
c.addExtrinsicKeyword(kw);
|
||||||
@@ -386,6 +401,8 @@ public class DigEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//table trigger there
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This should be somewhere else, maybe like CardUtil or something like that
|
// TODO This should be somewhere else, maybe like CardUtil or something like that
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ 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.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.PlayerZone;
|
import forge.game.zone.PlayerZone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
@@ -76,6 +76,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final Card host = sa.getHostCard();
|
final Card host = sa.getHostCard();
|
||||||
|
final Game game = host.getGame();
|
||||||
|
|
||||||
String[] type = new String[]{"Card"};
|
String[] type = new String[]{"Card"};
|
||||||
if (sa.hasParam("Valid")) {
|
if (sa.hasParam("Valid")) {
|
||||||
@@ -94,8 +95,6 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
final boolean remember = sa.hasParam("RememberFound");
|
final boolean remember = sa.hasParam("RememberFound");
|
||||||
|
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
|
|
||||||
final ZoneType foundDest = ZoneType.smartValueOf(sa.getParam("FoundDestination"));
|
final ZoneType foundDest = ZoneType.smartValueOf(sa.getParam("FoundDestination"));
|
||||||
final int foundLibPos = AbilityUtils.calculateAmount(host, sa.getParam("FoundLibraryPosition"), sa);
|
final int foundLibPos = AbilityUtils.calculateAmount(host, sa.getParam("FoundLibraryPosition"), sa);
|
||||||
final ZoneType revealedDest = ZoneType.smartValueOf(sa.getParam("RevealedDestination"));
|
final ZoneType revealedDest = ZoneType.smartValueOf(sa.getParam("RevealedDestination"));
|
||||||
@@ -107,11 +106,13 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
final boolean optional = sa.hasParam("Optional");
|
final boolean optional = sa.hasParam("Optional");
|
||||||
final boolean optionalFound = sa.hasParam("OptionalFoundMove");
|
final boolean optionalFound = sa.hasParam("OptionalFoundMove");
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if (p == null) {
|
if (p == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
if (optional && !p.getController().confirmAction(sa, null, "Do you want to dig your library?")) {
|
if (optional && !p.getController().confirmAction(sa, null, "Do you want to dig your library?")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -142,7 +143,6 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Game game = p.getGame();
|
|
||||||
if (revealed.size() > 0) {
|
if (revealed.size() > 0) {
|
||||||
game.getAction().reveal(revealed, p, false);
|
game.getAction().reveal(revealed, p, false);
|
||||||
}
|
}
|
||||||
@@ -157,19 +157,24 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
final Iterator<Card> itr = found.iterator();
|
final Iterator<Card> itr = found.iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Card c = itr.next();
|
final Card c = itr.next();
|
||||||
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
if (optionalFound && !p.getController().confirmAction(sa, null,
|
if (optionalFound && !p.getController().confirmAction(sa, null,
|
||||||
"Do you want to put that card to " + foundDest.name() + "?")) {
|
"Do you want to put that card to " + foundDest.name() + "?")) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
Card m = null;
|
||||||
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
|
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
|
||||||
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||||
game.getAction().moveTo(c.getController().getZone(foundDest), c, sa);
|
m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa);
|
||||||
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
|
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
|
||||||
//Don't do anything
|
//Don't do anything
|
||||||
} else {
|
} else {
|
||||||
game.getAction().moveTo(foundDest, c, foundLibPos, sa);
|
m = game.getAction().moveTo(foundDest, c, foundLibPos, sa);
|
||||||
}
|
}
|
||||||
revealed.remove(c);
|
revealed.remove(c);
|
||||||
|
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||||
|
table.put(origin, m.getZone().getZoneType(), m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +206,11 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
final Iterator<Card> itr = revealed.iterator();
|
final Iterator<Card> itr = revealed.iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Card c = itr.next();
|
final Card c = itr.next();
|
||||||
game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa);
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
|
final Card m = game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa);
|
||||||
|
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||||
|
table.put(origin, m.getZone().getZoneType(), m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Allow ordering the rest of the revealed cards
|
// Allow ordering the rest of the revealed cards
|
||||||
@@ -216,7 +225,11 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
final Iterator<Card> itr = revealed.iterator();
|
final Iterator<Card> itr = revealed.iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Card c = itr.next();
|
final Card c = itr.next();
|
||||||
game.getAction().moveTo(revealedDest, c, revealedLibPos, sa);
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
|
final Card m = game.getAction().moveTo(revealedDest, c, revealedLibPos, sa);
|
||||||
|
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||||
|
table.put(origin, m.getZone().getZoneType(), m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +238,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
} // end foreach player
|
} // end foreach player
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
} // end resolve
|
} // end resolve
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
@@ -10,12 +8,17 @@ import forge.game.card.CardPredicates.Presets;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerActionConfirmMode;
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
|
import forge.util.Lang;
|
||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -29,10 +32,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||||
|
|
||||||
if (!tgtPlayers.isEmpty()) {
|
if (!tgtPlayers.isEmpty()) {
|
||||||
|
sb.append(Lang.joinHomogenous(tgtPlayers)).append(" ");
|
||||||
for (final Player p : tgtPlayers) {
|
|
||||||
sb.append(p.toString()).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode.equals("RevealYouChoose")) {
|
if (mode.equals("RevealYouChoose")) {
|
||||||
sb.append("reveals their hand.").append(" You choose (");
|
sb.append("reveals their hand.").append(" You choose (");
|
||||||
@@ -105,8 +105,6 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
final String mode = sa.getParam("Mode");
|
final String mode = sa.getParam("Mode");
|
||||||
//final boolean anyNumber = sa.hasParam("AnyNumber");
|
//final boolean anyNumber = sa.hasParam("AnyNumber");
|
||||||
|
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
|
|
||||||
final List<Card> discarded = new ArrayList<Card>();
|
final List<Card> discarded = new ArrayList<Card>();
|
||||||
final List<Player> targets = getTargetPlayers(sa),
|
final List<Player> targets = getTargetPlayers(sa),
|
||||||
discarders;
|
discarders;
|
||||||
@@ -115,7 +113,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
// In this case the target need not be the discarding player
|
// In this case the target need not be the discarding player
|
||||||
discarders = getDefinedPlayersOrTargeted(sa);
|
discarders = getDefinedPlayersOrTargeted(sa);
|
||||||
firstTarget = Iterables.getFirst(targets, null);
|
firstTarget = Iterables.getFirst(targets, null);
|
||||||
if (tgt != null && !firstTarget.canBeTargetedBy(sa)) {
|
if (sa.usesTargeting() && !firstTarget.canBeTargetedBy(sa)) {
|
||||||
firstTarget = null;
|
firstTarget = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -123,8 +121,9 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final CardZoneTable table = new CardZoneTable();
|
||||||
for (final Player p : discarders) {
|
for (final Player p : discarders) {
|
||||||
if ((mode.equals("RevealTgtChoose") && firstTarget != null) || tgt == null || p.canBeTargetedBy(sa)) {
|
if ((mode.equals("RevealTgtChoose") && firstTarget != null) || !sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
if (sa.hasParam("RememberDiscarder")) {
|
if (sa.hasParam("RememberDiscarder")) {
|
||||||
source.addRemembered(p);
|
source.addRemembered(p);
|
||||||
}
|
}
|
||||||
@@ -140,7 +139,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final Card c : toDiscard) {
|
for (final Card c : toDiscard) {
|
||||||
boolean hasDiscarded = p.discard(c, sa) != null;
|
boolean hasDiscarded = p.discard(c, sa, table) != null;
|
||||||
if (hasDiscarded) {
|
if (hasDiscarded) {
|
||||||
discarded.add(c);
|
discarded.add(c);
|
||||||
}
|
}
|
||||||
@@ -164,7 +163,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(Card c : toDiscard) { // without copying will get concurrent modification exception
|
for(Card c : toDiscard) { // without copying will get concurrent modification exception
|
||||||
boolean hasDiscarded = p.discard(c, sa) != null;
|
boolean hasDiscarded = p.discard(c, sa, table) != null;
|
||||||
if( hasDiscarded && shouldRemember )
|
if( hasDiscarded && shouldRemember )
|
||||||
source.addRemembered(c);
|
source.addRemembered(c);
|
||||||
}
|
}
|
||||||
@@ -178,7 +177,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final Card c : dPHand) {
|
for (final Card c : dPHand) {
|
||||||
p.discard(c, sa);
|
p.discard(c, sa, table);
|
||||||
discarded.add(c);
|
discarded.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +215,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Card c : toDiscardView) {
|
for (Card c : toDiscardView) {
|
||||||
if (p.discard(c, sa) != null) {
|
if (p.discard(c, sa, table) != null) {
|
||||||
discarded.add(c);
|
discarded.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +232,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Card c : toDiscard) {
|
for (Card c : toDiscard) {
|
||||||
c.getController().discard(c, sa);
|
c.getController().discard(c, sa, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,7 +259,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
// Reveal cards that will be discarded?
|
// Reveal cards that will be discarded?
|
||||||
for (final Card c : dPChHand) {
|
for (final Card c : dPChHand) {
|
||||||
p.discard(c, sa);
|
p.discard(c, sa, table);
|
||||||
discarded.add(c);
|
discarded.add(c);
|
||||||
}
|
}
|
||||||
} else if (mode.equals("RevealYouChoose") || mode.equals("RevealTgtChoose") || mode.equals("TgtChoose")) {
|
} else if (mode.equals("RevealYouChoose") || mode.equals("RevealTgtChoose") || mode.equals("TgtChoose")) {
|
||||||
@@ -304,7 +303,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
for (Card card : toBeDiscarded) {
|
for (Card card : toBeDiscarded) {
|
||||||
if (card == null) { continue; }
|
if (card == null) { continue; }
|
||||||
p.discard(card, sa);
|
p.discard(card, sa, table);
|
||||||
discarded.add(card);
|
discarded.add(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,5 +316,8 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
source.addRemembered(c);
|
source.addRemembered(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run trigger if something got milled
|
||||||
|
table.triggerChangesZoneAll(source.getGame());
|
||||||
} // discardResolve()
|
} // discardResolve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import forge.card.CardStateName;
|
import forge.card.CardStateName;
|
||||||
|
import forge.game.Game;
|
||||||
import forge.game.GameLogEntryType;
|
import forge.game.GameLogEntryType;
|
||||||
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.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.TextUtil;
|
|
||||||
|
|
||||||
import java.util.List;
|
import forge.util.Lang;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
public class MillEffect extends SpellAbilityEffect {
|
public class MillEffect extends SpellAbilityEffect {
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
|
final Game game = source.getGame();
|
||||||
final int numCards = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa);
|
final int numCards = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa);
|
||||||
final boolean bottom = sa.hasParam("FromBottom");
|
final boolean bottom = sa.hasParam("FromBottom");
|
||||||
final boolean facedown = sa.hasParam("ExileFaceDown");
|
final boolean facedown = sa.hasParam("ExileFaceDown");
|
||||||
@@ -28,27 +30,27 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
source.clearRemembered();
|
source.clearRemembered();
|
||||||
}
|
}
|
||||||
|
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
|
|
||||||
ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
|
ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
|
||||||
if (destination == null) {
|
if (destination == null) {
|
||||||
destination = ZoneType.Graveyard;
|
destination = ZoneType.Graveyard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final CardZoneTable table = new CardZoneTable();
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
if (sa.hasParam("Optional")) {
|
if (sa.hasParam("Optional")) {
|
||||||
final String prompt = TextUtil.concatWithSpace("Do you want to put card(s) from library to", TextUtil.addSuffix(destination.toString(),"?"));
|
final String prompt = TextUtil.concatWithSpace("Do you want to put card(s) from library to", TextUtil.addSuffix(destination.toString(),"?"));
|
||||||
if (!p.getController().confirmAction(sa, null, prompt)) {
|
if (!p.getController().confirmAction(sa, null, prompt)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final CardCollectionView milled = p.mill(numCards, destination, bottom);
|
final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table);
|
||||||
// Reveal the milled cards, so players don't have to manually inspect the
|
// Reveal the milled cards, so players don't have to manually inspect the
|
||||||
// graveyard to figure out which ones were milled.
|
// graveyard to figure out which ones were milled.
|
||||||
if (!facedown && reveal) { // do not reveal when exiling face down
|
if (!facedown && reveal) { // do not reveal when exiling face down
|
||||||
if (showRevealDialog) {
|
if (showRevealDialog) {
|
||||||
p.getGame().getAction().reveal(milled, p, false);
|
game.getAction().reveal(milled, p, false);
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(p).append(" milled ").append(milled).append(" to ").append(destination);
|
sb.append(p).append(" milled ").append(milled).append(" to ").append(destination);
|
||||||
@@ -78,6 +80,9 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run trigger if something got milled
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,10 +90,7 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final int numCards = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa);
|
final int numCards = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa);
|
||||||
|
|
||||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
sb.append(Lang.joinHomogenous(getTargetPlayers(sa))).append(" ");
|
||||||
for (final Player p : tgtPlayers) {
|
|
||||||
sb.append(p.toString()).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
final ZoneType dest = ZoneType.smartValueOf(sa.getParam("Destination"));
|
final ZoneType dest = ZoneType.smartValueOf(sa.getParam("Destination"));
|
||||||
if ((dest == null) || dest.equals(ZoneType.Graveyard)) {
|
if ((dest == null) || dest.equals(ZoneType.Graveyard)) {
|
||||||
|
|||||||
@@ -63,12 +63,14 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
|
|||||||
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
|
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
for (Card sac : list) {
|
for (Card sac : list) {
|
||||||
final Card lKICopy = CardUtil.getLKICopy(sac);
|
final Card lKICopy = CardUtil.getLKICopy(sac);
|
||||||
if (game.getAction().sacrifice(sac, sa) != null && remSacrificed) {
|
if (game.getAction().sacrifice(sac, sa, table) != null && remSacrificed) {
|
||||||
card.addRemembered(lKICopy);
|
card.addRemembered(lKICopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,14 +91,15 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
final boolean remSacrificed = sa.hasParam("RememberSacrificed");
|
final boolean remSacrificed = sa.hasParam("RememberSacrificed");
|
||||||
final String remSVar = sa.getParam("RememberSacrificedSVar");
|
final String remSVar = sa.getParam("RememberSacrificedSVar");
|
||||||
int countSacrificed = 0;
|
int countSacrificed = 0;
|
||||||
|
CardZoneTable table = new CardZoneTable();
|
||||||
|
|
||||||
if (valid.equals("Self") && game.getZoneOf(card) != null) {
|
if (valid.equals("Self") && game.getZoneOf(card) != null) {
|
||||||
if (game.getZoneOf(card).is(ZoneType.Battlefield)) {
|
if (game.getZoneOf(card).is(ZoneType.Battlefield)) {
|
||||||
if (game.getAction().sacrifice(card, sa) != null) {
|
if (game.getAction().sacrifice(card, sa, table) != null) {
|
||||||
countSacrificed++;
|
countSacrificed++;
|
||||||
if (remSacrificed) {
|
if (remSacrificed) {
|
||||||
card.addRemembered(card);
|
card.addRemembered(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,8 +136,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
for (Card sac : choosenToSacrifice) {
|
for (Card sac : choosenToSacrifice) {
|
||||||
final Card lKICopy = CardUtil.getLKICopy(sac);
|
final Card lKICopy = CardUtil.getLKICopy(sac);
|
||||||
boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa) != null;
|
boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, table) != null;
|
||||||
boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa);
|
boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, table);
|
||||||
// Run Devour Trigger
|
// Run Devour Trigger
|
||||||
if (devour) {
|
if (devour) {
|
||||||
card.addDevoured(lKICopy);
|
card.addDevoured(lKICopy);
|
||||||
@@ -168,6 +169,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
} while (root != null);
|
} while (root != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ public final class CardUtil {
|
|||||||
newCopy.setSetCode(in.getSetCode());
|
newCopy.setSetCode(in.getSetCode());
|
||||||
newCopy.setOwner(in.getOwner());
|
newCopy.setOwner(in.getOwner());
|
||||||
newCopy.setController(in.getController(), 0);
|
newCopy.setController(in.getController(), 0);
|
||||||
|
newCopy.setCommander(in.isCommander());
|
||||||
|
|
||||||
// needed to ensure that the LKI object has correct CMC info no matter what state the original card was in
|
// needed to ensure that the LKI object has correct CMC info no matter what state the original card was in
|
||||||
// (e.g. Scrap Trawler + transformed Harvest Hand)
|
// (e.g. Scrap Trawler + transformed Harvest Hand)
|
||||||
|
|||||||
48
forge-game/src/main/java/forge/game/card/CardZoneTable.java
Normal file
48
forge-game/src/main/java/forge/game/card/CardZoneTable.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package forge.game.card;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.ForwardingTable;
|
||||||
|
import com.google.common.collect.HashBasedTable;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Table;
|
||||||
|
|
||||||
|
import forge.game.Game;
|
||||||
|
import forge.game.trigger.TriggerType;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
|
public class CardZoneTable extends ForwardingTable<ZoneType, ZoneType, CardCollection> {
|
||||||
|
// TODO use EnumBasedTable if exist
|
||||||
|
private Table<ZoneType, ZoneType, CardCollection> dataMap = HashBasedTable.create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* special put logic, add Card to Card Collection
|
||||||
|
*/
|
||||||
|
public CardCollection put(ZoneType rowKey, ZoneType columnKey, Card value) {
|
||||||
|
CardCollection old;
|
||||||
|
if (contains(rowKey, columnKey)) {
|
||||||
|
old = get(rowKey, columnKey);
|
||||||
|
old.add(value);
|
||||||
|
} else {
|
||||||
|
old = new CardCollection(value);
|
||||||
|
dataMap.put(rowKey, columnKey, old);
|
||||||
|
}
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Table<ZoneType, ZoneType, CardCollection> delegate() {
|
||||||
|
return dataMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void triggerChangesZoneAll(final Game game) {
|
||||||
|
if (!isEmpty()) {
|
||||||
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
|
runParams.put("Cards", this);
|
||||||
|
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package forge.game.cost;
|
package forge.game.cost;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import forge.card.CardStateName;
|
import forge.card.CardStateName;
|
||||||
import forge.card.mana.ManaAtom;
|
import forge.card.mana.ManaAtom;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
@@ -19,14 +17,15 @@ import forge.game.spellability.Spell;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.trigger.TriggerType;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class CostAdjustment {
|
public class CostAdjustment {
|
||||||
|
|
||||||
public static Cost adjust(final Cost cost, final SpellAbility sa) {
|
public static Cost adjust(final Cost cost, final SpellAbility sa) {
|
||||||
@@ -214,7 +213,7 @@ public class CostAdjustment {
|
|||||||
if (sa.getHostCard().hasKeyword(Keyword.DELVE)) {
|
if (sa.getHostCard().hasKeyword(Keyword.DELVE)) {
|
||||||
sa.getHostCard().clearDelved();
|
sa.getHostCard().clearDelved();
|
||||||
|
|
||||||
final CardCollection delved = new CardCollection();
|
final CardZoneTable table = new CardZoneTable();
|
||||||
final Player pc = sa.getActivatingPlayer();
|
final Player pc = sa.getActivatingPlayer();
|
||||||
final CardCollection mutableGrave = new CardCollection(pc.getCardsIn(ZoneType.Graveyard));
|
final CardCollection mutableGrave = new CardCollection(pc.getCardsIn(ZoneType.Graveyard));
|
||||||
final CardCollectionView toExile = pc.getController().chooseCardsToDelve(cost.getUnpaidShards(ManaCostShard.GENERIC), mutableGrave);
|
final CardCollectionView toExile = pc.getController().chooseCardsToDelve(cost.getUnpaidShards(ManaCostShard.GENERIC), mutableGrave);
|
||||||
@@ -224,17 +223,11 @@ public class CostAdjustment {
|
|||||||
cardsToDelveOut.add(c);
|
cardsToDelveOut.add(c);
|
||||||
} else if (!test) {
|
} else if (!test) {
|
||||||
sa.getHostCard().addDelved(c);
|
sa.getHostCard().addDelved(c);
|
||||||
delved.add(game.getAction().exile(c, null, null));
|
final Card d = game.getAction().exile(c, null, null);
|
||||||
|
table.put(ZoneType.Graveyard, d.getZone().getZoneType(), d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!delved.isEmpty()) {
|
table.triggerChangesZoneAll(game);
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
|
||||||
triggerList.put(ZoneType.Graveyard, delved);
|
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", ZoneType.Exile);
|
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
|
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
|
||||||
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class CostDiscard extends CostPartWithList {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Card doPayment(SpellAbility ability, Card targetCard) {
|
protected Card doPayment(SpellAbility ability, Card targetCard) {
|
||||||
return targetCard.getController().discard(targetCard, ability);
|
return targetCard.getController().discard(targetCard, ability, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ 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.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.zone.Zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Class CostPartWithList.
|
* The Class CostPartWithList.
|
||||||
@@ -35,6 +37,8 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
/** The lists: one for LKI, one for the actual cards. */
|
/** The lists: one for LKI, one for the actual cards. */
|
||||||
private final CardCollection lkiList = new CardCollection();
|
private final CardCollection lkiList = new CardCollection();
|
||||||
protected final CardCollection cardList = new CardCollection();
|
protected final CardCollection cardList = new CardCollection();
|
||||||
|
|
||||||
|
protected final CardZoneTable table = new CardZoneTable();
|
||||||
// set is here because executePayment() adds card to list, while ai's decide payment does the same thing.
|
// set is here because executePayment() adds card to list, while ai's decide payment does the same thing.
|
||||||
// set allows to avoid duplication
|
// set allows to avoid duplication
|
||||||
|
|
||||||
@@ -52,6 +56,7 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
public final void resetLists() {
|
public final void resetLists() {
|
||||||
lkiList.clear();
|
lkiList.clear();
|
||||||
cardList.clear();
|
cardList.clear();
|
||||||
|
table.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,13 +102,21 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
|
|
||||||
public final boolean executePayment(SpellAbility ability, Card targetCard) {
|
public final boolean executePayment(SpellAbility ability, Card targetCard) {
|
||||||
lkiList.add(CardUtil.getLKICopy(targetCard));
|
lkiList.add(CardUtil.getLKICopy(targetCard));
|
||||||
|
final Zone origin = targetCard.getZone();
|
||||||
final Card newCard = doPayment(ability, targetCard);
|
final Card newCard = doPayment(ability, targetCard);
|
||||||
cardList.add(newCard);
|
|
||||||
|
|
||||||
// need to update the LKI info to ensure correct interaction with cards which may trigger on this
|
// need to update the LKI info to ensure correct interaction with cards which may trigger on this
|
||||||
// (e.g. Necroskitter + a creature dying from a -1/-1 counter on a cost payment).
|
// (e.g. Necroskitter + a creature dying from a -1/-1 counter on a cost payment).
|
||||||
targetCard.getGame().updateLastStateForCard(targetCard);
|
targetCard.getGame().updateLastStateForCard(targetCard);
|
||||||
|
|
||||||
|
if (newCard != null) {
|
||||||
|
final Zone newZone = newCard.getZone();
|
||||||
|
cardList.add(newCard);
|
||||||
|
|
||||||
|
if (!origin.equals(newZone)) {
|
||||||
|
table.put(origin.getZoneType(), newZone.getZoneType(), newCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +125,13 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
if (canPayListAtOnce()) { // This is used by reveal. Without it when opponent would reveal hand, you'll get N message boxes.
|
if (canPayListAtOnce()) { // This is used by reveal. Without it when opponent would reveal hand, you'll get N message boxes.
|
||||||
lkiList.addAll(targetCards);
|
lkiList.addAll(targetCards);
|
||||||
cardList.addAll(doListPayment(ability, targetCards));
|
cardList.addAll(doListPayment(ability, targetCards));
|
||||||
|
handleChangeZoneTrigger(ability);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (Card c: targetCards) {
|
for (Card c: targetCards) {
|
||||||
executePayment(ability, c);
|
executePayment(ability, c);
|
||||||
}
|
}
|
||||||
|
handleChangeZoneTrigger(ability);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,4 +160,15 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void handleChangeZoneTrigger(SpellAbility ability) {
|
||||||
|
if (table.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy table because the original get cleaned after the cost is done
|
||||||
|
final CardZoneTable copyTable = new CardZoneTable();
|
||||||
|
copyTable.putAll(table);
|
||||||
|
copyTable.triggerChangesZoneAll(ability.getHostCard().getGame());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ public class CostSacrifice extends CostPartWithList {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Card doPayment(SpellAbility ability, Card targetCard) {
|
protected Card doPayment(SpellAbility ability, Card targetCard) {
|
||||||
return targetCard.getGame().getAction().sacrifice(targetCard, ability);
|
// no table there, it is already handled by CostPartWithList
|
||||||
|
return targetCard.getGame().getAction().sacrifice(targetCard, ability, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import forge.game.card.CardCollectionView;
|
|||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
@@ -38,9 +39,11 @@ import forge.game.player.Player;
|
|||||||
import forge.game.player.PlayerController.BinaryChoiceType;
|
import forge.game.player.PlayerController.BinaryChoiceType;
|
||||||
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.LandAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
|
import forge.game.zone.Zone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.CollectionSuppliers;
|
import forge.util.CollectionSuppliers;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
@@ -359,9 +362,11 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max;
|
int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max;
|
||||||
|
|
||||||
if (numDiscard > 0) {
|
if (numDiscard > 0) {
|
||||||
|
final CardZoneTable table = new CardZoneTable();
|
||||||
for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)){
|
for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)){
|
||||||
playerTurn.discard(c, null);
|
playerTurn.discard(c, null, table);
|
||||||
}
|
}
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule 514.2
|
// Rule 514.2
|
||||||
@@ -983,7 +988,23 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
pFirstPriority = pPlayerPriority; // all opponents have to pass before stack is allowed to resolve
|
pFirstPriority = pPlayerPriority; // all opponents have to pass before stack is allowed to resolve
|
||||||
for (SpellAbility sa : chosenSa) {
|
for (SpellAbility sa : chosenSa) {
|
||||||
|
Card saHost = sa.getHostCard();
|
||||||
|
final Zone originZone = saHost.getZone();
|
||||||
|
|
||||||
|
// TODO it has no return value if successful
|
||||||
pPlayerPriority.getController().playChosenSpellAbility(sa);
|
pPlayerPriority.getController().playChosenSpellAbility(sa);
|
||||||
|
|
||||||
|
saHost = game.getCardState(saHost);
|
||||||
|
final Zone currentZone = saHost.getZone();
|
||||||
|
|
||||||
|
// Need to check if Zone did change
|
||||||
|
if (currentZone != null && originZone != null && !currentZone.equals(originZone) && (sa.isSpell() || sa instanceof LandAbility)) {
|
||||||
|
// currently there can be only one Spell put on the Stack at once, or Land Abilities be played
|
||||||
|
final CardZoneTable triggerList = new CardZoneTable();
|
||||||
|
triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost);
|
||||||
|
triggerList.triggerChangesZoneAll(game);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
loopCount++;
|
loopCount++;
|
||||||
} while (loopCount < 999 || !pPlayerPriority.getController().isAI());
|
} while (loopCount < 999 || !pPlayerPriority.getController().isAI());
|
||||||
|
|||||||
@@ -1581,12 +1581,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return numDrawnThisDrawStep;
|
return numDrawnThisDrawStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Card discard(final Card c, final SpellAbility sa) {
|
public final Card discard(final Card c, final SpellAbility sa, CardZoneTable table) {
|
||||||
// TODO: This line should be moved inside CostPayment somehow
|
// TODO: This line should be moved inside CostPayment somehow
|
||||||
/*if (sa != null) {
|
/*if (sa != null) {
|
||||||
sa.addCostToHashList(c, "Discarded");
|
sa.addCostToHashList(c, "Discarded");
|
||||||
}*/
|
}*/
|
||||||
final Card source = sa != null ? sa.getHostCard() : null;
|
final Card source = sa != null ? sa.getHostCard() : null;
|
||||||
|
final ZoneType origin = c.getZone().getZoneType();
|
||||||
|
|
||||||
boolean discardToTopOfLibrary = null != sa && sa.hasParam("DiscardToTopOfLibrary");
|
boolean discardToTopOfLibrary = null != sa && sa.hasParam("DiscardToTopOfLibrary");
|
||||||
boolean discardMadness = sa != null && sa.hasParam("Madness");
|
boolean discardMadness = sa != null && sa.hasParam("Madness");
|
||||||
@@ -1622,6 +1623,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
newCard = game.getAction().moveToGraveyard(c, sa, null);
|
newCard = game.getAction().moveToGraveyard(c, sa, null);
|
||||||
// Play the Discard sound
|
// Play the Discard sound
|
||||||
}
|
}
|
||||||
|
if (table != null) {
|
||||||
|
table.put(origin, newCard.getZone().getZoneType(), newCard);
|
||||||
|
}
|
||||||
sb.append(".");
|
sb.append(".");
|
||||||
numDiscardedThisTurn++;
|
numDiscardedThisTurn++;
|
||||||
// Run triggers
|
// Run triggers
|
||||||
@@ -1660,18 +1664,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
numCardsInHandStartedThisTurnWith = num;
|
numCardsInHandStartedThisTurnWith = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final CardCollectionView mill(final int n) {
|
public final CardCollectionView mill(final int n, final ZoneType destination,
|
||||||
return mill(n, ZoneType.Graveyard, false);
|
final boolean bottom, SpellAbility sa, CardZoneTable table) {
|
||||||
}
|
|
||||||
public final CardCollectionView mill(final int n, final ZoneType zone,
|
|
||||||
final boolean bottom) {
|
|
||||||
final CardCollectionView lib = getCardsIn(ZoneType.Library);
|
final CardCollectionView lib = getCardsIn(ZoneType.Library);
|
||||||
final CardCollection milled = new CardCollection();
|
final CardCollection milled = new CardCollection();
|
||||||
|
|
||||||
final int max = Math.min(n, lib.size());
|
final int max = Math.min(n, lib.size());
|
||||||
|
|
||||||
final ZoneType destination = getZone(zone).getZoneType();
|
|
||||||
|
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
if (bottom) {
|
if (bottom) {
|
||||||
milled.add(lib.get(lib.size() - i - 1));
|
milled.add(lib.get(lib.size() - i - 1));
|
||||||
@@ -1682,12 +1681,15 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CardCollectionView milledView = milled;
|
CardCollectionView milledView = milled;
|
||||||
|
|
||||||
if (destination == ZoneType.Graveyard && milled.size() > 1) {
|
if (destination == ZoneType.Graveyard && milled.size() > 1) {
|
||||||
milledView = GameActionUtil.orderCardsByTheirOwners(game, milled, ZoneType.Graveyard);
|
milledView = GameActionUtil.orderCardsByTheirOwners(game, milled, ZoneType.Graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Card m : milledView) {
|
for (Card m : milledView) {
|
||||||
game.getAction().moveTo(destination, m, null, null);
|
final ZoneType origin = m.getZone().getZoneType();
|
||||||
|
final Card d = game.getAction().moveTo(destination, m, sa, null);
|
||||||
|
table.put(origin, d.getZone().getZoneType(), d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return milled;
|
return milled;
|
||||||
|
|||||||
@@ -15,44 +15,10 @@ public class TriggerChangesZoneAll extends Trigger {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean performTest(Map<String, Object> runParams2) {
|
public boolean performTest(Map<String, Object> runParams2) {
|
||||||
@SuppressWarnings("unchecked")
|
final CardZoneTable table = (CardZoneTable) runParams2.get("Cards");
|
||||||
final Map<ZoneType, CardCollection> moved = (Map<ZoneType, CardCollection>) runParams2.get("Cards");
|
|
||||||
|
|
||||||
if (hasParam("Destination")) {
|
if (filterCards(table).isEmpty()) {
|
||||||
if (!getParam("Destination").equals("Any")) {
|
return false;
|
||||||
if (!runParams2.get("Destination").equals(ZoneType.valueOf(getParam("Destination")))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final CardCollection allCards = new CardCollection();
|
|
||||||
|
|
||||||
if (hasParam("Origin")) {
|
|
||||||
if (!getParam("Origin").equals("Any")) {
|
|
||||||
if (getParam("Origin") == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final List<ZoneType> origin = ZoneType.listValueOf((String)getParam("Origin"));
|
|
||||||
for (ZoneType z : origin) {
|
|
||||||
if (moved.containsKey(z)) {
|
|
||||||
allCards.addAll(moved.get(z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (CardCollection c : moved.values()) {
|
|
||||||
allCards.addAll(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasParam("ValidCards")) {
|
|
||||||
|
|
||||||
int count = CardLists.getValidCardCount(allCards, getParam("ValidCards").split(","),this.getHostCard().getController(),
|
|
||||||
this.getHostCard());
|
|
||||||
if (count == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -60,30 +26,9 @@ public class TriggerChangesZoneAll extends Trigger {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTriggeringObjects(SpellAbility sa) {
|
public void setTriggeringObjects(SpellAbility sa) {
|
||||||
@SuppressWarnings("unchecked")
|
final CardZoneTable table = (CardZoneTable) getRunParams().get("Cards");
|
||||||
final Map<ZoneType, CardCollection> moved = (Map<ZoneType, CardCollection>) getRunParams().get("Cards");
|
|
||||||
|
|
||||||
CardCollection allCards = new CardCollection();
|
CardCollection allCards = this.filterCards(table);
|
||||||
|
|
||||||
if (hasParam("Origin")) {
|
|
||||||
if (!getParam("Origin").equals("Any") && getParam("Origin") != null) {
|
|
||||||
final List<ZoneType> origin = ZoneType.listValueOf((String)getParam("Origin"));
|
|
||||||
for (ZoneType z : origin) {
|
|
||||||
if (moved.containsKey(z)) {
|
|
||||||
allCards.addAll(moved.get(z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (CardCollection c : moved.values()) {
|
|
||||||
allCards.addAll(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasParam("ValidCards")) {
|
|
||||||
allCards = CardLists.getValidCards(allCards, getParam("ValidCards").split(","),this.getHostCard().getController(),
|
|
||||||
this.getHostCard(), sa);
|
|
||||||
}
|
|
||||||
|
|
||||||
sa.setTriggeringObject("Cards", allCards);
|
sa.setTriggeringObject("Cards", allCards);
|
||||||
sa.setTriggeringObject("Amount", allCards.size());
|
sa.setTriggeringObject("Amount", allCards.size());
|
||||||
@@ -95,4 +40,50 @@ public class TriggerChangesZoneAll extends Trigger {
|
|||||||
sb.append("Amount: ").append(sa.getTriggeringObject("Amount"));
|
sb.append("Amount: ").append(sa.getTriggeringObject("Amount"));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CardCollection filterCards(CardZoneTable table) {
|
||||||
|
CardCollection allCards = new CardCollection();
|
||||||
|
ZoneType destination = null;
|
||||||
|
|
||||||
|
if (hasParam("Destination")) {
|
||||||
|
if (!getParam("Destination").equals("Any")) {
|
||||||
|
destination = ZoneType.valueOf(getParam("Destination"));
|
||||||
|
if (!table.containsColumn(destination)) {
|
||||||
|
return allCards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasParam("Origin") && !getParam("Origin").equals("Any")) {
|
||||||
|
if (getParam("Origin") == null) {
|
||||||
|
return allCards;
|
||||||
|
}
|
||||||
|
final List<ZoneType> origin = ZoneType.listValueOf(getParam("Origin"));
|
||||||
|
for (ZoneType z : origin) {
|
||||||
|
if (table.containsRow(z)) {
|
||||||
|
if (destination != null) {
|
||||||
|
allCards.addAll(table.row(z).get(destination));
|
||||||
|
} else {
|
||||||
|
for (CardCollection c : table.row(z).values()) {
|
||||||
|
allCards.addAll(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (destination != null) {
|
||||||
|
for (CardCollection c : table.column(destination).values()) {
|
||||||
|
allCards.addAll(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (CardCollection c : table.values()) {
|
||||||
|
allCards.addAll(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasParam("ValidCards")) {
|
||||||
|
allCards = CardLists.getValidCards(allCards, getParam("ValidCards").split(","),
|
||||||
|
getHostCard().getController(), getHostCard(), null);
|
||||||
|
}
|
||||||
|
return allCards;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Myth Unbound
|
|||||||
ManaCost:2 G
|
ManaCost:2 G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
S:Mode$ ReduceCost | ValidCard$ Card.IsCommander+YouOwn | Type$ Spell | Amount$ AffectedX | Description$ Your commander costs {1} less to cast for each time it's been cast from the command zone this game.
|
S:Mode$ ReduceCost | ValidCard$ Card.IsCommander+YouOwn | Type$ Spell | Amount$ AffectedX | Description$ Your commander costs {1} less to cast for each time it's been cast from the command zone this game.
|
||||||
T:Mode$ ChangesZoneAll | ValidCard$ Card.IsCommander+YouOwn | Origin$ Any | Destination$ Command | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever your commander is put into the command zone from anywhere, draw a card.
|
T:Mode$ ChangesZone | ValidCard$ Card.IsCommander+YouOwn | Origin$ Any | Destination$ Command | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever your commander is put into the command zone from anywhere, draw a card.
|
||||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
||||||
SVar:AffectedX:Count$CommanderCastFromCommandZone
|
SVar:AffectedX:Count$CommanderCastFromCommandZone
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ Types:Legendary Creature Naga Shaman
|
|||||||
PT:3/3
|
PT:3/3
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, put the top three cards of your library into your graveyard.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, put the top three cards of your library into your graveyard.
|
||||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMill | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, put the top three cards of your library into your graveyard.
|
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMill | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, put the top three cards of your library into your graveyard.
|
||||||
T:Mode$ ChangesZone | ValidCard$ Creature.YouCtrl | OncePerEffect$ True | Origin$ Library | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever one or more creature cards are put into your graveyard from your library, create a 2/2 black Zombie creature token.
|
T:Mode$ ChangesZoneAll | ValidCards$ Creature.YouOwn | Origin$ Library | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever one or more creature cards are put into your graveyard from your library, create a 2/2 black Zombie creature token.
|
||||||
SVar:TrigMill:DB$Mill | NumCards$ 3 | Defined$ You
|
SVar:TrigMill:DB$Mill | NumCards$ 3 | Defined$ You
|
||||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Zombie | TokenTypes$ Creature,Zombie | TokenOwner$ You | TokenColors$ Black | TokenPower$ 2 | TokenToughness$ 2 | TokenImage$ b 2 2 zombie KTK |
|
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ b_2_2_zombie | TokenOwner$ You
|
||||||
|
DeckHas:Ability$Token & Ability$Graveyard
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/sidisi_brood_tyrant.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/sidisi_brood_tyrant.jpg
|
||||||
Oracle:Whenever Sidisi, Brood Tyrant enters the battlefield or attacks, put the top three cards of your library into your graveyard.\nWhenever one or more creature cards are put into your graveyard from your library, create a 2/2 black Zombie creature token.
|
Oracle:Whenever Sidisi, Brood Tyrant enters the battlefield or attacks, put the top three cards of your library into your graveyard.\nWhenever one or more creature cards are put into your graveyard from your library, create a 2/2 black Zombie creature token.
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ PT:6/6
|
|||||||
K:Deathtouch
|
K:Deathtouch
|
||||||
K:UpkeepCost:Sac<1/Land>
|
K:UpkeepCost:Sac<1/Land>
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ AdjustLandPlays:1 | Description$ You may play an additional land on each of your turns.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ AdjustLandPlays:1 | Description$ You may play an additional land on each of your turns.
|
||||||
T:Mode$ ChangesZone | ValidCard$ Land.YouOwn | OncePerEffect$ True | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, draw a card.
|
T:Mode$ ChangesZoneAll | ValidCards$ Land.YouOwn | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, draw a card.
|
||||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
||||||
|
DeckHas:Ability$Graveyard
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/the_gitrog_monster.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/the_gitrog_monster.jpg
|
||||||
Oracle:Deathtouch\nAt the beginning of your upkeep, sacrifice The Gitrog Monster unless you sacrifice a land.\nYou may play an additional land on each of your turns.\nWhenever one or more land cards are put into your graveyard from anywhere, draw a card.
|
Oracle:Deathtouch\nAt the beginning of your upkeep, sacrifice The Gitrog Monster unless you sacrifice a land.\nYou may play an additional land on each of your turns.\nWhenever one or more land cards are put into your graveyard from anywhere, draw a card.
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ Name:Turntimber Sower
|
|||||||
ManaCost:2 G
|
ManaCost:2 G
|
||||||
Types:Creature Elf Druid
|
Types:Creature Elf Druid
|
||||||
PT:3/3
|
PT:3/3
|
||||||
T:Mode$ ChangesZone | ValidCard$ Land.YouOwn | Origin$ Any | Destination$ Graveyard | Execute$ TrigToken | OncePerEffect$ True | TriggerZones$ Battlefield | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.
|
T:Mode$ ChangesZoneAll | ValidCards$ Land.YouOwn | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.
|
||||||
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenName$ Plant | TokenTypes$ Creature,Plant | TokenOwner$ You | TokenColors$ Green | TokenPower$ 0 | TokenToughness$ 1 | TokenImage$ g 0 1 plant c18
|
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_0_1_plant | TokenOwner$ You
|
||||||
AI:RemoveDeck:Random
|
|
||||||
A:AB$ ChangeZone | Cost$ G Sac<3/Creature> | TgtPrompt$ Choose target land card in your graveyard | ValidTgts$ Land.YouCtrl | Origin$ Graveyard | Destination$ Hand | SpellDescription$ Return target land card from your graveyard to your hand.
|
A:AB$ ChangeZone | Cost$ G Sac<3/Creature> | TgtPrompt$ Choose target land card in your graveyard | ValidTgts$ Land.YouCtrl | Origin$ Graveyard | Destination$ Hand | SpellDescription$ Return target land card from your graveyard to your hand.
|
||||||
|
DeckHas:Ability$Token & Ability$Graveyard
|
||||||
|
AI:RemoveDeck:Random
|
||||||
Oracle:Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.\n{G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.
|
Oracle:Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.\n{G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.
|
||||||
|
|||||||
6
forge-gui/res/tokenscripts/b_2_2_zombie.txt
Normal file
6
forge-gui/res/tokenscripts/b_2_2_zombie.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Name:Zombie
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Creature Zombie
|
||||||
|
Colors:black
|
||||||
|
PT:2/2
|
||||||
|
Oracle:
|
||||||
6
forge-gui/res/tokenscripts/g_0_1_plant.txt
Normal file
6
forge-gui/res/tokenscripts/g_0_1_plant.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Name:Plant
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Creature Plant
|
||||||
|
Colors:green
|
||||||
|
PT:0/1
|
||||||
|
Oracle:
|
||||||
@@ -2,7 +2,6 @@ package forge.player;
|
|||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import forge.FThreads;
|
import forge.FThreads;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
@@ -34,7 +33,6 @@ import forge.util.gui.SGuiChoose;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -310,7 +308,7 @@ public class HumanPlay {
|
|||||||
|
|
||||||
final HumanCostDecision hcd = new HumanCostDecision(controller, p, sourceAbility, source);
|
final HumanCostDecision hcd = new HumanCostDecision(controller, p, sourceAbility, source);
|
||||||
boolean mandatory = cost.isMandatory();
|
boolean mandatory = cost.isMandatory();
|
||||||
|
|
||||||
//the following costs do not need inputs
|
//the following costs do not need inputs
|
||||||
for (CostPart part : parts) {
|
for (CostPart part : parts) {
|
||||||
boolean mayRemovePart = true;
|
boolean mayRemovePart = true;
|
||||||
@@ -355,7 +353,7 @@ public class HumanPlay {
|
|||||||
}
|
}
|
||||||
else if (part instanceof CostGainLife) {
|
else if (part instanceof CostGainLife) {
|
||||||
PaymentDecision pd = part.accept(hcd);
|
PaymentDecision pd = part.accept(hcd);
|
||||||
|
|
||||||
if (pd == null)
|
if (pd == null)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
@@ -369,7 +367,7 @@ public class HumanPlay {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PaymentDecision pd = part.accept(hcd);
|
PaymentDecision pd = part.accept(hcd);
|
||||||
|
|
||||||
if (pd == null)
|
if (pd == null)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
@@ -520,22 +518,19 @@ public class HumanPlay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (part instanceof CostExile) {
|
else if (part instanceof CostExile) {
|
||||||
final CardCollection exiledList = new CardCollection();
|
CostExile costExile = (CostExile) part;
|
||||||
|
|
||||||
ZoneType from = ZoneType.Graveyard;
|
ZoneType from = ZoneType.Graveyard;
|
||||||
if ("All".equals(part.getType())) {
|
if ("All".equals(part.getType())) {
|
||||||
if (!p.getController().confirmPayment(part, "Do you want to exile all cards in your graveyard?", sourceAbility)) {
|
if (!p.getController().confirmPayment(part, "Do you want to exile all cards in your graveyard?", sourceAbility)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CardCollection cards = new CardCollection(p.getCardsIn(ZoneType.Graveyard));
|
costExile.executePayment(sourceAbility, p.getCardsIn(ZoneType.Graveyard));
|
||||||
for (final Card card : cards) {
|
|
||||||
exiledList.add(p.getGame().getAction().exile(card, null));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CostExile costExile = (CostExile) part;
|
|
||||||
from = costExile.getFrom();
|
from = costExile.getFrom();
|
||||||
List<Card> list = CardLists.getValidCards(p.getCardsIn(from), part.getType().split(";"), p, source, sourceAbility);
|
CardCollection list = CardLists.getValidCards(p.getCardsIn(from), part.getType().split(";"), p, source, sourceAbility);
|
||||||
final int nNeeded = getAmountFromPart(costPart, source, sourceAbility);
|
final int nNeeded = getAmountFromPart(costPart, source, sourceAbility);
|
||||||
if (list.size() < nNeeded) {
|
if (list.size() < nNeeded) {
|
||||||
return false;
|
return false;
|
||||||
@@ -546,11 +541,10 @@ public class HumanPlay {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list = list.subList(0, nNeeded);
|
list = list.subList(0, nNeeded);
|
||||||
for (Card c : list) {
|
costExile.executePayment(sourceAbility, list);
|
||||||
exiledList.add(p.getGame().getAction().exile(c, null));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// replace this with input
|
// replace this with input
|
||||||
|
CardCollection newList = new CardCollection();
|
||||||
for (int i = 0; i < nNeeded; i++) {
|
for (int i = 0; i < nNeeded; i++) {
|
||||||
final Card c = p.getGame().getCard(SGuiChoose.oneOrNone("Exile from " + from, CardView.getCollection(list)));
|
final Card c = p.getGame().getCard(SGuiChoose.oneOrNone("Exile from " + from, CardView.getCollection(list)));
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
@@ -558,19 +552,11 @@ public class HumanPlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
list.remove(c);
|
list.remove(c);
|
||||||
exiledList.add(p.getGame().getAction().exile(c, null));
|
newList.add(c);
|
||||||
}
|
}
|
||||||
|
costExile.executePayment(sourceAbility, newList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exiledList.isEmpty()) {
|
|
||||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
|
||||||
triggerList.put(from, exiledList);
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", ZoneType.Exile);
|
|
||||||
p.getGame().getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (part instanceof CostPutCardToLib) {
|
else if (part instanceof CostPutCardToLib) {
|
||||||
int amount = Integer.parseInt(((CostPutCardToLib) part).getAmount());
|
int amount = Integer.parseInt(((CostPutCardToLib) part).getAmount());
|
||||||
@@ -651,10 +637,7 @@ public class HumanPlay {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CardCollection cards = new CardCollection(p.getCardsIn(ZoneType.Hand));
|
((CostDiscard)part).executePayment(sourceAbility, p.getCardsIn(ZoneType.Hand));
|
||||||
for (final Card card : cards) {
|
|
||||||
p.discard(card, sourceAbility);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType(), p, source);
|
CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType(), p, source);
|
||||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||||
@@ -722,7 +705,7 @@ public class HumanPlay {
|
|||||||
String promptCurrent = current == null ? "" : "Current Card: " + current;
|
String promptCurrent = current == null ? "" : "Current Card: " + current;
|
||||||
prompt = source + "\n" + promptCurrent;
|
prompt = source + "\n" + promptCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceAbility.clearManaPaid();
|
sourceAbility.clearManaPaid();
|
||||||
boolean paid = p.getController().payManaCost(cost.getCostMana(), sourceAbility, prompt, false);
|
boolean paid = p.getController().payManaCost(cost.getCostMana(), sourceAbility, prompt, false);
|
||||||
if (!paid) {
|
if (!paid) {
|
||||||
@@ -743,42 +726,33 @@ public class HumanPlay {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Card c : inp.getSelected()) {
|
cpl.executePayment(sourceAbility, new CardCollection(inp.getSelected()));
|
||||||
cpl.executePayment(sourceAbility, c);
|
|
||||||
}
|
|
||||||
if (sourceAbility != null) {
|
if (sourceAbility != null) {
|
||||||
cpl.reportPaidCardsTo(sourceAbility);
|
cpl.reportPaidCardsTo(sourceAbility);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean handleOfferingConvokeAndDelve(final SpellAbility ability, CardCollection cardsToDelve, boolean manaInputCancelled) {
|
private static boolean handleOfferingConvokeAndDelve(final SpellAbility ability, CardCollection cardsToDelve, boolean manaInputCancelled) {
|
||||||
|
Card hostCard = ability.getHostCard();
|
||||||
|
final Game game = hostCard.getGame();
|
||||||
|
|
||||||
|
final CardZoneTable table = new CardZoneTable();
|
||||||
if (!manaInputCancelled && !cardsToDelve.isEmpty()) {
|
if (!manaInputCancelled && !cardsToDelve.isEmpty()) {
|
||||||
Card hostCard = ability.getHostCard();
|
|
||||||
final Game game = hostCard.getGame();
|
|
||||||
|
|
||||||
final CardCollection delved = new CardCollection();
|
|
||||||
final Map<ZoneType, CardCollection> triggerList = Maps.newEnumMap(ZoneType.class);
|
|
||||||
|
|
||||||
for (final Card c : cardsToDelve) {
|
for (final Card c : cardsToDelve) {
|
||||||
hostCard.addDelved(c);
|
hostCard.addDelved(c);
|
||||||
delved.add(game.getAction().exile(c, null));
|
final ZoneType o = c.getZone().getZoneType();
|
||||||
}
|
final Card d = game.getAction().exile(c, null);
|
||||||
|
table.put(o, d.getZone().getZoneType(), d);
|
||||||
if (!delved.isEmpty()) {
|
|
||||||
triggerList.put(ZoneType.Graveyard, delved);
|
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
|
||||||
runParams.put("Cards", triggerList);
|
|
||||||
runParams.put("Destination", ZoneType.Exile);
|
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {
|
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {
|
||||||
final Card offering = ability.getSacrificedAsOffering();
|
final Card offering = ability.getSacrificedAsOffering();
|
||||||
offering.setUsedToPay(false);
|
offering.setUsedToPay(false);
|
||||||
if (!manaInputCancelled) {
|
if (!manaInputCancelled) {
|
||||||
ability.getHostCard().getGame().getAction().sacrifice(offering, ability);
|
game.getAction().sacrifice(offering, ability, table);
|
||||||
}
|
}
|
||||||
ability.resetSacrificedAsOffering();
|
ability.resetSacrificedAsOffering();
|
||||||
}
|
}
|
||||||
@@ -786,7 +760,7 @@ public class HumanPlay {
|
|||||||
final Card emerge = ability.getSacrificedAsEmerge();
|
final Card emerge = ability.getSacrificedAsEmerge();
|
||||||
emerge.setUsedToPay(false);
|
emerge.setUsedToPay(false);
|
||||||
if (!manaInputCancelled) {
|
if (!manaInputCancelled) {
|
||||||
ability.getHostCard().getGame().getAction().sacrifice(emerge, ability);
|
game.getAction().sacrifice(emerge, ability, table);
|
||||||
}
|
}
|
||||||
ability.resetSacrificedAsEmerge();
|
ability.resetSacrificedAsEmerge();
|
||||||
}
|
}
|
||||||
@@ -799,9 +773,12 @@ public class HumanPlay {
|
|||||||
}
|
}
|
||||||
ability.clearTappedForConvoke();
|
ability.clearTappedForConvoke();
|
||||||
}
|
}
|
||||||
|
if (!table.isEmpty() && !manaInputCancelled) {
|
||||||
|
table.triggerChangesZoneAll(game);
|
||||||
|
}
|
||||||
return !manaInputCancelled;
|
return !manaInputCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean payManaCost(final PlayerControllerHuman controller, final ManaCost realCost, final CostPartMana mc, final SpellAbility ability, final Player activator, String prompt, ManaConversionMatrix matrix, boolean isActivatedSa) {
|
public static boolean payManaCost(final PlayerControllerHuman controller, final ManaCost realCost, final CostPartMana mc, final SpellAbility ability, final Player activator, String prompt, ManaConversionMatrix matrix, boolean isActivatedSa) {
|
||||||
final Card source = ability.getHostCard();
|
final Card source = ability.getHostCard();
|
||||||
ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction());
|
ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction());
|
||||||
@@ -887,7 +864,7 @@ public class HumanPlay {
|
|||||||
if (ability.getSacrificedAsOffering() != null) {
|
if (ability.getSacrificedAsOffering() != null) {
|
||||||
System.out.println("Finishing up Offering");
|
System.out.println("Finishing up Offering");
|
||||||
offering.setUsedToPay(false);
|
offering.setUsedToPay(false);
|
||||||
activator.getGame().getAction().sacrifice(offering, ability);
|
activator.getGame().getAction().sacrifice(offering, ability, null);
|
||||||
ability.resetSacrificedAsOffering();
|
ability.resetSacrificedAsOffering();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -898,7 +875,7 @@ public class HumanPlay {
|
|||||||
if (ability.getSacrificedAsEmerge() != null) {
|
if (ability.getSacrificedAsEmerge() != null) {
|
||||||
System.out.println("Finishing up Emerge");
|
System.out.println("Finishing up Emerge");
|
||||||
emerge.setUsedToPay(false);
|
emerge.setUsedToPay(false);
|
||||||
activator.getGame().getAction().sacrifice(emerge, ability);
|
activator.getGame().getAction().sacrifice(emerge, ability, null);
|
||||||
ability.resetSacrificedAsEmerge();
|
ability.resetSacrificedAsEmerge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user