(unpaidShards.keySet());
- if (pool != null) { //replace shards with generic mana if they can be paid with any color mana
+ // TODO Fix this. Should we really be changing Shards here?
+ if (false && pool != null) { //replace shards with generic mana if they can be paid with any color mana
for (int i = 0; i < shards.size(); i++) {
ManaCostShard shard = shards.get(i);
- if (shard != ManaCostShard.GENERIC && pool.getPossibleColorUses(shard.getColorMask()) == MagicColor.ALL_COLORS) {
+ if (shard != ManaCostShard.GENERIC && pool.getPossibleColorUses(shard.getColorMask()) == ManaAtom.ALL_MANA_TYPES) {
nGeneric += unpaidShards.get(shard).totalCount;
shards.remove(i);
i--;
diff --git a/forge-game/src/main/java/forge/game/mana/ManaPool.java b/forge-game/src/main/java/forge/game/mana/ManaPool.java
index 2d2de63d968..de59a57ef21 100644
--- a/forge-game/src/main/java/forge/game/mana/ManaPool.java
+++ b/forge-game/src/main/java/forge/game/mana/ManaPool.java
@@ -20,9 +20,7 @@ package forge.game.mana;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
-
import forge.GameCommand;
-import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaAtom;
import forge.card.mana.ManaCostShard;
@@ -37,14 +35,9 @@ import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
-
import org.apache.commons.lang3.StringUtils;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
/**
*
@@ -54,7 +47,7 @@ import java.util.List;
* @author Forge
* @version $Id$
*/
-public class ManaPool implements Iterable {
+public class ManaPool extends ManaConversionMatrix implements Iterable {
private final Player owner;
private final Multimap floatingMana = ArrayListMultimap.create();
@@ -355,37 +348,10 @@ public class ManaPool implements Iterable {
Player p = sa.getActivatingPlayer();
p.getGame().fireEvent(new GameEventZone(ZoneType.Battlefield, p, EventValueChangeType.ComplexUpdate, null));
}
-
- // Conversion matrix ORs byte values to make mana more payable
- // Restrictive matrix ANDs byte values to make mana less payable
- private final byte[] colorConversionMatrix = new byte[ManaAtom.MANATYPES.length];
- private final byte[] colorRestrictionMatrix = new byte[ManaAtom.MANATYPES.length];
- private static final byte[] identityMatrix = { ManaAtom.WHITE, ManaAtom.BLUE, ManaAtom.BLACK, ManaAtom.RED, ManaAtom.GREEN, ManaAtom.COLORLESS };
-
- public void adjustColorReplacement(byte originalColor, byte replacementColor, boolean additive) {
- // Fix the index without hardcodes
- int rowIdx = MagicColor.getIndexOfFirstColor(originalColor);
- rowIdx = rowIdx < 0 ? identityMatrix.length - 1 : rowIdx;
- if (additive) {
- colorConversionMatrix[rowIdx] |= replacementColor;
- }
- else {
- colorRestrictionMatrix[rowIdx] &= replacementColor;
- }
- }
-
- public void restoreColorReplacements() {
- for (int i = 0; i < colorConversionMatrix.length; i++) {
- colorConversionMatrix[i] = identityMatrix[i];
- }
- for (int i = 0; i < colorRestrictionMatrix.length; i++) {
- colorRestrictionMatrix[i] = ColorSet.ALL_COLORS.getColor();
- }
- }
public byte getPossibleColorUses(byte color) {
// Take the current conversion value, AND with restrictions to get mana usage
- int rowIdx = MagicColor.getIndexOfFirstColor(color);
+ int rowIdx = ManaAtom.getIndexOfFirstManaType(color);
int matrixIdx = rowIdx < 0 ? identityMatrix.length - 1 : rowIdx;
byte colorUse = colorConversionMatrix[matrixIdx];
@@ -394,14 +360,16 @@ public class ManaPool implements Iterable {
}
public boolean canPayForShardWithColor(ManaCostShard shard, byte color) {
+ // TODO Debug this for Paying Gonti,
byte line = getPossibleColorUses(color);
- for (int i = 0; i < MagicColor.NUMBER_OR_COLORS; i++) {
- byte outColor = MagicColor.WUBRG[i];
+
+ for(byte outColor : ManaAtom.MANATYPES) {
if ((line & outColor) != 0 && shard.canBePaidWithManaOfColor(outColor)) {
return true;
}
}
+ // TODO The following may not be needed anymore?
if (((color & (byte) ManaAtom.COLORLESS) != 0) && shard.canBePaidWithManaOfColor((byte) (byte)ManaAtom.COLORLESS)) {
return true;
}
diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
index 3fbde336028..ba10cde1a85 100644
--- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
+++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
@@ -372,6 +372,8 @@ public class PhaseHandler implements java.io.Serializable {
game.getEndOfCombat().executeUntil(); //Repeat here in case Time Stop et. al. ends combat early
game.getEndOfTurn().executeUntil();
+ game.getEndOfTurn().executeUntilEndOfPhase(playerTurn);
+ game.getEndOfTurn().registerUntilEndCommand(playerTurn);
for (Player player : game.getPlayers()) {
player.onCleanupPhase();
@@ -664,7 +666,7 @@ public class PhaseHandler implements java.io.Serializable {
combat.removeAbsentCombatants();
- combat.fireTriggersForUnblockedAttackers();
+ combat.fireTriggersForUnblockedAttackers(game);
final List declaredBlockers = combat.getAllBlockers();
if (!declaredBlockers.isEmpty()) {
diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java
index f3e15e1d872..e4e5bfe45ce 100644
--- a/forge-game/src/main/java/forge/game/player/Player.java
+++ b/forge-game/src/main/java/forge/game/player/Player.java
@@ -1751,6 +1751,9 @@ public class Player extends GameEntity implements Comparable {
return canPlayLand(land, false);
}
public final boolean canPlayLand(final Card land, final boolean ignoreZoneAndTiming) {
+ return canPlayLand(land, ignoreZoneAndTiming, null);
+ }
+ public final boolean canPlayLand(final Card land, final boolean ignoreZoneAndTiming, SpellAbility landSa) {
if (!ignoreZoneAndTiming && !canCastSorcery()) {
return false;
}
@@ -1766,7 +1769,7 @@ public class Player extends GameEntity implements Comparable {
}
if (land != null && !ignoreZoneAndTiming) {
- final boolean mayPlay = !land.mayPlay(this).isEmpty();
+ final boolean mayPlay = landSa == null ? !land.mayPlay(this).isEmpty() : landSa.getMayPlay() != null;
if (land.getOwner() != this && !mayPlay) {
return false;
}
@@ -2662,6 +2665,14 @@ public class Player extends GameEntity implements Comparable {
commanderCast.put(commander, getCommanderCast(commander) + 1);
}
+ public int getTotalCommanderCast() {
+ int result = 0;
+ for (Integer i : commanderCast.values()) {
+ result += i;
+ }
+ return result;
+ }
+
public boolean isPlayingExtraTurn() {
return isPlayingExtraTrun;
}
diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java
index adc6bd77754..f603e7656e4 100644
--- a/forge-game/src/main/java/forge/game/player/PlayerController.java
+++ b/forge-game/src/main/java/forge/game/player/PlayerController.java
@@ -20,6 +20,7 @@ import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.mana.Mana;
+import forge.game.mana.ManaConversionMatrix;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.*;
import forge.game.trigger.WrappedAbility;
@@ -220,9 +221,13 @@ public abstract class PlayerController {
public abstract void resetAtEndOfTurn(); // currently used by the AI to perform card memory cleanup
public final boolean payManaCost(CostPartMana costPartMana, SpellAbility sa, String prompt, boolean isActivatedAbility) {
- return payManaCost(costPartMana.getManaCostFor(sa), costPartMana, sa, prompt, isActivatedAbility);
+ return payManaCost(costPartMana, sa, prompt, null, isActivatedAbility);
}
- public abstract boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt, boolean isActivatedAbility);
+
+ public final boolean payManaCost(CostPartMana costPartMana, SpellAbility sa, String prompt, ManaConversionMatrix matrix, boolean isActivatedAbility) {
+ return payManaCost(costPartMana.getManaCostFor(sa), costPartMana, sa, prompt, matrix, isActivatedAbility);
+ }
+ public abstract boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt, ManaConversionMatrix matrix, boolean isActivatedAbility);
public abstract Map chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise);
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
index c47dd86d932..f08e0b660a7 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
@@ -181,7 +181,7 @@ public class ReplacementHandler {
final String effectAbString = host.getSVar(effectSVar);
// TODO: the source of replacement effect should be the source of the original effect
effectSA = AbilityFactory.getAbility(effectAbString, host);
- effectSA.setTrigger(true);
+ //effectSA.setTrigger(true);
SpellAbility tailend = effectSA;
do {
@@ -209,8 +209,9 @@ public class ReplacementHandler {
if (replacementEffect.isIntrinsic()) {
effectSA.setIntrinsic(true);
effectSA.changeText();
- effectSA.setReplacementAbility(true);
}
+ effectSA.setReplacementAbility(true);
+ effectSA.setReplacementEffect(replacementEffect);
}
// Decider gets to choose whether or not to apply the replacement.
@@ -309,13 +310,15 @@ public class ReplacementHandler {
game.forEachCardInGame(new Visitor() {
@Override
public boolean visit(Card c) {
- for (int i = 0; i < c.getReplacementEffects().size(); i++) {
- ReplacementEffect rep = c.getReplacementEffects().get(i);
+ List toRemove = Lists.newArrayList();
+ for (ReplacementEffect rep : c.getReplacementEffects()) {
if (rep.isTemporary()) {
- c.removeReplacementEffect(rep);
- i--;
+ toRemove.add(rep);
}
}
+ for (ReplacementEffect rep : toRemove) {
+ c.removeReplacementEffect(rep);
+ }
return true;
}
});
diff --git a/forge-game/src/main/java/forge/game/spellability/LandAbility.java b/forge-game/src/main/java/forge/game/spellability/LandAbility.java
index a524a7222a9..8b1ba1557ca 100644
--- a/forge-game/src/main/java/forge/game/spellability/LandAbility.java
+++ b/forge-game/src/main/java/forge/game/spellability/LandAbility.java
@@ -17,13 +17,10 @@
*/
package forge.game.spellability;
-import forge.game.Game;
import forge.game.card.Card;
import forge.game.cost.Cost;
import forge.game.player.Player;
import forge.game.staticability.StaticAbility;
-import forge.game.zone.Zone;
-import forge.game.zone.ZoneType;
public class LandAbility extends Ability {
@@ -33,57 +30,14 @@ public class LandAbility extends Ability {
setMayPlay(mayPlay);
}
public LandAbility(Card sourceCard) {
- this(sourceCard, sourceCard.getController(), (StaticAbility)null);
+ this(sourceCard, sourceCard.getController(), null);
}
@Override
public boolean canPlay() {
final Card land = this.getHostCard();
final Player p = this.getActivatingPlayer();
- final Game game = p.getGame();
- if (!p.canCastSorcery()) {
- return false;
- }
- // CantBeCast static abilities
- for (final Card ca : game.getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
- final Iterable staticAbilities = ca.getStaticAbilities();
- for (final StaticAbility stAb : staticAbilities) {
- if (stAb.applyAbility("CantPlayLand", land, this)) {
- return false;
- }
- }
- }
-
- if (land != null) {
- final boolean mayPlay = getMayPlay() != null;
- if (land.getOwner() != p && !mayPlay) {
- return false;
- }
-
- final Zone zone = game.getZoneOf(land);
- if (zone != null && (zone.is(ZoneType.Battlefield) || (!zone.is(ZoneType.Hand) && !mayPlay))) {
- return false;
- }
- }
-
- // **** Check for land play limit per turn ****
- // Dev Mode
- if (p.getController().canPlayUnlimitedLands() || p.hasKeyword("You may play any number of additional lands on each of your turns.")) {
- return true;
- }
-
- // check for adjusted max lands play per turn
- int adjMax = 1;
- for (String keyword : p.getKeywords()) {
- if (keyword.startsWith("AdjustLandPlays")) {
- final String[] k = keyword.split(":");
- adjMax += Integer.valueOf(k[1]);
- }
- }
- if (p.getLandsPlayedThisTurn() < adjMax) {
- return true;
- }
- return false;
+ return p.canPlayLand(land, false, this);
}
@Override
public void resolve() {
diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
index afa679d269d..3e866b91fb1 100644
--- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
+++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
@@ -38,7 +38,9 @@ import forge.game.cost.CostRemoveCounter;
import forge.game.keyword.Keyword;
import forge.game.mana.Mana;
import forge.game.player.Player;
+import forge.game.replacement.ReplacementEffect;
import forge.game.staticability.StaticAbility;
+import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.trigger.WrappedAbility;
import forge.util.Expressions;
@@ -87,8 +89,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private boolean basicSpell = true;
private boolean trigger = false;
+ private Trigger triggerObj = null;
private boolean optionalTrigger = false;
private boolean replacementAbility = false;
+ private ReplacementEffect replacementEffect = null;
private int sourceTrigger = -1;
private List