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

@ -108,7 +108,7 @@ class DayEffect extends ContinuousEffectImpl {
if (this.affectedObjectsSet) {
List<Permanent> creatures = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getFirstTarget(), game);
for (Permanent creature : creatures) {
affectedObjectList.add(new MageObjectReference(creature));
affectedObjectList.add(new MageObjectReference(creature, game));
}
}
}

View file

@ -127,7 +127,7 @@ class AggravateRequirementEffect extends RequirementEffect {
public boolean applies(Permanent permanent, Ability source, Game game) {
DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId());
if (watcher != null) {
return watcher.wasDamaged(permanent);
return watcher.wasDamaged(permanent, game);
}
return false;
}

View file

@ -79,7 +79,7 @@ class SecondSpellPredicate implements Predicate<Spell> {
public boolean apply(Spell input, Game game) {
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher");
if (watcher.getSpellOrder(input) == 2) {
if (watcher.getSpellOrder(input, game) == 2) {
return true;
}

View file

@ -129,7 +129,7 @@ class KumanosBlessingEffect extends ReplacementEffectImpl {
if (zce.isDiesEvent()) {
DamagedByEnchantedWatcher watcher = (DamagedByEnchantedWatcher) game.getState().getWatchers().get("DamagedByEnchantedWatcher", source.getSourceId());
if (watcher != null) {
return watcher.wasDamaged(zce.getTarget());
return watcher.wasDamaged(zce.getTarget(), game);
}
}
}
@ -177,7 +177,7 @@ class DamagedByEnchantedWatcher extends Watcher {
damagedCreatures.clear();
}
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));
}
}

View file

