move zoneChangeCounter to GameState - Card is now immutable

This commit is contained in:
betasteward 2015-03-29 08:30:31 -04:00
parent 45aa5f675c
commit 6405c8d2f0
101 changed files with 899 additions and 257 deletions

View file

@ -48,4 +48,9 @@ public interface MageObject extends MageItem, Serializable {
* @return
*/
boolean isCopy();
int getZoneChangeCounter(Game game);
void updateZoneChangeCounter(Game game);
void setZoneChangeCounter(int value, Game game);
}

View file

@ -198,4 +198,20 @@ public abstract class MageObjectImpl implements MageObject {
public boolean isCopy() {
return copy;
}
@Override
public int getZoneChangeCounter(Game game) {
return game.getState().getZoneChangeCounter(objectId);
}
@Override
public void updateZoneChangeCounter(Game game) {
game.getState().updateZoneChangeCounter(objectId);
}
@Override
public void setZoneChangeCounter(int value, Game game) {
game.getState().setZoneChangeCounter(objectId, value);
}
}

View file

@ -45,26 +45,9 @@ public class MageObjectReference implements Comparable<MageObjectReference> {
private final UUID sourceId;
private final int zoneChangeCounter;
public MageObjectReference(Permanent permanent) {
this.sourceId = permanent.getId();
this.zoneChangeCounter = permanent.getZoneChangeCounter();
}
public MageObjectReference(Card card) {
this.sourceId = card.getId();
this.zoneChangeCounter = card.getZoneChangeCounter();
}
public MageObjectReference(MageObject mageObject) {
public MageObjectReference(MageObject mageObject, Game game) {
this.sourceId = mageObject.getId();
if (mageObject instanceof Card) {
this.zoneChangeCounter = ((Card)mageObject).getZoneChangeCounter();
} else if (mageObject instanceof Permanent) {
this.zoneChangeCounter = ((Permanent)mageObject).getZoneChangeCounter();
} else {
this.zoneChangeCounter = 0;
}
this.zoneChangeCounter = mageObject.getZoneChangeCounter(game);
}
/**
* That values manually (can be used to let it reference to a Permanent
@ -80,17 +63,12 @@ public class MageObjectReference implements Comparable<MageObjectReference> {
}
public MageObjectReference(UUID sourceId, Game game) {
MageObject mageObject = game.getObject(sourceId);
this.sourceId = sourceId;
if (mageObject instanceof Permanent) {
this.zoneChangeCounter = ((Permanent)mageObject).getZoneChangeCounter();
} else if (mageObject instanceof Card) {
this.zoneChangeCounter = ((Card)mageObject).getZoneChangeCounter();
} else if (mageObject instanceof Spell) {
this.zoneChangeCounter = ((Spell)mageObject).getZoneChangeCounter();
} else {
zoneChangeCounter = 0;
}
MageObject mageObject = game.getObject(sourceId);
if (mageObject != null)
this.zoneChangeCounter = mageObject.getZoneChangeCounter(game);
else
this.zoneChangeCounter = 0;
}
public UUID getSourceId() {
@ -127,35 +105,16 @@ public class MageObjectReference implements Comparable<MageObjectReference> {
}
public boolean refersTo(UUID id, Game game) {
return refersTo(game.getObject(id));
return refersTo(game.getObject(id), game);
}
public boolean refersTo(Permanent permanent) {
return permanent.getZoneChangeCounter()== zoneChangeCounter && permanent.getId().equals(sourceId);
}
public boolean refersTo(Card card) {
return card.getZoneChangeCounter()== zoneChangeCounter && card.getId().equals(sourceId);
}
public boolean refersTo(Spell spell) {
return spell.getZoneChangeCounter()== zoneChangeCounter && spell.getSourceId().equals(sourceId);
}
public boolean refersTo(MageObject mageObject) {
if (mageObject instanceof Permanent) {
return refersTo(((Permanent)mageObject));
} else if (mageObject instanceof Spell) {
return refersTo(((Spell)mageObject));
} else if (mageObject instanceof Card) {
return refersTo(((Card)mageObject));
}
return mageObject.getId().equals(sourceId);
public boolean refersTo(MageObject mageObject, Game game) {
return mageObject.getId().equals(sourceId) && this.zoneChangeCounter == mageObject.getZoneChangeCounter(game);
}
public Permanent getPermanent(Game game) {
Permanent permanent = game.getPermanent(sourceId);
if (permanent != null && permanent.getZoneChangeCounter() == zoneChangeCounter) {
if (permanent != null && permanent.getZoneChangeCounter(game) == zoneChangeCounter) {
return permanent;
}
return null;
@ -163,7 +122,7 @@ public class MageObjectReference implements Comparable<MageObjectReference> {
public Permanent getPermanentOrLKIBattlefield(Game game) {
Permanent permanent = game.getPermanentOrLKIBattlefield(sourceId);
if (permanent != null && permanent.getZoneChangeCounter() == zoneChangeCounter) {
if (permanent != null && permanent.getZoneChangeCounter(game) == zoneChangeCounter) {
return permanent;
}
return null;
@ -171,7 +130,7 @@ public class MageObjectReference implements Comparable<MageObjectReference> {
public Card getCard(Game game) {
Card card = game.getCard(sourceId);
if (card != null && card.getZoneChangeCounter() == zoneChangeCounter) {
if (card != null && card.getZoneChangeCounter(game) == zoneChangeCounter) {
return card;
}
return null;

View file

@ -879,10 +879,10 @@ public abstract class AbilityImpl implements Ability {
boolean found = false;
// unfortunately we need to handle double faced cards separately and only this way
if (object instanceof PermanentCard) {
// if (((PermanentCard)object).canTransform()) {
// PermanentCard permanent = (PermanentCard)object;
// found = permanent.getSecondCardFace().getAbilities().contains(this) || permanent.getCard().getAbilities().contains(this);
// }
if (((PermanentCard)object).canTransform()) {
PermanentCard permanent = (PermanentCard)object;
found = permanent.getSecondCardFace().getAbilities().contains(this) || permanent.getCard().getAbilities().contains(this);
}
} else {
// check if it's an ability that is temporary gained to a card
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());

View file

@ -41,7 +41,7 @@ public class DiesAndDealtDamageThisTurnTriggeredAbility extends TriggeredAbility
if (zEvent.getTarget().getCardType().contains(CardType.CREATURE)) {
boolean damageDealt = false;
for (MageObjectReference mor : zEvent.getTarget().getDealtDamageByThisTurn()) {
if (mor.refersTo(getSourceObject(game))) {
if (mor.refersTo(getSourceObject(game), game)) {
damageDealt = true;
break;
}

View file

@ -53,7 +53,7 @@ public class SweepNumber implements DynamicValue {
if (zoneChangeCounter == 0) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
if (previousZone) {
zoneChangeCounter--;
}

View file

@ -150,7 +150,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
}
game.rememberLKI(card.getId(), fromZone, card);
PermanentCard permanent = new PermanentCard(card, card.getOwnerId());
PermanentCard permanent = new PermanentCard(card, card.getOwnerId(), game);
game.getBattlefield().addPermanent(permanent);
card.setZone(Zone.BATTLEFIELD, game);
game.applyEffects();

View file

@ -79,7 +79,7 @@ public class PreventDamageBySourceEffect extends PreventionEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {
MageObject mageObject = game.getObject(event.getSourceId());
if (mageObject != null && mageObjectReference.refersTo(mageObject)) {
if (mageObject != null && mageObjectReference.refersTo(mageObject, game)) {
return true;
}
}

View file

@ -61,9 +61,9 @@ public class ReturnToBattlefieldUnderYourControlSourceEffect extends OneShotEffe
@Override
public boolean apply(Game game, Ability source) {
MageObjectReference mor = new MageObjectReference(source.getSourceObject(game));
MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game);
Card card = game.getCard(source.getSourceId());
if (card != null && game.getState().getZone(source.getSourceId()) == onlyFromZone && mor.getZoneChangeCounter() == card.getZoneChangeCounter() + 1) {
if (card != null && game.getState().getZone(source.getSourceId()) == onlyFromZone && mor.getZoneChangeCounter() == card.getZoneChangeCounter(game) + 1) {
Zone currentZone = game.getState().getZone(card.getId());
if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), source.getControllerId())) {
return true;

View file

@ -60,7 +60,7 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect {
if (attackingCreature != null && attackingCreature.isAttacking()) {
if (!source.getAbilityType().equals(AbilityType.STATIC)) {
BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get("BlockedAttackerWatcher");
if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attackingCreature, permanent)) {
if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attackingCreature, permanent, game)) {
// has already blocked this turn, so no need to do again
return false;
}

View file

@ -63,7 +63,7 @@ public class MustBeBlockedByTargetSourceEffect extends RequirementEffect {
Permanent attacker = game.getPermanent(source.getSourceId());
if (attacker != null) {
BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get("BlockedAttackerWatcher");
if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker)) {
if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) {
// has already blocked this turn, so no need to do again
return false;
}

View file

@ -86,7 +86,7 @@ public class BecomesFaceDownCreatureAllEffect extends ContinuousEffectImpl imple
super.init(source, game);
for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
if (!perm.isFaceDown(game) && !perm.canTransform()) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
perm.setFaceDown(true, game);
// check for Morph
Card card = game.getCard(perm.getId());

View file

@ -113,7 +113,7 @@ public class BoostAllEffect extends ContinuousEffectImpl {
if (this.affectedObjectsSet) {
for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -116,7 +116,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
if (this.affectedObjectsSet) {
for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -51,7 +51,7 @@ public class BoostOpponentsEffect extends ContinuousEffectImpl {
Set<UUID> opponents = game.getOpponents(source.getControllerId());
for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
if (opponents.contains(perm.getControllerId())) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -113,9 +113,9 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
return;
}
this.lockedControllers.put(permanent1.getId(), permanent2.getControllerId());
this.zoneChangeCounter.put(permanent1.getId(), permanent1.getZoneChangeCounter());
this.zoneChangeCounter.put(permanent1.getId(), permanent1.getZoneChangeCounter(game));
this.lockedControllers.put(permanent2.getId(), permanent1.getControllerId());
this.zoneChangeCounter.put(permanent2.getId(), permanent2.getZoneChangeCounter());
this.zoneChangeCounter.put(permanent2.getId(), permanent2.getZoneChangeCounter(game));
} else {
// discard if there are less than 2 permanents
discard();
@ -127,7 +127,7 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
Set<UUID> toDelete = new HashSet<>();
for (Map.Entry<UUID, Integer> entry: zoneChangeCounter.entrySet()) {
Permanent permanent = game.getPermanent(entry.getKey());
if (permanent == null || permanent.getZoneChangeCounter() != entry.getValue()) {
if (permanent == null || permanent.getZoneChangeCounter(game) != entry.getValue()) {
// controll effect cease if the same permanent is no longer on the battlefield
toDelete.add(entry.getKey());
continue;

View file

@ -90,7 +90,7 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
if (this.affectedObjectsSet) {
for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -95,7 +95,7 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl {
if (this.affectedObjectsSet) {
for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -91,7 +91,7 @@ public class SetPowerToughnessAllEffect extends ContinuousEffectImpl {
super.init(source, game);
if (affectedObjectsSet) {
for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
if (lockedInPT) {

View file

@ -74,7 +74,7 @@ public class SwitchPowerToughnessAllEffect extends ContinuousEffectImpl {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (Permanent perm :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -94,7 +94,7 @@ public class DealtDamageToCreatureBySourceDies extends ReplacementEffectImpl {
if (zce.isDiesEvent()) {
DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId());
if (watcher != null) {
return watcher.wasDamaged(zce.getTarget());
return watcher.wasDamaged(zce.getTarget(), game);
}
}
return false;

View file

@ -86,7 +86,7 @@ public class ManifestEffect extends OneShotEffect {
manaCosts = new ManaCostsImpl("{0}");
}
}
MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter() +1, game);
MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) +1, game);
game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource);
controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, newSource.getSourceId(), false, true);
Permanent permanent = game.getPermanent(card.getId());

View file

@ -90,7 +90,7 @@ public class ManifestTargetPlayerEffect extends OneShotEffect {
manaCosts = new ManaCostsImpl("{0}");
}
}
MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter() +1, game);
MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) +1, game);
game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource);
targetPlayer.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, newSource.getSourceId(), false, true);
Permanent permanent = game.getPermanent(card.getId());

View file

@ -110,7 +110,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts
@Override
public boolean isActivated(Ability ability, Game game) {
Card card = game.getCard(sourceId);
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) {
for (AlternativeCost2 cost: alternativeSourceCosts) {
if(cost.isActivated(game)) {
return true;
@ -158,7 +158,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts
if (zoneChangeCounter == 0) {
Card card = game.getCard(getSourceId());
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
} else {
throw new IllegalArgumentException("Dash source card not found");
}

View file

@ -145,7 +145,7 @@ class EchoEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObjectReference mor = new MageObjectReference(source.getSourceId(), game);
if (controller != null && mor.refersTo(source.getSourceObject(game))) {
if (controller != null && mor.refersTo(source.getSourceObject(game), game)) {
if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + "?", game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) {

View file

@ -103,7 +103,7 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost
@Override
public boolean isActivated(Ability ability, Game game) {
Card card = game.getCard(sourceId);
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) {
for (AlternativeCost2 cost: evokeCosts) {
if(cost.isActivated(game)) {
return true;
@ -151,7 +151,7 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost
if (zoneChangeCounter == 0) {
Card card = game.getCard(getSourceId());
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
} else {
throw new IllegalArgumentException("Evoke source card not found");
}

View file

@ -108,7 +108,7 @@ public class HauntAbility extends TriggeredAbilityImpl {
if (zEvent.isDiesEvent()) {
Card card = game.getCard(getSourceId());
if (card != null) {
String key = new StringBuilder("Haunting_").append(getSourceId().toString()).append("_").append(card.getZoneChangeCounter()).toString();
String key = new StringBuilder("Haunting_").append(getSourceId().toString()).append("_").append(card.getZoneChangeCounter(game)).toString();
Object object = game.getState().getValue(key);
if (object != null && object instanceof FixedTarget) {
FixedTarget target = (FixedTarget) object;
@ -205,7 +205,7 @@ class HauntEffect extends OneShotEffect {
if (hauntedCreature != null) {
if (card.moveToExile(source.getSourceId(), "Haunting", source.getSourceId(), game)) {
// remember the haunted creature
String key = new StringBuilder("Haunting_").append(source.getSourceId().toString()).append("_").append(card.getZoneChangeCounter()).toString();
String key = new StringBuilder("Haunting_").append(source.getSourceId().toString()).append("_").append(card.getZoneChangeCounter(game)).toString();
game.getState().setValue(key, new FixedTarget(targetPointer.getFirst(game, source)));
card.addInfo("hauntinfo", new StringBuilder("Haunting ").append(hauntedCreature.getLogName()).toString(), game);
hauntedCreature.addInfo("hauntinfo", new StringBuilder("Haunted by ").append(card.getLogName()).toString(), game);

View file

@ -164,7 +164,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
public boolean isKicked(Game game) {
Card card = game.getCard(sourceId);
// kicked status counts only if card not changed zone since it was kicked
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) {
for (OptionalAdditionalCost cost: kickerCosts) {
if(cost.isActivated()) {
return true;
@ -186,7 +186,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
if (zoneChangeCounter == 0) {
Card card = game.getCard(getSourceId());
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
} else {
throw new IllegalArgumentException("Kicker source card not found");
}

View file

@ -184,7 +184,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
@Override
public boolean isActivated(Ability ability, Game game) {
Card card = game.getCard(sourceId);
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) {
return alternateCosts.isActivated(game);
}
return false;
@ -261,7 +261,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
if (zoneChangeCounter == 0) {
Card card = game.getCard(getSourceId());
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
} else {
throw new IllegalArgumentException("Morph source card not found");
}

View file

@ -102,7 +102,7 @@ class StormEffect extends OneShotEffect {
if (spell != null) {
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher");
int stormCount = watcher.getSpellOrder(spell) - 1;
int stormCount = watcher.getSpellOrder(spell, game) - 1;
if (stormCount > 0) {
game.informPlayers("Storm: " + spell.getName() + " will be copied " + stormCount + " time" + (stormCount > 1 ?"s":""));
for (int i = 0; i < stormCount; i++) {

View file

@ -69,9 +69,6 @@ public interface Card extends MageObject {
void assignNewId();
int getZoneChangeCounter();
void updateZoneChangeCounter();
void addInfo(String key, String value, Game game);
/**

View file

@ -86,7 +86,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
protected SpellAbility spellAbility;
protected boolean flipCard;
protected String flipCardName;
protected int zoneChangeCounter = 1;
protected boolean usesVariousArt = false;
protected boolean splitCard;
protected boolean morphCard;
@ -150,7 +149,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
secondSideCard = card.secondSideCard;
nightCard = card.nightCard;
}
zoneChangeCounter = card.zoneChangeCounter;
flipCard = card.flipCard;
flipCardName = card.flipCardName;
splitCard = card.splitCard;
@ -377,7 +375,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
}
setFaceDown(false, game);
updateZoneChangeCounter();
updateZoneChangeCounter(game);
switch (event.getToZone()) {
case GRAVEYARD:
game.getPlayer(ownerId).putInGraveyard(this, game, !flag);
@ -403,7 +401,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
}
break;
case BATTLEFIELD:
PermanentCard permanent = new PermanentCard(this, event.getPlayerId()); // controller can be replaced (e.g. Gather Specimens)
PermanentCard permanent = new PermanentCard(this, event.getPlayerId(), game); // controller can be replaced (e.g. Gather Specimens)
game.addPermanent(permanent);
game.setZone(objectId, Zone.BATTLEFIELD);
game.setScopeRelevant(true);
@ -510,7 +508,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
game.getExile().createZone(exileId, name).add(this);
}
setFaceDown(false, game);
updateZoneChangeCounter();
updateZoneChangeCounter(game);
game.setZone(objectId, event.getToZone());
game.addSimultaneousEvent(event);
return true;
@ -574,8 +572,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
logger.warn("Couldn't find card in fromZone, card=" + getName() + ", fromZone=" + fromZone);
}
}
updateZoneChangeCounter();
PermanentCard permanent = new PermanentCard(this, event.getPlayerId());
updateZoneChangeCounter(game);
PermanentCard permanent = new PermanentCard(this, event.getPlayerId(), game);
// make sure the controller of all continuous effects of this card are switched to the current controller
game.getContinuousEffects().setController(objectId, event.getPlayerId());
game.addPermanent(permanent);
@ -662,20 +660,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
return splitCard;
}
@Override
public int getZoneChangeCounter() {
// logger.info(name + " get= " + zoneChangeCounter + " " + ((this instanceof Permanent) ? " Permanent":"Card"));
return zoneChangeCounter;
}
@Override
public void updateZoneChangeCounter() {
zoneChangeCounter++;
// logger.info(name + " set= " + zoneChangeCounter + " " + ((this instanceof Permanent) ? " Permanent":"Card"));
}
@Override
public void build() {}

View file

@ -2239,10 +2239,10 @@ public abstract class GameImpl implements Game, Serializable {
if (object instanceof Permanent) {
Map<Integer, MageObject> lkiExtendedMap = lkiExtended.get(objectId);
if (lkiExtendedMap != null) {
lkiExtendedMap.put(((Permanent) object).getZoneChangeCounter(), copy);
lkiExtendedMap.put(((Permanent) object).getZoneChangeCounter(this), copy);
} else {
lkiExtendedMap = new HashMap<>();
lkiExtendedMap.put(((Permanent) object).getZoneChangeCounter(), copy);
lkiExtendedMap.put(((Permanent) object).getZoneChangeCounter(this), copy);
lkiExtended.put(objectId, lkiExtendedMap);
}
}
@ -2349,7 +2349,7 @@ public abstract class GameImpl implements Game, Serializable {
for (PermanentCard card : battlefield) {
card.setZone(Zone.BATTLEFIELD, this);
card.setOwnerId(ownerId);
PermanentCard permanent = new PermanentCard(card.getCard(), ownerId);
PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this);
getBattlefield().addPermanent(permanent);
permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false);
((PermanentImpl)permanent).removeSummoningSickness();

View file

@ -104,6 +104,7 @@ public class GameState implements Serializable, Copyable<GameState> {
private Map<UUID, Zone> zones = new HashMap<>();
private List<GameEvent> simultaneousEvents = new ArrayList<>();
private Map<UUID, CardState> cardState = new HashMap<>();
private Map<UUID, Integer> zoneChangeCounter = new HashMap<>();
public GameState() {
players = new Players();
@ -159,6 +160,7 @@ public class GameState implements Serializable, Copyable<GameState> {
for (Map.Entry<UUID, CardState> entry: state.cardState.entrySet()) {
cardState.put(entry.getKey(), entry.getValue().copy());
}
this.zoneChangeCounter.putAll(state.zoneChangeCounter);
}
@Override
@ -495,6 +497,7 @@ public class GameState implements Serializable, Copyable<GameState> {
}
this.simultaneousEvents = state.simultaneousEvents;
this.cardState = state.cardState;
this.zoneChangeCounter = state.zoneChangeCounter;
}
public void addSimultaneousEvent(GameEvent event, Game game) {
@ -691,8 +694,8 @@ public class GameState implements Serializable, Copyable<GameState> {
/**
* Adds the ability to continuous or triggered abilities
* @param attachedTo
* @param ability
* @param card
*/
public void addOtherAbility(Card attachedTo, Ability ability) {
ability.setSourceId(attachedTo.getId());
@ -794,4 +797,25 @@ public class GameState implements Serializable, Copyable<GameState> {
this.watchers.add(watcher);
}
public int getZoneChangeCounter(UUID objectId) {
if (this.zoneChangeCounter.containsKey(objectId)) {
return this.zoneChangeCounter.get(objectId);
}
return 1;
}
public void updateZoneChangeCounter(UUID objectId) {
Integer value = getZoneChangeCounter(objectId);
value++;
this.zoneChangeCounter.put(objectId, value);
// card is changing zone so clear state
if (cardState.containsKey(objectId)) {
this.cardState.get(objectId).clear();
}
}
public void setZoneChangeCounter(UUID objectId, int value) {
this.zoneChangeCounter.put(objectId, value);
}
}

View file

@ -192,5 +192,20 @@ public class Commander implements CommandObject{
public String getImageName() {
return card.getImageName();
}
@Override
public int getZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void updateZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
}

View file

@ -198,5 +198,20 @@ public class Emblem implements CommandObject {
public String getExpansionSetCodeForImage() {
return expansionSetCodeForImage;
}
@Override
public int getZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void updateZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
}

View file

@ -48,21 +48,17 @@ public class PermanentCard extends PermanentImpl {
protected int maxLevelCounters;
protected Card card;
protected int zoneChangeCounter;
public PermanentCard(Card card, UUID controllerId) {
public PermanentCard(Card card, UUID controllerId, Game game) {
super(card.getId(), card.getOwnerId(), controllerId, card.getName());
this.card = card.copy();
init(card);
init(card, game);
}
protected PermanentCard(UUID id, Card card, UUID controllerId) {
super(card.getId(), card.getOwnerId(), controllerId, card.getName());
this.card = card.copy();
init(card);
}
private void init(Card card) {
private void init(Card card, Game game) {
copyFromCard(card);
this.zoneChangeCounter = card.getZoneChangeCounter(game);
/*if (card.getCardType().contains(CardType.PLANESWALKER)) {
this.loyalty = new MageInt(card.getLoyalty().getValue());
}*/
@ -75,6 +71,7 @@ public class PermanentCard extends PermanentImpl {
super(permanent);
this.card = permanent.card.copy();
this.maxLevelCounters = permanent.maxLevelCounters;
this.zoneChangeCounter = permanent.zoneChangeCounter;
}
@Override
@ -99,6 +96,7 @@ public class PermanentCard extends PermanentImpl {
this.abilities = card.getAbilities().copy();
}
this.abilities.setControllerId(this.controllerId);
this.abilities.setSourceId(objectId);
this.cardType.clear();
this.cardType.addAll(card.getCardType());
this.color = card.getColor().copy();
@ -116,7 +114,6 @@ public class PermanentCard extends PermanentImpl {
this.rarity = card.getRarity();
this.cardNumber = card.getCardNumber();
this.usesVariousArt = card.getUsesVariousArt();
this.zoneChangeCounter = card.getZoneChangeCounter();
canTransform = card.canTransform();
if (canTransform) {
@ -140,15 +137,12 @@ public class PermanentCard extends PermanentImpl {
Zone fromZone = game.getState().getZone(objectId);
Player controller = game.getPlayer(controllerId);
if (controller != null && controller.removeFromBattlefield(this, game)) {
Card originalCard = game.getCard(this.getId());
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, controllerId, fromZone, toZone, appliedEffects);
if (!game.replaceEvent(event)) {
Player owner = game.getPlayer(ownerId);
game.rememberLKI(objectId, Zone.BATTLEFIELD, this);
if (owner != null) {
if (originalCard != null) {
originalCard.updateZoneChangeCounter();
}
card.updateZoneChangeCounter(game);
switch (event.getToZone()) {
case GRAVEYARD:
owner.putInGraveyard(card, game, !flag);
@ -196,7 +190,7 @@ public class PermanentCard extends PermanentImpl {
if (!game.replaceEvent(event)) {
game.rememberLKI(objectId, Zone.BATTLEFIELD, this);
// update zone change counter of original card
game.getCard(this.getId()).updateZoneChangeCounter();
card.updateZoneChangeCounter(game);
if (exileId == null) {
game.getExile().getPermanentExile().add(card);
} else {
@ -252,6 +246,20 @@ public class PermanentCard extends PermanentImpl {
}
return super.getManaCost();
}
@Override
public int getZoneChangeCounter(Game game) {
return this.zoneChangeCounter;
}
@Override
public void updateZoneChangeCounter(Game game) {
this.zoneChangeCounter++;
}
@Override
public void setZoneChangeCounter(int value, Game game) {
this.zoneChangeCounter = value;
}
}

View file

@ -777,7 +777,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
if (dealtDamageByThisTurn == null) {
dealtDamageByThisTurn = new HashSet<>();
}
dealtDamageByThisTurn.add(new MageObjectReference(source));
dealtDamageByThisTurn.add(new MageObjectReference(source, game));
}
}
}

View file

@ -124,17 +124,6 @@ public class PermanentToken extends PermanentImpl {
return new PermanentToken(this);
}
@Override
public void addAbility(Ability ability, Game game) {
if (!abilities.containsKey(ability.getId())) {
Ability copyAbility = ability.copy();
copyAbility.setControllerId(controllerId);
copyAbility.setSourceId(objectId);
game.getState().addAbility(copyAbility, this);
abilities.add(copyAbility);
}
}
@Override
public void adjustTargets(Ability ability, Game game) {
if (getToken().getCopySourceCard() != null) {

View file

@ -873,10 +873,15 @@ public class Spell implements StackObject, Card {
}
@Override
public void updateZoneChangeCounter() {
public void updateZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public Ability getStackAbility() {
return this.ability;
@ -888,8 +893,8 @@ public class Spell implements StackObject, Card {
}
@Override
public int getZoneChangeCounter() {
return card.getZoneChangeCounter();
public int getZoneChangeCounter(Game game) {
return card.getZoneChangeCounter(game);
}
@Override

View file

@ -507,5 +507,19 @@ public class StackAbility implements StackObject, Ability {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int getZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void updateZoneChangeCounter(Game game) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Not supported.");
}
}

View file

@ -252,7 +252,7 @@ public abstract class TargetImpl implements Target {
private void rememberZoneChangeCounter(UUID id, Game game) {
Card card = game.getCard(id);
if (card != null) {
zoneChangeCounters.put(id, card.getZoneChangeCounter());
zoneChangeCounters.put(id, card.getZoneChangeCounter(game));
}
}
@ -331,7 +331,7 @@ public abstract class TargetImpl implements Target {
for (UUID targetId: targets.keySet()) {
Card card = game.getCard(targetId);
if (card != null) {
if (zoneChangeCounters.containsKey(targetId) && zoneChangeCounters.get(targetId) != card.getZoneChangeCounter()) {
if (zoneChangeCounters.containsKey(targetId) && zoneChangeCounters.get(targetId) != card.getZoneChangeCounter(game)) {
illegalTargets.add(targetId);
continue; // it's not legal so continue to have a look at other targeted objects
}

View file

@ -34,7 +34,7 @@ public class FirstTargetPointer implements TargetPointer {
for (UUID target : source.getTargets().get(0).getTargets()) {
Card card = game.getCard(target);
if (card != null) {
this.zoneChangeCounter.put(target, card.getZoneChangeCounter());
this.zoneChangeCounter.put(target, card.getZoneChangeCounter(game));
}
}
}
@ -47,11 +47,10 @@ public class FirstTargetPointer implements TargetPointer {
for (UUID targetId : source.getTargets().get(0).getTargets()) {
Card card = game.getCard(targetId);
if (card != null && zoneChangeCounter.containsKey(targetId)
&& card.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
// because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before
&& card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
// but no longer if new permanent is already on the battlefield
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
if (permanent == null || permanent.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
if (permanent == null || permanent.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
continue;
}
}
@ -67,11 +66,11 @@ public class FirstTargetPointer implements TargetPointer {
if (zoneChangeCounter.containsKey(targetId)) {
Card card = game.getCard(targetId);
if (card != null && zoneChangeCounter.containsKey(targetId)
&& card.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
&& card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
// because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before
// but no longer if new permanent is already on the battlefield
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
if (permanent == null || permanent.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
if (permanent == null || permanent.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
return null;
}
}

View file

@ -25,7 +25,7 @@ public class FixedTarget implements TargetPointer {
public void init(Game game, Ability source) {
Card card = game.getCard(target);
if (card != null) {
this.zoneChangeCounter = card.getZoneChangeCounter();
this.zoneChangeCounter = card.getZoneChangeCounter(game);
}
}
@ -34,7 +34,7 @@ public class FixedTarget implements TargetPointer {
// check target not changed zone
if (this.zoneChangeCounter > 0) { // will be zero if not defined in init
Card card = game.getCard(target);
if (card != null && card.getZoneChangeCounter() != this.zoneChangeCounter) {
if (card != null && card.getZoneChangeCounter(game) != this.zoneChangeCounter) {
return new ArrayList<>(); // return empty
}
}
@ -49,7 +49,7 @@ public class FixedTarget implements TargetPointer {
// check target not changed zone
if (this.zoneChangeCounter > 0) { // will be zero if not defined in init
Card card = game.getCard(target);
if (card != null && card.getZoneChangeCounter() != this.zoneChangeCounter) {
if (card != null && card.getZoneChangeCounter(game) != this.zoneChangeCounter) {
return null;
}
}

View file

@ -33,7 +33,7 @@ public class SecondTargetPointer implements TargetPointer {
for (UUID target : source.getTargets().get(1).getTargets()) {
Card card = game.getCard(target);
if (card != null) {
this.zoneChangeCounter.put(target, card.getZoneChangeCounter());
this.zoneChangeCounter.put(target, card.getZoneChangeCounter(game));
}
}
}
@ -46,7 +46,7 @@ public class SecondTargetPointer implements TargetPointer {
for (UUID targetId : source.getTargets().get(1).getTargets()) {
Card card = game.getCard(targetId);
if (card != null && zoneChangeCounter.containsKey(targetId)
&& card.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
&& card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
continue;
}
target.add(targetId);
@ -62,7 +62,7 @@ public class SecondTargetPointer implements TargetPointer {
if (zoneChangeCounter.containsKey(targetId)) {
Card card = game.getCard(targetId);
if (card != null && zoneChangeCounter.containsKey(targetId)
&& card.getZoneChangeCounter() != zoneChangeCounter.get(targetId)) {
&& card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) {
return null;
}
}

View file

@ -485,9 +485,9 @@ public class CardUtil {
public static UUID getObjectExileZoneId(Game game, MageObject mageObject, boolean previous) {
int zoneChangeCounter = 0;
if (mageObject instanceof Permanent) {
zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter();
zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter(game);
} else if (mageObject instanceof Card) {
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter();
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter(game);
}
if (zoneChangeCounter > 0 && previous) {
zoneChangeCounter--;
@ -526,7 +526,7 @@ public class CardUtil {
int zoneChangeCounter= 0;
Card card = game.getCard(cardId); // if called for a token, the id is enough
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
}
return getObjectZoneString(text,cardId, game, zoneChangeCounter, previous);
}
@ -534,9 +534,9 @@ public class CardUtil {
public static String getObjectZoneString(String text, MageObject mageObject, Game game) {
int zoneChangeCounter = 0;
if (mageObject instanceof Permanent) {
zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter();
zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter(game);
} else if (mageObject instanceof Card) {
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter();
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter(game);
}
return getObjectZoneString(text, mageObject.getId(), game, zoneChangeCounter, false);
}

View file

@ -85,8 +85,8 @@ public class BlockedAttackerWatcher extends Watcher {
blockData.clear();
}
public boolean creatureHasBlockedAttacker(Permanent attacker, Permanent blocker) {
Set<MageObjectReference> blockedAttackers = blockData.get(new MageObjectReference(blocker));
return blockedAttackers != null && blockedAttackers.contains(new MageObjectReference(attacker));
public boolean creatureHasBlockedAttacker(Permanent attacker, Permanent blocker, Game game) {
Set<MageObjectReference> blockedAttackers = blockData.get(new MageObjectReference(blocker, game));
return blockedAttackers != null && blockedAttackers.contains(new MageObjectReference(attacker, game));
}
}

View file

@ -68,7 +68,7 @@ public class CastSpellLastTurnWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
spellsCastThisTurnInOrder.add(new MageObjectReference(event.getSourceId(), game));
spellsCastThisTurnInOrder.add(new MageObjectReference(event.getTargetId(), game));
UUID playerId = event.getPlayerId();
if (playerId != null) {
Integer amount = amountOfSpellsCastOnCurrentTurn.get(playerId);
@ -115,11 +115,11 @@ public class CastSpellLastTurnWatcher extends Watcher {
}
}
public int getSpellOrder(Spell spell) {
public int getSpellOrder(Spell spell, Game game) {
int index = 0;
for (MageObjectReference mor : spellsCastThisTurnInOrder) {
index++;
if (mor.refersTo(spell)) {
if (mor.refersTo(spell, game)) {
return index;
}
}

View file

@ -80,12 +80,12 @@ public class DamagedByWatcher extends Watcher {
public boolean wasDamaged(UUID sourceId, Game game) {
MageObject mageObject = game.getObject(sourceId);
if (mageObject instanceof Permanent) {
return wasDamaged((Permanent) mageObject);
return wasDamaged((Permanent) mageObject, game);
}
return false;
}
public boolean wasDamaged(Permanent permanent) {
return damagedCreatures.contains(new MageObjectReference(permanent));
public boolean wasDamaged(Permanent permanent, Game game) {
return damagedCreatures.contains(new MageObjectReference(permanent, game));
}
}