Merge branch 'counterGameCheck' into 'master'

Put Counter Effects check Game State

Closes #548

See merge request core-developers/forge!568
This commit is contained in:
Michael Kamensky
2018-05-20 17:14:43 +00:00
43 changed files with 118 additions and 79 deletions

View File

@@ -543,15 +543,19 @@ public class Game {
return found == null;
}
public Card getFound() {
return found == null ? old : found;
public Card getFound(final Card notFound) {
return found == null ? notFound : found;
}
}
public Card getCardState(final Card card) {
return getCardState(card, card);
}
public Card getCardState(final Card card, final Card notFound) {
CardStateVisitor visit = new CardStateVisitor(card);
this.forEachCardInGame(visit);
return visit.getFound();
return visit.getFound(notFound);
}
// Allows visiting cards in game without allocating a temporary list.

View File

@@ -95,8 +95,8 @@ public class CountersMoveEffect extends SpellAbilityEffect {
return;
}
Card cur = game.getCardState(dest);
if (cur.getTimestamp() != dest.getTimestamp()) {
Card cur = game.getCardState(dest, null);
if (cur == null || !cur.equalsWithTimestamp(dest)) {
// Test to see if the card we're trying to add is in the expected state
return;
}
@@ -185,8 +185,8 @@ public class CountersMoveEffect extends SpellAbilityEffect {
continue;
}
Card cur = game.getCardState(dest);
if (cur.getTimestamp() != dest.getTimestamp()) {
Card cur = game.getCardState(dest, null);
if (cur == null || !cur.equalsWithTimestamp(dest)) {
// Test to see if the card we're trying to add is in the expected state
continue;
}
@@ -238,8 +238,8 @@ public class CountersMoveEffect extends SpellAbilityEffect {
if (source.equals(dest)) {
continue;
}
Card cur = game.getCardState(dest);
if (cur.getTimestamp() != dest.getTimestamp()) {
Card cur = game.getCardState(dest, null);
if (cur == null || !cur.equalsWithTimestamp(dest)) {
// Test to see if the card we're trying to add is in the expected state
continue;
}

View File

@@ -42,14 +42,21 @@ public class CountersMultiplyEffect extends SpellAbilityEffect {
final int n = Integer.valueOf(sa.getParamOrDefault("Multiplier", "2")) - 1;
for (final Card tgtCard : getTargetCards(sa)) {
Card gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue;
}
if (counterType != null) {
tgtCard.addCounter(counterType, tgtCard.getCounters(counterType) * n, host, true);
gameCard.addCounter(counterType, gameCard.getCounters(counterType) * n, host, true);
} else {
for (Map.Entry<CounterType, Integer> e : tgtCard.getCounters().entrySet()) {
tgtCard.addCounter(e.getKey(), e.getValue() * n, host, true);
for (Map.Entry<CounterType, Integer> e : gameCard.getCounters().entrySet()) {
gameCard.addCounter(e.getKey(), e.getValue() * n, host, true);
}
}
game.updateLastStateForCard(tgtCard);
game.updateLastStateForCard(gameCard);
}
}

View File

@@ -128,6 +128,18 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
for (final GameObject obj : tgtObjects) {
// check if the object is still in game or if it was moved
if (obj instanceof Card) {
Card tgtCard = (Card) obj;
Card gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue;
}
}
if (existingCounter) {
final List<CounterType> choices = Lists.newArrayList();
if (obj instanceof GameEntity) {
@@ -186,11 +198,22 @@ public class CountersPutEffect extends SpellAbilityEffect {
// this check needs to check if this card would be on the battlefield
noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield));
// double freeze tracker, so it doesn't update view
game.getTracker().freeze();
CardCollection preList = new CardCollection(noTributeLKI);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(noTributeLKI), preList);
boolean abort = !noTributeLKI.canReceiveCounters(counterType);
game.getAction().checkStaticAbilities(false);
// clear delayed changes, this check should not have updated the view
game.getTracker().clearDelayed();
// need to unfreeze tracker
game.getTracker().unfreeze();
// check if it can recive the Tribute
if (!noTributeLKI.canReceiveCounters(counterType)) {
if (abort) {
continue;
}
@@ -225,9 +248,9 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Monstrosity")) {
tgtCard.setMonstrous(true);
tgtCard.setMonstrosityNum(counterAmount);
final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Card", tgtCard);
runParams.put("MonstrosityAmount", counterAmount);
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false);
}
if (sa.hasParam("Renown")) {

View File

@@ -57,6 +57,13 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
}
for (final Card tgtCard : getDefinedCardsOrTargeted(sa)) {
Card gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue;
}
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) {
if (tgtCard.hasCounters()) {
if (sa.hasParam("EachExistingCounter")) {

View File

@@ -108,8 +108,15 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
}
for (final Card tgtCard : getTargetCards(sa)) {
Card gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue;
}
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) {
final Zone zone = game.getZoneOf(tgtCard);
final Zone zone = game.getZoneOf(gameCard);
if (type.equals("All")) {
for (Map.Entry<CounterType, Integer> e : tgtCard.getCounters().entrySet()) {
tgtCard.subtractCounter(e.getKey(), e.getValue());

View File

@@ -154,7 +154,6 @@ public class Card extends GameEntity implements Comparable<Card> {
private boolean unearthed;
private boolean monstrous = false;
private int monstrosityNum = 0;
private boolean renowned = false;
@@ -4725,13 +4724,6 @@ public class Card extends GameEntity implements Comparable<Card> {
monstrous = monstrous0;
}
public final int getMonstrosityNum() {
return monstrosityNum;
}
public final void setMonstrosityNum(final int num) {
monstrosityNum = num;
}
public final boolean isRenowned() {
return renowned;
}

View File

@@ -1017,11 +1017,6 @@ public class CardFactoryUtil {
return 0;
}
// Count$MonstrosityMagnitude
if (sq[0].contains("MonstrosityMagnitude")) {
return doXMath(c.getMonstrosityNum(), m, c);
}
// Count$Chroma.<color name>
// Count$Devotion.<color name>
if (sq[0].contains("Chroma") || sq[0].equals("Devotion")) {

View File

@@ -17,6 +17,8 @@
*/
package forge.game.trigger;
import java.util.Map;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -42,15 +44,15 @@ public class TriggerBecomeMonstrous extends Trigger {
* @param intrinsic
* the intrinsic
*/
public TriggerBecomeMonstrous(final java.util.Map<String, String> params, final Card host, final boolean intrinsic) {
public TriggerBecomeMonstrous(Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/** {@inheritDoc} */
@Override
public final boolean performTest(final java.util.Map<String, Object> runParams2) {
if (this.mapParams.containsKey("ValidCard")) {
if (!matchesValid(runParams2.get("Card"), this.mapParams.get("ValidCard").split(","),
public final boolean performTest(Map<String, Object> runParams2) {
if (hasParam("ValidCard")) {
if (!matchesValid(runParams2.get("Card"), getParam("ValidCard").split(","),
this.getHostCard())) {
return false;
}
@@ -62,7 +64,8 @@ public class TriggerBecomeMonstrous extends Trigger {
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa) {
sa.setTriggeringObject("Card", this.getRunParams().get("Card"));
sa.setTriggeringObject("Card", getRunParams().get("Card"));
sa.setTriggeringObject("MonstrosityAmount", getRunParams().get("MonstrosityAmount"));
}
@Override

View File

@@ -52,6 +52,10 @@ public class Tracker {
delayedPropChanges.add(new DelayedPropChange(object, prop, value));
}
public void clearDelayed() {
delayedPropChanges.clear();
}
private class DelayedPropChange {
private final TrackableObject object;
private final TrackableProperty prop;