@ -85,12 +85,12 @@ class BileBlightEffect extends BoostAllEffect {
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (target != null) {
if (target.getName().isEmpty()) { // face down creature
affectedObjectList.add(new MageObjectReference(target));
affectedObjectList.add(new MageObjectReference(target, game));
} else {
String name = target.getLogName();
for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) {
if (perm.getLogName().equals(name)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -123,7 +123,7 @@ class GainProtectionFromColorSourceEffect extends GainAbilitySourceEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && new MageObjectReference(permanent).refersTo(source.getSourceObject(game))) {
if (permanent != null && new MageObjectReference(permanent, game).refersTo(source.getSourceObject(game), game)) {
permanent.addAbility(ability, source.getSourceId(), game);
} else {
// the source permanent is no longer on the battlefield, effect can be discarded

View file

@ -103,7 +103,7 @@ class TakenoSamuraiGeneralEffect extends ContinuousEffectImpl {
if (!perm.getId().equals(source.getSourceId())) {
for (Ability ability : perm.getAbilities()) {
if (ability instanceof BushidoAbility) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}

View file

@ -111,7 +111,7 @@ class BroodingSaurianControlEffect extends ContinuousEffectImpl {
FilterPermanent playerFilter = filter.copy();
playerFilter.add(new OwnerIdPredicate(playerId));
for (Permanent permanent :game.getBattlefield().getActivePermanents(playerFilter, playerId, game)) {
affectedObjectList.add(new MageObjectReference(permanent));
affectedObjectList.add(new MageObjectReference(permanent, game));
}
}
}

View file

@ -107,7 +107,7 @@ class HomewardPathControlEffect extends ContinuousEffectImpl {
FilterPermanent playerFilter = filter.copy();
playerFilter.add(new OwnerIdPredicate(playerId));
for (Permanent permanent :game.getBattlefield().getActivePermanents(playerFilter, playerId, game)) {
affectedObjectList.add(new MageObjectReference(permanent));
affectedObjectList.add(new MageObjectReference(permanent, game));
}
}
}

View file

@ -113,7 +113,7 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect {
if (controller != null && sourceCard != null) {
JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get("ManaPaidToCastJelevaNephalias", source.getSourceId());
if (watcher != null) {
int xValue = watcher.getManaSpentToCastLastTime(sourceCard.getZoneChangeCounter() - 1);
int xValue = watcher.getManaSpentToCastLastTime(sourceCard.getZoneChangeCounter(game) - 1);
if (xValue > 0) {
for (UUID playerId : controller.getInRange()) {
Player player = game.getPlayer(playerId);
@ -195,8 +195,8 @@ class JelevaNephaliasWatcher extends Watcher {
for (StackObject stackObject : game.getStack()) {
if (stackObject instanceof Spell && ((Spell)stackObject).getSourceId().equals(sourceId)) {
Card card = game.getCard(sourceId);
if (!manaSpendToCast.containsValue(card.getZoneChangeCounter())) {
manaSpendToCast.put(new Integer(card.getZoneChangeCounter()), new Integer(((Spell)stackObject).getSpellAbility().getManaCostsToPay().convertedManaCost()));
if (!manaSpendToCast.containsValue(card.getZoneChangeCounter(game))) {
manaSpendToCast.put(new Integer(card.getZoneChangeCounter(game)), new Integer(((Spell)stackObject).getSpellAbility().getManaCostsToPay().convertedManaCost()));
}
}
}

View file

@ -143,7 +143,7 @@ class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) {
MageObject mageObject = source.getSourceObject(game);
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && mageObject == null && new MageObjectReference(permanent).refersTo(mageObject)) {
if (permanent != null && mageObject == null && new MageObjectReference(permanent, game).refersTo(mageObject, game)) {
discard();
return false;
}
@ -190,7 +190,7 @@ class LivingLoreSacrificeEffect extends OneShotEffect {
if (controller != null) {
MageObject mageObject = source.getSourceObject(game);
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && mageObject != null && new MageObjectReference(permanent).refersTo(mageObject)) {
if (permanent != null && mageObject != null && new MageObjectReference(permanent, game).refersTo(mageObject, game)) {
if (permanent.sacrifice(source.getSourceId(), game)) {
UUID exileId = CardUtil.getObjectExileZoneId(game, mageObject);
if (exileId != null) {

View file

@ -130,7 +130,7 @@ class MythRealizedSetPTEffect extends ContinuousEffectImpl {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && new MageObjectReference(source.getSourceObject(game)).refersTo(permanent)) {
if (permanent != null && new MageObjectReference(source.getSourceObject(game), game).refersTo(permanent, game)) {
int amount = permanent.getCounters().getCount(CounterType.LORE);
permanent.getPower().setValue(amount);
permanent.getToughness().setValue(amount);

View file

@ -133,7 +133,7 @@ class GainProtectionFromColorSourceEffect extends GainAbilitySourceEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && new MageObjectReference(permanent).refersTo(source.getSourceObject(game))) {
if (permanent != null && new MageObjectReference(permanent, game).refersTo(source.getSourceObject(game), game)) {
permanent.addAbility(ability, source.getSourceId(), game);
} else {
// the source permanent is no longer on the battlefield, effect can be discarded

View file

@ -112,7 +112,7 @@ class GhastlyConscriptionEffect 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);
if (controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), false, true)) {
game.informPlayers(new StringBuilder(controller.getName())

View file

@ -133,7 +133,7 @@ class JeskaiInfiltratorEffect 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);
if (player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), false, true)) {
game.informPlayers(new StringBuilder(player.getName())

View file

@ -124,7 +124,7 @@ class UnboostCreaturesTargetPlayerEffect extends ContinuousEffectImpl {
super.init(source, game);
if (this.affectedObjectsSet) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), getTargetPointer().getFirst(game, source), game)) {
affectedObjectList.add(new MageObjectReference(creature));
affectedObjectList.add(new MageObjectReference(creature, game));
}
}
}

View file

@ -123,9 +123,9 @@ class SoulflayerEffect extends ContinuousEffectImpl implements SourceEffect {
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
if (objectReference == null || !objectReference.refersTo(permanent)) {
if (objectReference == null || !objectReference.refersTo(permanent, game)) {
abilitiesToAdd = new HashSet<>();
this.objectReference = new MageObjectReference(permanent);
this.objectReference = new MageObjectReference(permanent, game);
String keyString = CardUtil.getCardZoneString("delvedCards", source.getSourceId(), game, true);
List<Card> delvedCards = (List<Card>) game.getState().getValue(keyString);
if (delvedCards != null) {

View file

@ -132,9 +132,9 @@ class JuxtaposeEffect 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));
permanent1.changeControllerId(targetPlayer.getId(), game);
permanent2.changeControllerId(you.getId(), game);
@ -153,7 +153,7 @@ class JuxtaposeEffect 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

@ -137,7 +137,7 @@ class TheWretchedEffect extends OneShotEffect {
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get("BlockedAttackerWatcher");
if (watcher != null) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), game)) {
if (watcher.creatureHasBlockedAttacker(theWretched, creature)
if (watcher.creatureHasBlockedAttacker(theWretched, creature, game)
&& !creature.isRemovedFromCombat()) {
ContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom, source.getControllerId()), new SourceOnBattlefieldControlUnchangedCondition(), "test");
effect.setTargetPointer(new FixedTarget(creature.getId()));

View file

@ -96,7 +96,7 @@ class ScoutsWarningAsThoughEffect extends AsThoughEffectImpl {
watcher = (ScoutsWarningWatcher) game.getState().getWatchers().get("consumeScoutsWarningWatcher", source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher != null && card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
watcher.addScoutsWarningSpell(source.getSourceId(), zoneChangeCounter);
}
}

View file

@ -110,32 +110,32 @@ class AureliaAttacksTriggeredAbility extends TriggeredAbilityImpl {
@Override
public void reset(Game game) {
Card sourceCard = game.getCard(getSourceId());
game.getState().setValue(getValueKey(sourceCard), new Integer(0));
game.getState().setValue(getValueKey(sourceCard, game), new Integer(0));
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId()) ) {
Card sourceCard = game.getCard(getSourceId());
Integer amountAttacks = (Integer) game.getState().getValue(getValueKey(sourceCard));
Integer amountAttacks = (Integer) game.getState().getValue(getValueKey(sourceCard, game));
if (amountAttacks == null || amountAttacks.intValue() < 1) {
if (amountAttacks == null) {
amountAttacks = new Integer(1);
} else {
++amountAttacks;
}
game.getState().setValue(getValueKey(sourceCard), amountAttacks);
game.getState().setValue(getValueKey(sourceCard, game), amountAttacks);
return true;
}
}
return false;
}
protected String getValueKey(Card sourceCard) {
protected String getValueKey(Card sourceCard, Game game) {
if (sourceCard == null) {
return "";
}
return new StringBuilder(this.getId().toString()).append(sourceCard.getZoneChangeCounter()).append("amountAttacks").toString();
return new StringBuilder(this.getId().toString()).append(sourceCard.getZoneChangeCounter(game)).append("amountAttacks").toString();
}
@Override

View file

@ -100,13 +100,13 @@ class CantBeBlockedByTokenEffect extends RestrictionEffect {
public void init(Ability source, Game game) {
affectedObjectsSet = true;
for (Permanent perm: game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
if (affectedObjectList.contains(new MageObjectReference(permanent))) {
if (affectedObjectList.contains(new MageObjectReference(permanent, game))) {
return true;
}
return false;

View file

@ -97,7 +97,7 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl {
quickenWatcher = (QuickenWatcher) game.getState().getWatchers().get("consumeQuickenWatcher", source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (quickenWatcher != null && card != null) {
zoneChangeCounter = card.getZoneChangeCounter();
zoneChangeCounter = card.getZoneChangeCounter(game);
quickenWatcher.addQuickenSpell(source.getSourceId(), zoneChangeCounter);
}
}

View file

@ -100,7 +100,7 @@ class PastInFlamesEffect extends ContinuousEffectImpl {
for (UUID cardId: player.getGraveyard()) {
Card card = game.getCard(cardId);
if (card.getCardType().contains(CardType.INSTANT) || card.getCardType().contains(CardType.SORCERY)) {
affectedObjectList.add(new MageObjectReference(card));
affectedObjectList.add(new MageObjectReference(card, game));
}
}
}

View file

@ -191,7 +191,7 @@ class GodsendExileEffect extends OneShotEffect {
if (creature != null && controller != null && sourcePermanent != null) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
controller.moveCardToExileWithInfo(creature, exileId,
new StringBuilder(sourcePermanent.getName()).append(" (").append(sourcePermanent.getZoneChangeCounter()).append(")").toString()
new StringBuilder(sourcePermanent.getName()).append(" (").append(sourcePermanent.getZoneChangeCounter(game)).append(")").toString()
, source.getSourceId(), game, Zone.BATTLEFIELD);
}

View file

@ -110,15 +110,15 @@ class AshlingThePilgrimEffect extends OneShotEffect {
Object object = game.getState().getValue(source.getSourceId() + "ActivationInfo");
if (object instanceof ActivationInfo) {
info = (ActivationInfo) object;
if (info.turn != game.getTurnNum() || sourcePermanent.getZoneChangeCounter() != info.zoneChangeCounter) {
if (info.turn != game.getTurnNum() || sourcePermanent.getZoneChangeCounter(game) != info.zoneChangeCounter) {
info.turn = game.getTurnNum();
info.zoneChangeCounter = sourcePermanent.getZoneChangeCounter();
info.zoneChangeCounter = sourcePermanent.getZoneChangeCounter(game);
info.activations = 0;
}
} else {
info = new ActivationInfo();
info.turn = game.getTurnNum();
info.zoneChangeCounter = sourcePermanent.getZoneChangeCounter();
info.zoneChangeCounter = sourcePermanent.getZoneChangeCounter(game);
game.getState().setValue(source.getSourceId() + "ActivationInfo", info);
}
info.activations++;

View file

@ -115,7 +115,7 @@ class VengefulPharaohTriggeredAbility extends TriggeredAbilityImpl {
// even if Vengeful Pharaoh is put back into your graveyard before it tries to resolve, as it's a
// different Vengeful Pharaoh than the one that was there before.
MageObjectReference mor = new MageObjectReference(getSourceId(), game);
return mor.refersTo(this.getSourceObject(game));
return mor.refersTo(this.getSourceObject(game), game);
}
@Override

View file

@ -110,7 +110,7 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl {
watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher != null && card != null) {
watcher.setSavageSummoningSpellActive(card);
watcher.setSavageSummoningSpellActive(card, game);
} else {
throw new IllegalArgumentException("Consume Savage watcher could not be found");
}
@ -174,7 +174,7 @@ class SavageSummoningWatcher extends Watcher {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && spell.getCardType().contains(CardType.CREATURE)) {
spellsCastWithSavageSummoning.put(spell.getId(), new HashSet<>(savageSummoningSpells));
String cardKey = new StringBuilder(spell.getCard().getId().toString()).append("_").append(spell.getCard().getZoneChangeCounter()).toString();
String cardKey = new StringBuilder(spell.getCard().getId().toString()).append("_").append(spell.getCard().getZoneChangeCounter(game)).toString();
cardsCastWithSavageSummoning.put(cardKey, new HashSet<>(savageSummoningSpells));
savageSummoningSpells.clear();
}
@ -182,8 +182,8 @@ class SavageSummoningWatcher extends Watcher {
}
}
public void setSavageSummoningSpellActive(Card card) {
String cardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter()).toString();
public void setSavageSummoningSpellActive(Card card, Game game) {
String cardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter(game)).toString();
savageSummoningSpells.add(cardKey);
}
@ -200,8 +200,8 @@ class SavageSummoningWatcher extends Watcher {
return false;
}
public boolean isCardCastWithThisSavageSummoning(Card card, UUID cardId, int zoneChangeCounter) {
String creatureCardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter()-1).toString();
public boolean isCardCastWithThisSavageSummoning(Card card, UUID cardId, int zoneChangeCounter, Game game) {
String creatureCardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter(game)-1).toString();
// add one because card is now gone to battlefield as creature
String cardKey = new StringBuilder(cardId.toString()).append("_").append(zoneChangeCounter).toString();
HashSet<String> savageSpells = (HashSet<String>) cardsCastWithSavageSummoning.get(creatureCardKey);
@ -243,7 +243,7 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl
if (watcher == null || card == null) {
throw new IllegalArgumentException("Consume Savage watcher or card could not be found");
}
this.zoneChangeCounter = card.getZoneChangeCounter();
this.zoneChangeCounter = card.getZoneChangeCounter(game);
}
@Override
@ -300,7 +300,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl {
if (watcher == null || card == null) {
throw new IllegalArgumentException("Consume Savage watcher or card could not be found");
}
this.zoneChangeCounter = card.getZoneChangeCounter();
this.zoneChangeCounter = card.getZoneChangeCounter(game);
}
@Override
@ -327,7 +327,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) {
if ((event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD)) {
Card card = game.getCard(event.getTargetId());
if (card != null && watcher.isCardCastWithThisSavageSummoning(card, source.getSourceId(), zoneChangeCounter)) {
if (card != null && watcher.isCardCastWithThisSavageSummoning(card, source.getSourceId(), zoneChangeCounter, game)) {
return true;
}
}

View file

@ -96,7 +96,7 @@ class PolymorphistsJestEffect extends ContinuousEffectImpl {
super.init(source, game);
if (this.affectedObjectsSet) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, getTargetPointer().getFirst(game, source), game)) {
affectedObjectList.add(new MageObjectReference(permanent));
affectedObjectList.add(new MageObjectReference(permanent, game));
}
}
}

View file

@ -117,7 +117,7 @@ class ScytheOfTheWretchedTriggeredAbility extends TriggeredAbilityImpl {
return false;
}
for (MageObjectReference mor : zoneChange.getTarget().getDealtDamageByThisTurn()) {
if (mor.refersTo(equippedCreature)) {
if (mor.refersTo(equippedCreature, game)) {
setTarget(new FixedTarget(event.getTargetId()));
return true;
}

View file

@ -127,7 +127,7 @@ class JhoiraOfTheGhituSuspendEffect extends OneShotEffect {
if (controller.moveCardToExileWithInfo(card, exileId, "Suspended cards of " + controller.getName(), source.getSourceId(), game, Zone.HAND)) {
card.addCounters(CounterType.TIME.createInstance(4), game);
if (!hasSuspend) {
game.addEffect(new JhoiraGainSuspendEffect(new MageObjectReference(card)), source);
game.addEffect(new JhoiraGainSuspendEffect(new MageObjectReference(card, game)), source);
}
game.informPlayers(controller.getName() + " suspends 4 - " + card.getName());
return true;
@ -160,7 +160,7 @@ class JhoiraGainSuspendEffect extends ContinuousEffectImpl implements SourceEffe
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(mor.getSourceId());
if (card != null && mor.refersTo(card) && game.getState().getZone(card.getId()).equals(Zone.EXILED)) {
if (card != null && mor.refersTo(card, game) && game.getState().getZone(card.getId()).equals(Zone.EXILED)) {
SuspendAbility.addSuspendTemporaryToCard(card, source, game);
} else {
discard();

View file

@ -93,7 +93,7 @@ class BecomesCreatureAllEffect extends ContinuousEffectImpl {
super.init(source, game);
this.affectedObjectsSet = true;
for (Permanent perm: game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}

View file

@ -123,12 +123,12 @@ class RallyTheRighteousBoostEffect extends ContinuousEffectImpl {
super.init(source, game);
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (target != null) {
affectedObjectList.add(new MageObjectReference(target));
affectedObjectList.add(new MageObjectReference(target, game));
ObjectColor color = target.getColor();
target.addPower(2);
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) {
if (!permanent.getId().equals(target.getId()) && permanent.getColor().shares(color)) {
affectedObjectList.add(new MageObjectReference(permanent));
affectedObjectList.add(new MageObjectReference(permanent, game));
}
}
}

View file

@ -108,7 +108,7 @@ class GraveBetrayalTriggeredAbility extends TriggeredAbilityImpl {
if (card != null) {
Effect effect = new GraveBetrayalEffect();
effect.setTargetPointer(new FixedTarget(card.getId()));
Integer zoneChanges = card.getZoneChangeCounter();
Integer zoneChanges = card.getZoneChangeCounter(game);
effect.setValue("zoneChanges", zoneChanges);
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
@ -150,7 +150,7 @@ class GraveBetrayalEffect extends OneShotEffect {
Card card = game.getCard(targetPointer.getFirst(game, source));
if (card != null) {
Integer zoneChanges = (Integer) getValue("zoneChanges");
if (card.getZoneChangeCounter() == zoneChanges) {
if (card.getZoneChangeCounter(game) == zoneChanges) {
Zone currentZone = game.getState().getZone(card.getId());
if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), source.getControllerId())) {
Permanent creature = game.getPermanent(card.getId());

View file

@ -103,7 +103,7 @@ class TrostaniSelesnyasVoiceTriggeredAbility extends TriggeredAbilityImpl {
&& event.getTargetId() != this.getSourceId()) {
Effect effect = this.getEffects().get(0);
effect.setValue("lifeSource", event.getTargetId());
effect.setValue("zoneChangeCounter", permanent.getZoneChangeCounter());
effect.setValue("zoneChangeCounter", permanent.getZoneChangeCounter(game));
return true;
}
}
@ -142,7 +142,7 @@ class TrostaniSelesnyasVoiceEffect extends OneShotEffect {
UUID creatureId = (UUID) getValue("lifeSource");
Integer zoneChangeCounter = (Integer) getValue("zoneChangeCounter");
Permanent creature = game.getPermanent(creatureId);
if (creature == null || creature.getZoneChangeCounter() != zoneChangeCounter) {
if (creature == null || creature.getZoneChangeCounter(game) != zoneChangeCounter) {
creature = (Permanent) game.getLastKnownInformation(creatureId, Zone.BATTLEFIELD, zoneChangeCounter);
}
if (creature != null) {

View file

@ -131,7 +131,7 @@ class LeoninArbiterIgnoreEffect extends OneShotEffect {
String key = permanent.getId() + keyString;
// Using a Map.Entry since there is no pair class
long zoneChangeCount = permanent.getZoneChangeCounter();
long zoneChangeCount = permanent.getZoneChangeCounter(game);
long turnNum = game.getTurnNum();
Long activationState = zoneChangeCount << 32 | turnNum & 0xFFFFFFFFL;
@ -170,7 +170,7 @@ class LeoninArbiterCantSearchEffect extends ContinuousRuleModifyingEffectImpl {
String key = permanent.getId() + keyString;
Map.Entry<Long, Set<UUID>> turnIgnoringPlayersPair = (Map.Entry<Long, Set<UUID>>) game.getState().getValue(key);
if (turnIgnoringPlayersPair != null) {
long zoneChangeCount = permanent.getZoneChangeCounter();
long zoneChangeCount = permanent.getZoneChangeCounter(game);
long turnNum = game.getTurnNum();
Long activationState = zoneChangeCount << 32 | turnNum & 0xFFFFFFFFL;
if (activationState.equals(turnIgnoringPlayersPair.getKey())) {

View file

@ -131,7 +131,7 @@ class SkeletonizeDelayedTriggeredAbility extends DelayedTriggeredAbility {
if (zce.isDiesEvent()) {
DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", this.getSourceId());
if (watcher != null) {
return watcher.wasDamaged(zce.getTarget());
return watcher.wasDamaged(zce.getTarget(), game);
}
}
}

View file

@ -96,7 +96,7 @@ class MarchOfTheMachinesEffect extends ContinuousEffectImpl {
affectedObjectList.clear();
for(Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)){
if(permanent != null){
affectedObjectList.add(new MageObjectReference(permanent));
affectedObjectList.add(new MageObjectReference(permanent, game));
permanent.getCardType().add(CardType.CREATURE);
}
}

View file

@ -120,7 +120,7 @@ class TimeToFeedTextEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (creature != null) {
DelayedTriggeredAbility ability = new TimeToFeedDiesTriggeredAbility(creature.getId(), creature.getZoneChangeCounter());
DelayedTriggeredAbility ability = new TimeToFeedDiesTriggeredAbility(creature.getId(), creature.getZoneChangeCounter(game));
new CreateDelayedTriggeredAbilityEffect(ability, false).apply(game, source);
}
@ -155,7 +155,7 @@ class TimeToFeedDiesTriggeredAbility extends DelayedTriggeredAbility {
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && ((ZoneChangeEvent)event).isDiesEvent()) {
if (event.getTargetId().equals(watchedCreatureId)) {
Permanent creature = (Permanent) game.getLastKnownInformation(watchedCreatureId, Zone.BATTLEFIELD);
if (creature.getZoneChangeCounter() == this.zoneChangeCounter) {
if (creature.getZoneChangeCounter(game) == this.zoneChangeCounter) {
return true;
}
}

View file

@ -127,7 +127,7 @@ class TritonTacticsUntapTargetEffect extends OneShotEffect {
} else {
targetMap = new HashMap<>();
}
targetMap.put(new Integer(game.getCard(source.getSourceId()).getZoneChangeCounter()), targets);
targetMap.put(new Integer(game.getCard(source.getSourceId()).getZoneChangeCounter(game)), targets);
if (object == null) {
game.getState().setValue("targets" + source.getSourceId().toString(), targetMap);
}

View file

@ -97,7 +97,7 @@ class SuddenSpoilingEffect extends ContinuousEffectImpl {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player != null) {
for (Permanent perm: game.getState().getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game)) {
affectedObjectList.add(new MageObjectReference(perm));
affectedObjectList.add(new MageObjectReference(perm, game));
}
}
}
@ -107,7 +107,7 @@ class SuddenSpoilingEffect extends ContinuousEffectImpl {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player != null) {
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game)) {
if (affectedObjectList.contains(new MageObjectReference(permanent))) {
if (affectedObjectList.contains(new MageObjectReference(permanent, game))) {
switch (layer) {
case AbilityAddingRemovingEffects_6:
permanent.removeAllAbilities(source.getSourceId(), game);

View file

@ -137,7 +137,7 @@ class DiabolicServitudeCreatureDiesTriggeredAbility extends TriggeredAbilityImpl
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && ((ZoneChangeEvent)event).isDiesEvent()) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Object object = game.getState().getValue(getSourceId().toString() + "returnedCreature");
if ((object instanceof MageObjectReference) && ((MageObjectReference)object).refersTo(zEvent.getTarget())) {
if ((object instanceof MageObjectReference) && ((MageObjectReference)object).refersTo(zEvent.getTarget(), game)) {
return true;
}
}

View file

@ -107,7 +107,7 @@ class MarshCasualtiesEffect extends ContinuousEffectImpl {
super.init(source, game);
if (this.affectedObjectsSet) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getFirstTarget(), game)) {
affectedObjectList.add(new MageObjectReference(creature));
affectedObjectList.add(new MageObjectReference(creature, game));
}
}
}

View file

@ -0,0 +1,173 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author BetaSteward
*/
public class KickerTest extends CardTestPlayerBase {
/**
* 702.32. Kicker
* 702.32a Kicker is a static ability that functions while the spell with kicker is on the stack. Kicker
* [cost] means You may pay an additional [cost] as you cast this spell. Paying a spells kicker
* cost(s) follows the rules for paying additional costs in rules 601.2b and 601.2eg.
* 702.32b The phrase Kicker [cost 1] and/or [cost 2] means the same thing as Kicker [cost 1],
* kicker [cost 2].
* 702.32c Multikicker is a variant of the kicker ability. Multikicker [cost] means You may pay an
* additional [cost] any number of times as you cast this spell. A multikicker cost is a kicker cost.
* 702.32d If a spells controller declares the intention to pay any of that spells kicker costs, that spell
* has been kicked. If a spell has two kicker costs or has multikicker, it may be kicked multiple
* times. See rule 601.2b.
* 702.32e Objects with kicker or multikicker have additional abilities that specify what happens if
* they are kicked. These abilities are linked to the kicker or multikicker abilities printed on that
* object: they can refer only to those specific kicker or multikicker abilities. See rule 607, Linked
* Abilities.
* 702.32f Objects with more than one kicker cost have abilities that each correspond to a specific
* kicker cost. They contain the phrases if it was kicked with its [A] kicker and if it was kicked
* with its [B] kicker, where A and B are the first and second kicker costs listed on the card,
* respectively. Each of those abilities is linked to the appropriate kicker ability.
* 702.32g If part of a spells ability has its effect only if that spell was kicked, and that part of the
* ability includes any targets, the spells controller chooses those targets only if that spell was
* kicked. Otherwise, the spell is cast as if it did not have those targets. See rule 601.2c.
*
*/
/**
* AEther Figment
* Creature Illusion 1/1, 1U (2)
* Kicker {3} (You may pay an additional {3} as you cast this spell.)
* AEther Figment can't be blocked.
* If AEther Figment was kicked, it enters the battlefield with two +1/+1 counters on it.
*
*/
@Test
public void testUseKicker() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.HAND, playerA, "AEther Figment");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "AEther Figment");
setChoice(playerA, "Yes");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "AEther Figment", 1);
assertCounterCount("AEther Figment", CounterType.P1P1, 2);
assertPowerToughness(playerA, "AEther Figment", 3, 3);
}
@Test
public void testDontUseKicker() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.HAND, playerA, "AEther Figment");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "AEther Figment");
setChoice(playerA, "No");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "AEther Figment", 1);
assertCounterCount("AEther Figment", CounterType.P1P1, 0);
assertPowerToughness(playerA, "AEther Figment", 1, 1);
}
/**
* Apex Hawks
* Creature Bird 2/2, 2W (3)
* Multikicker {1}{W} (You may pay an additional {1}{W} any number of times as you cast this spell.)
* Flying
* Apex Hawks enters the battlefield with a +1/+1 counter on it for each time it was kicked.
*
*/
@Test
public void testUseMultikickerOnce() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.HAND, playerA, "Apex Hawks");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Apex Hawks");
setChoice(playerA, "Yes");
setChoice(playerA, "No");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Apex Hawks", 1);
assertCounterCount("Apex Hawks", CounterType.P1P1, 1);
assertPowerToughness(playerA, "Apex Hawks", 3, 3);
}
@Test
public void testUseMultikickerTwice() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 7);
addCard(Zone.HAND, playerA, "Apex Hawks");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Apex Hawks");
setChoice(playerA, "Yes");
setChoice(playerA, "Yes");
setChoice(playerA, "No");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Apex Hawks", 1);
assertCounterCount("Apex Hawks", CounterType.P1P1, 2);
assertPowerToughness(playerA, "Apex Hawks", 4, 4);
}
@Test
public void testDontUseMultikicker() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 7);
addCard(Zone.HAND, playerA, "Apex Hawks");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Apex Hawks");
setChoice(playerA, "No");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Apex Hawks", 1);
assertCounterCount("Apex Hawks", CounterType.P1P1, 0);
assertPowerToughness(playerA, "Apex Hawks", 2, 2);
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author BetaSteward
*/
public class StormTest extends CardTestPlayerBase {
/**
* 702.39. Storm
* 702.39a Storm is a triggered ability that functions on the stack. Storm means When you cast this
* spell, put a copy of it onto the stack for each other spell that was cast before it this turn. If the
* spell has any targets, you may choose new targets for any of the copies.
* 702.39b If a spell has multiple instances of storm, each triggers separately.
*
*/
/**
* Grapeshot
* Sorcery, 1R (2)
* Grapeshot deals 1 damage to target creature or player.
* Storm (When you cast this spell, copy it for each spell cast before it
* this turn. You may choose new targets for the copies.)
*
*/
@Test
public void testStorm1x() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.HAND, playerA, "Grapeshot");
addCard(Zone.HAND, playerA, "Lightning Bolt");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerB, 15);
}
@Test
public void testStorm2x() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
addCard(Zone.HAND, playerA, "Grapeshot");
addCard(Zone.HAND, playerA, "Lightning Bolt", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerB, 11);
}
@Test
public void testStorm3x() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
addCard(Zone.HAND, playerA, "Grapeshot");
addCard(Zone.HAND, playerA, "Lightning Bolt", 3);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerB, 7);
}
@Test
public void testStorm4x() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
addCard(Zone.HAND, playerA, "Grapeshot");
addCard(Zone.HAND, playerA, "Lightning Bolt", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerB, 3);
}
@Test
public void testNoStorm() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.HAND, playerA, "Grapeshot");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerB, 19);
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.continuous;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author BetaSteward
*/
public class MarchOfTheMachinesTest extends CardTestPlayerBase {
/**
* March of the Machines
* Enchantment, 3U (4)
* Each noncreature artifact is an artifact creature with power and toughness
* each equal to its converted mana cost. (Equipment that's a creature can't
* equip a creature.)
*
*/
/**
* Abzan Banner
* Artifact, 3 (3)
* {T}: Add {W}, {B}, or {G} to your mana pool.
* {W}{B}{G}, {T}, Sacrifice Abzan Banner: Draw a card.
*/
@Test
public void testNonCreatureArtifactsBecomeCreatures() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerA, "Abzan Banner");
addCard(Zone.BATTLEFIELD, playerA, "Alloy Myr");
addCard(Zone.HAND, playerA, "March of the Machines");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of the Machines");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Alloy Myr", 2, 2);
assertPermanentCount(playerA, "Abzan Banner", 1);
assertPowerToughness(playerA, "Abzan Banner", 3, 3);
assertType("Abzan Banner", CardType.CREATURE, true);
}
@Test
public void testArtifactsRevertBack() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerA, "Abzan Banner");
addCard(Zone.HAND, playerA, "March of the Machines");
addCard(Zone.HAND, playerB, "Disenchant");
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of the Machines");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "March of the Machines");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Abzan Banner", 1);
assertType("Abzan Banner", CardType.CREATURE, false);
}
@Test
public void testEquipmentDetaches() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
addCard(Zone.BATTLEFIELD, playerA, "Avacyn's Collar");
addCard(Zone.BATTLEFIELD, playerA, "Ornithopter");
addCard(Zone.HAND, playerA, "March of the Machines");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Ornithopter");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "March of the Machines");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Ornithopter", 1);
assertPowerToughness(playerA, "Ornithopter", 0, 2);
assertPermanentCount(playerA, "Avacyn's Collar", 1);
assertPowerToughness(playerA, "Avacyn's Collar", 1, 1);
assertType("Avacyn's Collar", CardType.CREATURE, true);
}
@Test
public void testZeroCostIsDestroyed() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerA, "Accorder's Shield");
addCard(Zone.HAND, playerA, "March of the Machines");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of the Machines");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Accorder's Shield", 0);
assertGraveyardCount(playerA, "Accorder's Shield", 1);
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.dynamicvalue;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author BetaSteward
*/
public class SweepTest extends CardTestPlayerBase {
/**
* Plow Through Reito
* 1W
* Instant -- Arcane
* Sweep -- Return any number of Plains you control to their owner's hand.
* Target creature gets +1/+1 until end of turn for each Plains returned this way.
*
*/
@Test
public void testSweep1x() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
addCard(Zone.HAND, playerA, "Plow Through Reito");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito");
addTarget(playerA, "Plains");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Raging Goblin", 1);
assertPermanentCount(playerA, "Plains", 4);
assertPowerToughness(playerA, "Raging Goblin", 2, 2);
}
@Test
public void testSweep2x() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
addCard(Zone.HAND, playerA, "Plow Through Reito");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito");
addTarget(playerA, "Plains^Plains");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Raging Goblin", 1);
assertPermanentCount(playerA, "Plains", 3);
assertPowerToughness(playerA, "Raging Goblin", 3, 3);
}
@Test
public void testSweep3x() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
addCard(Zone.HAND, playerA, "Plow Through Reito");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito");
addTarget(playerA, "Plains^Plains^Plains");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Raging Goblin", 1);
assertPermanentCount(playerA, "Plains", 2);
assertPowerToughness(playerA, "Raging Goblin", 4, 4);
}
@Test
public void testSweep0x() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
addCard(Zone.HAND, playerA, "Plow Through Reito");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Raging Goblin", 1);
assertPermanentCount(playerA, "Plains", 5);
assertPowerToughness(playerA, "Raging Goblin", 1, 1);
}
}

View file

@ -11,6 +11,28 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*/
public class HuntmasterOfTheFellsTest extends CardTestPlayerBase {
/**
* Huntmaster of the Fells
* Creature Human Werewolf 2/2, 2RG (4)
* Whenever this creature enters the battlefield or transforms into Huntmaster
* of the Fells, put a 2/2 green Wolf creature token onto the battlefield and
* you gain 2 life.
* At the beginning of each upkeep, if no spells were cast last turn, transform
* Huntmaster of the Fells.
*
*/
/**
* Ravager of the Fells
* Creature Werewolf 4/4
* Trample
* Whenever this creature transforms into Ravager of the Fells, it deals 2
* damage to target opponent and 2 damage to up to one target creature that
* player controls.
* At the beginning of each upkeep, if a player cast two or more spells last
* turn, transform Ravager of the Fells.
*/
@Test
public void testCard() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);

View file

@ -31,6 +31,7 @@ import java.io.FilenameFilter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.mage.test.serverside.base.MageTestPlayerBase.currentGame;
/**
* Base class for all tests.
@ -259,7 +260,7 @@ public abstract class MageTestBase {
Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card != null) {
if (gameZone.equals(Zone.BATTLEFIELD)) {
PermanentCard p = new PermanentCard(card, null);
PermanentCard p = new PermanentCard(card, null, currentGame);
p.setTapped(tapped);
perms.add(p);
} else {

View file

@ -239,7 +239,7 @@ public abstract class MageTestPlayerBase {
Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card != null) {
if (gameZone.equals(Zone.BATTLEFIELD)) {
PermanentCard p = new PermanentCard(card, null);
PermanentCard p = new PermanentCard(card, null, currentGame);
p.setTapped(tapped);
perms.add(p);
} else {

View file

@ -124,7 +124,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP
if (card == null) {
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName);
}
PermanentCard p = new PermanentCard(card, null);
PermanentCard p = new PermanentCard(card, null, currentGame);
p.setTapped(tapped);
if (player.equals(playerA)) {
battlefieldCardsA.add(p);

View file

@ -37,6 +37,7 @@ import java.util.UUID;
public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implements CardTestAPI {
static {
// CardScanner.scanned = true;
CardScanner.scan();
}
@ -168,7 +169,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
if (card == null) {
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName);
}
PermanentCard p = new PermanentCard(card, null);
PermanentCard p = new PermanentCard(card, null, currentGame);
p.setTapped(tapped);
getBattlefieldCards(player).add(p);
}
@ -511,6 +512,28 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
*
* @param cardName Name of the permanent that should be checked.
* @param type A type to test for
* @param flag true if creature should have type, false if it should not
*/
public void assertType(String cardName, CardType type, boolean flag) throws AssertionError {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
found = permanent;
break;
}
}
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertTrue("(Battlefield) card type not found (" + cardName + ":" + type + ")", (found.getCardType().contains(type) == flag));
}
/**
* Assert whether a permanent is a specified type
*
* @param cardName Name of the permanent that should be checked.
* @param type A type to test for
* @param subType a subtype to test for
*/
public void assertType(String cardName, CardType type, String subType) throws AssertionError {

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;
}
}

Some files were not shown because too many files have changed in this diff Show more