prevent direct access of Player->counters ; some cleanup on counter removal effects ; implement [MH3] Izzet Generatorium (#12314)

This commit is contained in:
Susucre 2024-05-29 22:34:54 +02:00 committed by GitHub
parent 8d02ff14ff
commit 20b7a115da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
110 changed files with 895 additions and 646 deletions

View file

@ -16,8 +16,6 @@ import mage.components.ImagePanelStyle;
import mage.constants.CardType; import mage.constants.CardType;
import static mage.constants.Constants.*; import static mage.constants.Constants.*;
import mage.constants.ManaType; import mage.constants.ManaType;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.designations.DesignationType; import mage.designations.DesignationType;
import mage.utils.timer.PriorityTimer; import mage.utils.timer.PriorityTimer;
import mage.view.*; import mage.view.*;
@ -186,6 +184,18 @@ public class PlayerPanelExt extends javax.swing.JPanel {
return false; return false;
} }
// Not the most optimized, but we just query a few counterName here.
// More optimized would use a Map<String, CounterView>
private static int counterOfName(PlayerView player, String name) {
return player
.getCounters()
.stream()
.filter(counter -> counter.getName().equals(name))
.map(CounterView::getCount)
.findFirst()
.orElse(0);
}
public void update(GameView game, PlayerView player, Set<UUID> possibleTargets) { public void update(GameView game, PlayerView player, Set<UUID> possibleTargets) {
this.player = player; this.player = player;
int pastLife = player.getLife(); int pastLife = player.getLife();
@ -226,10 +236,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
changedFontLife = false; changedFontLife = false;
} }
setTextForLabel("life", lifeLabel, life, playerLife, true); setTextForLabel("life", lifeLabel, life, playerLife, true);
setTextForLabel("poison", poisonLabel, poison, player.getCounters().getCount(CounterType.POISON), false); setTextForLabel("poison", poisonLabel, poison, counterOfName(player, "poison"), false);
setTextForLabel("energy", energyLabel, energy, player.getCounters().getCount(CounterType.ENERGY), false); setTextForLabel("energy", energyLabel, energy, counterOfName(player, "energy"), false);
setTextForLabel("experience", experienceLabel, experience, player.getCounters().getCount(CounterType.EXPERIENCE), false); setTextForLabel("experience", experienceLabel, experience, counterOfName(player, "experience"), false);
setTextForLabel("rad", radLabel, rad, player.getCounters().getCount(CounterType.RAD), false); setTextForLabel("rad", radLabel, rad, counterOfName(player, "rad"), false);
setTextForLabel("hand zone", handLabel, hand, player.getHandCount(), true); setTextForLabel("hand zone", handLabel, hand, player.getHandCount(), true);
int libraryCards = player.getLibraryCount(); int libraryCards = player.getLibraryCount();
if (libraryCards > 99) { if (libraryCards > 99) {
@ -417,7 +427,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
} }
// counters // counters
for (Counter counter : player.getCounters().values()) { for (CounterView counter : player.getCounters()) {
tooltipText.append("<br/>").append(counter.getName()).append(" counters: ").append(counter.getCount()); tooltipText.append("<br/>").append(counter.getName()).append(" counters: ").append(counter.getCount());
} }

View file

@ -1,7 +1,7 @@
package mage.view; package mage.view;
import mage.cards.Card; import mage.cards.Card;
import mage.counters.Counters; import mage.counters.Counter;
import mage.designations.Designation; import mage.designations.Designation;
import mage.game.ExileZone; import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
@ -27,7 +27,7 @@ public class PlayerView implements Serializable {
private final boolean controlled; // gui: player is current user private final boolean controlled; // gui: player is current user
private final boolean isHuman; // human or computer private final boolean isHuman; // human or computer
private final int life; private final int life;
private final Counters counters; private final List<CounterView> counters;
private final int wins; private final int wins;
private final int winsNeeded; private final int winsNeeded;
private final int libraryCount; private final int libraryCount;
@ -64,7 +64,6 @@ public class PlayerView implements Serializable {
this.controlled = player.getId().equals(createdForPlayerId); this.controlled = player.getId().equals(createdForPlayerId);
this.isHuman = player.isHuman(); this.isHuman = player.isHuman();
this.life = player.getLife(); this.life = player.getLife();
this.counters = player.getCounters();
this.wins = player.getMatchPlayer().getWins(); this.wins = player.getMatchPlayer().getWins();
this.winsNeeded = player.getMatchPlayer().getWinsNeeded(); this.winsNeeded = player.getMatchPlayer().getWinsNeeded();
this.libraryCount = player.getLibrary().size(); this.libraryCount = player.getLibrary().size();
@ -158,6 +157,10 @@ public class PlayerView implements Serializable {
for (Designation designation : player.getDesignations()) { for (Designation designation : player.getDesignations()) {
this.designationNames.add(designation.getName()); this.designationNames.add(designation.getName());
} }
this.counters = new ArrayList<>();
for (Counter counter : player.getCountersAsCopy().values()) {
counters.add(new CounterView(counter));
}
} }
private boolean showInBattlefield(Permanent permanent, GameState state) { private boolean showInBattlefield(Permanent permanent, GameState state) {
@ -187,7 +190,7 @@ public class PlayerView implements Serializable {
return this.life; return this.life;
} }
public Counters getCounters() { public List<CounterView> getCounters() {
return this.counters; return this.counters;
} }

View file

@ -57,7 +57,7 @@ public final class CombatUtil {
return blockableAttackers; return blockableAttackers;
} }
if (sumPoisonDamage(attackersThatWontBeBlocked, defender) >= 10 - defender.getCounters().getCount(CounterType.POISON)) { if (sumPoisonDamage(attackersThatWontBeBlocked, defender) >= 10 - defender.getCountersCount(CounterType.POISON)) {
blockableAttackers.addAll(unblockableAttackers); blockableAttackers.addAll(unblockableAttackers);
return blockableAttackers; return blockableAttackers;
} }

View file

@ -9,8 +9,6 @@ import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.Counter;
import mage.counters.Counters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken; import mage.game.permanent.PermanentToken;
@ -67,13 +65,7 @@ class AetherSnapEffect extends OneShotEffect {
if (permanent instanceof PermanentToken) { if (permanent instanceof PermanentToken) {
tokens.add(permanent); tokens.add(permanent);
} }
if (permanent.getCounters(game).isEmpty()) { permanent.removeAllCounters(source, game);
continue;
}
Counters counters = permanent.getCounters(game).copy();
for (Counter counter : counters.values()) {
permanent.removeCounters(counter, source, game);
}
} }
controller.moveCards(tokens, Zone.EXILED, source, game); controller.moveCards(tokens, Zone.EXILED, source, game);
return true; return true;

View file

@ -1,10 +1,6 @@
package mage.cards.a; package mage.cards.a;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -22,6 +18,7 @@ import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.counters.Counters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -29,8 +26,11 @@ import mage.game.permanent.token.ServoToken;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetPermanentOrPlayer; import mage.target.common.TargetPermanentOrPlayer;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
/** /**
*
* @author emerald000 * @author emerald000
*/ */
public final class AnimationModule extends CardImpl { public final class AnimationModule extends CardImpl {
@ -148,22 +148,23 @@ class AnimationModuleEffect extends OneShotEffect {
} else { } else {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player != null) { if (player != null) {
if (!player.getCounters().isEmpty()) { Counters counters = player.getCountersAsCopy();
if (player.getCounters().size() == 1) { if (!counters.isEmpty()) {
for (Counter counter : player.getCounters().values()) { if (counters.size() == 1) {
for (Counter counter : counters.values()) {
Counter newCounter = new Counter(counter.getName()); Counter newCounter = new Counter(counter.getName());
player.addCounters(newCounter, source.getControllerId(), source, game); player.addCounters(newCounter, source.getControllerId(), source, game);
} }
} else { } else {
Choice choice = new ChoiceImpl(true); Choice choice = new ChoiceImpl(true);
Set<String> choices = new LinkedHashSet<>(); Set<String> choices = new LinkedHashSet<>();
for (Counter counter : player.getCounters().values()) { for (Counter counter : counters.values()) {
choices.add(counter.getName()); choices.add(counter.getName());
} }
choice.setChoices(choices); choice.setChoices(choices);
choice.setMessage("Choose a counter"); choice.setMessage("Choose a counter");
if (controller.choose(Outcome.Benefit, choice, game)) { if (controller.choose(Outcome.Benefit, choice, game)) {
for (Counter counter : player.getCounters().values()) { for (Counter counter : counters.values()) {
if (counter.getName().equals(choice.getChoice())) { if (counter.getName().equals(choice.getChoice())) {
Counter newCounter = new Counter(counter.getName()); Counter newCounter = new Counter(counter.getName());
player.addCounters(newCounter, source.getControllerId(), source, game); player.addCounters(newCounter, source.getControllerId(), source, game);

View file

@ -1,9 +1,5 @@
package mage.cards.a; package mage.cards.a;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -18,6 +14,10 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
@ -68,8 +68,7 @@ class AnointWithAfflictionEffect extends OneShotEffect {
|| Optional || Optional
.ofNullable(game.getPlayer(permanent.getControllerId())) .ofNullable(game.getPlayer(permanent.getControllerId()))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(Player::getCounters) .map(p -> p.getCountersCount(CounterType.POISON) >= 3)
.map(counters -> counters.getCount(CounterType.POISON) >= 3)
.orElse(false)) .orElse(false))
&& player.moveCards(permanent, Zone.EXILED, source, game); && player.moveCards(permanent, Zone.EXILED, source, game);
} }

View file

@ -1,7 +1,6 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
@ -20,8 +19,9 @@ import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author Plopman * @author Plopman
*/ */
public final class Anthroplasm extends CardImpl { public final class Anthroplasm extends CardImpl {
@ -73,7 +73,7 @@ class AnthroplasmEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) { if (permanent != null) {
//Remove all +1/+1 counters //Remove all +1/+1 counters
permanent.removeCounters(permanent.getCounters(game).get(CounterType.P1P1.getName()), source, game); permanent.removeAllCounters(CounterType.P1P1.getName(), source, game);
//put X +1/+1 counters //put X +1/+1 counters
permanent.addCounters(CounterType.P1P1.createInstance(source.getManaCostsToPay().getX()), source.getControllerId(), source, game); permanent.addCounters(CounterType.P1P1.createInstance(source.getManaCostsToPay().getX()), source.getControllerId(), source, game);
return true; return true;

View file

@ -75,14 +75,11 @@ class AshlingThePilgrimEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null) { if (sourcePermanent == null) {
int counters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1);
if (counters < 1) {
return false; return false;
} }
sourcePermanent.removeCounters(CounterType.P1P1.createInstance(counters), source, game); int amountRemoved = sourcePermanent.removeAllCounters(CounterType.P1P1.getName(), source, game);
return new DamageEverythingEffect(counters, StaticFilters.FILTER_PERMANENT_CREATURE).apply(game, source); new DamageEverythingEffect(amountRemoved, StaticFilters.FILTER_PERMANENT_CREATURE).apply(game, source);
}
return true; return true;
} }
} }

View file

@ -123,10 +123,7 @@ public final class Aurification extends CardImpl {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game)) {
if (permanent != null) { if (permanent != null) {
int numToRemove = permanent.getCounters(game).getCount(CounterType.GOLD); permanent.removeAllCounters(CounterType.GOLD.getName(), source, game);
if (numToRemove > 0) {
permanent.removeCounters(CounterType.GOLD.getName(), numToRemove, source, game);
}
} }
} }
return true; return true;

View file

@ -21,7 +21,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author Susucr * @author Susucr
*/ */
public final class BewitchingLeechcraft extends CardImpl { public final class BewitchingLeechcraft extends CardImpl {
@ -84,13 +83,15 @@ class BewitchingLeechcraftReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent permanentUntapping = game.getPermanent(source.getSourceId()); Permanent permanentUntapping = game.getPermanent(source.getSourceId());
if(!applies(event,source,game)){ if (!applies(event, source, game)) {
return false; return false;
} }
int amountBefore = permanentUntapping.getCounters(game).getCount(CounterType.P1P1);
permanentUntapping.removeCounters(CounterType.P1P1.getName(), 1, source, game);
int amountAfter = permanentUntapping.getCounters(game).getCount(CounterType.P1P1);
// If we could not remove a counter, we are replacing the UNTAP event. // If we could not remove a counter, we are replacing the UNTAP event.
// If we could remove a counter, we are not replacing the UNTAP, just adding to it. // If we could remove a counter, we are not replacing the UNTAP, just adding to it.
return !permanentUntapping.getCounters(game).removeCounter(CounterType.P1P1, 1); return amountBefore < amountAfter;
} }
@Override @Override

View file

@ -3,21 +3,16 @@ package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
@ -36,7 +31,7 @@ public final class BlitzLeech extends CardImpl {
// When Blitz Leech enters the battlefield, target creature an opponent controls gets -2/-2 until end of turn. Remove all counters from that creature. // When Blitz Leech enters the battlefield, target creature an opponent controls gets -2/-2 until end of turn. Remove all counters from that creature.
Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2)); Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2));
ability.addEffect(new BlitzLeechEffect()); ability.addEffect(new RemoveAllCountersPermanentTargetEffect().setText("Remove all counters from that creature"));
ability.addTarget(new TargetOpponentsCreaturePermanent()); ability.addTarget(new TargetOpponentsCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }
@ -50,35 +45,3 @@ public final class BlitzLeech extends CardImpl {
return new BlitzLeech(this); return new BlitzLeech(this);
} }
} }
class BlitzLeechEffect extends OneShotEffect {
BlitzLeechEffect() {
super(Outcome.Benefit);
staticText = "Remove all counters from that creature.";
}
private BlitzLeechEffect(final BlitzLeechEffect effect) {
super(effect);
}
@Override
public BlitzLeechEffect copy() {
return new BlitzLeechEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent == null) {
return false;
}
Set<String> counterTypes = permanent
.getCounters(game)
.keySet()
.stream()
.collect(Collectors.toSet());
counterTypes.forEach(permanent.getCounters(game)::removeAllCounters);
return true;
}
}

View file

@ -122,7 +122,7 @@ class BombSquadDamgeEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (creature != null) { if (creature != null) {
creature.removeCounters(CounterType.FUSE.getName(), creature.getCounters(game).getCount(CounterType.FUSE), source, game); creature.removeAllCounters(CounterType.FUSE.getName(), source, game);
creature.destroy(source, game, false); creature.destroy(source, game, false);
} }
if (creature == null) { if (creature == null) {

View file

@ -1,7 +1,6 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility; import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility;
@ -17,8 +16,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class BountyOfTheLuxa extends CardImpl { public final class BountyOfTheLuxa extends CardImpl {
@ -64,30 +64,26 @@ class BountyOfTheLuxaEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent bountyOfLuxa = game.getPermanent(source.getSourceId());
if (bountyOfLuxa != null && bountyOfLuxa.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()) {
bountyOfLuxa = null;
}
if (controller == null) { if (controller == null) {
return false; return false;
} }
Permanent bountyOfLuxa = source.getSourcePermanentIfItStillExists(game);
if (bountyOfLuxa != null if (bountyOfLuxa == null) {
&& bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) { // No flood counters will be removed. Only the draw part of the effect will apply.
bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game); controller.drawCards(1, source, game);
if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) { return true;
}
int amountRemoved = bountyOfLuxa.removeAllCounters(CounterType.FLOOD.getName(), source, game);
if (amountRemoved == 0) {
new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source);
controller.drawCards(1, source, game);
} else {
Mana manaToAdd = new Mana(); Mana manaToAdd = new Mana();
manaToAdd.increaseColorless(); manaToAdd.increaseColorless();
manaToAdd.increaseGreen(); manaToAdd.increaseGreen();
manaToAdd.increaseBlue(); manaToAdd.increaseBlue();
controller.getManaPool().addMana(manaToAdd, game, source); controller.getManaPool().addMana(manaToAdd, game, source);
} }
} else {
if (bountyOfLuxa != null) {
new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source);
}
controller.drawCards(1, source, game);
}
return true; return true;
} }

View file

@ -1,7 +1,5 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
@ -18,8 +16,9 @@ import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetSpell; import mage.target.TargetSpell;
import java.util.UUID;
/** /**
*
* @author @stwalsh4118 * @author @stwalsh4118
*/ */
public final class BringTheEnding extends CardImpl { public final class BringTheEnding extends CardImpl {
@ -70,7 +69,7 @@ class BringTheEndingCounterEffect extends OneShotEffect {
UUID controllerId = game.getControllerId(targetId); UUID controllerId = game.getControllerId(targetId);
Player player = game.getPlayer(controllerId); Player player = game.getPlayer(controllerId);
if (player != null && player.getCounters().getCount(CounterType.POISON) >= 3) { if (player != null && player.getCountersCount(CounterType.POISON) >= 3) {
hardCounterEffect.setTargetPointer(this.getTargetPointer().copy()); hardCounterEffect.setTargetPointer(this.getTargetPointer().copy());
return hardCounterEffect.apply(game, source); return hardCounterEffect.apply(game, source);
} else { } else {

View file

@ -1,7 +1,5 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
@ -18,18 +16,15 @@ import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.common.FilterAttackingOrBlockingCreature;
import mage.game.Game; import mage.game.Game;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author zeffirojoe * @author zeffirojoe
*/ */
public final class CattiBrieOfMithralHall extends CardImpl { public final class CattiBrieOfMithralHall extends CardImpl {
@ -42,7 +37,7 @@ public final class CattiBrieOfMithralHall extends CardImpl {
} }
public CattiBrieOfMithralHall(UUID ownerId, CardSetInfo setInfo) { public CattiBrieOfMithralHall(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{G}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}");
this.supertype.add(SuperType.LEGENDARY); this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
@ -56,15 +51,12 @@ public final class CattiBrieOfMithralHall extends CardImpl {
// Reach // Reach
this.addAbility(ReachAbility.getInstance()); this.addAbility(ReachAbility.getInstance());
// Whenever Catti-brie of Mithral Hall attacks, put a +1/+1 counter on it for // Whenever Catti-brie of Mithral Hall attacks, put a +1/+1 counter on it for each Equipment attached to it.
// each Equipment attached to it.
EquipmentAttachedCount amount = new EquipmentAttachedCount(); EquipmentAttachedCount amount = new EquipmentAttachedCount();
this.addAbility(new AttacksTriggeredAbility( this.addAbility(new AttacksTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(), amount, false).setText("put a +1/+1 counter on it for each Equipment attached to it"))); new AddCountersSourceEffect(CounterType.P1P1.createInstance(), amount, false).setText("put a +1/+1 counter on it for each Equipment attached to it")));
// {1}, Remove all +1/+1 counters from Catti-brie: It deals X damage to target // {1}, Remove all +1/+1 counters from Catti-brie: It deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way.
// attacking or blocking creature an opponent controls, where X is the number of
// counters removed this way.
Ability damageAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, Ability damageAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new DamageTargetEffect(CattiBrieRemovedCounterValue.instance).setText("it deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way"), new ManaCostsImpl<>("{1}")); new DamageTargetEffect(CattiBrieRemovedCounterValue.instance).setText("it deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way"), new ManaCostsImpl<>("{1}"));
damageAbility.addTarget(new TargetCreaturePermanent(filter)); damageAbility.addTarget(new TargetCreaturePermanent(filter));

View file

@ -66,7 +66,7 @@ class ChainedThroatseekerCantAttackEffect extends RestrictionEffect {
@Override @Override
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
Player targetPlayer = game.getPlayerOrPlaneswalkerController(defenderId); Player targetPlayer = game.getPlayerOrPlaneswalkerController(defenderId);
return targetPlayer != null && targetPlayer.getCounters().containsKey(CounterType.POISON); return targetPlayer != null && targetPlayer.getCountersCount(CounterType.POISON) > 0;
} }
@Override @Override

View file

@ -1,7 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility; import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility;
@ -22,8 +21,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class CoalitionRelic extends CardImpl { public final class CoalitionRelic extends CardImpl {
@ -70,11 +70,10 @@ class CoalitionRelicEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (sourcePermanent != null && player != null) { if (sourcePermanent != null && player != null) {
int chargeCounters = sourcePermanent.getCounters(game).getCount(CounterType.CHARGE); int amountRemoved = sourcePermanent.removeAllCounters(CounterType.CHARGE.getName(), source, game);
sourcePermanent.removeCounters(CounterType.CHARGE.createInstance(chargeCounters), source, game);
Mana mana = new Mana(); Mana mana = new Mana();
ChoiceColor choice = new ChoiceColor(); ChoiceColor choice = new ChoiceColor();
for (int i = 0; i < chargeCounters; i++) { for (int i = 0; i < amountRemoved; i++) {
if (!player.choose(outcome, choice, game)) { if (!player.choose(outcome, choice, game)) {
return false; return false;
} }

View file

@ -1,7 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
@ -20,14 +19,15 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class Corrosion extends CardImpl { public final class Corrosion extends CardImpl {
public Corrosion(UUID ownerId, CardSetInfo setInfo) { public Corrosion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}{R}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{R}");
// Cumulative upkeep-Pay {1}. // Cumulative upkeep-Pay {1}.
this.addAbility(new CumulativeUpkeepAbility(new GenericManaCost(1))); this.addAbility(new CumulativeUpkeepAbility(new GenericManaCost(1)));
@ -112,7 +112,7 @@ class CorrosionRemoveCountersEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) {
permanent.removeCounters(CounterType.RUST.createInstance(permanent.getCounters(game).getCount(CounterType.RUST)), source, game); permanent.removeAllCounters(CounterType.RUST.getName(), source, game);
} }
return true; return true;
} }

View file

@ -1,7 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -14,14 +13,15 @@ import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetSpell; import mage.target.TargetSpell;
import java.util.UUID;
/** /**
*
* @author Loki * @author Loki
*/ */
public final class CorruptedResolve extends CardImpl { public final class CorruptedResolve extends CardImpl {
public CorruptedResolve(UUID ownerId, CardSetInfo setInfo) { public CorruptedResolve(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Counter target spell if its controller is poisoned. // Counter target spell if its controller is poisoned.
@ -54,9 +54,10 @@ class CorruptedResolveEffect extends OneShotEffect {
Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source));
if (spell != null) { if (spell != null) {
Player player = game.getPlayer(spell.getControllerId()); Player player = game.getPlayer(spell.getControllerId());
if (player != null && player.getCounters().containsKey(CounterType.POISON)) if (player != null && player.getCountersCount(CounterType.POISON) > 0) {
return game.getStack().counter(getTargetPointer().getFirst(game, source), source, game); return game.getStack().counter(getTargetPointer().getFirst(game, source), source, game);
} }
}
return false; return false;
} }

View file

@ -13,7 +13,7 @@ import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersTargetEffect; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
@ -168,7 +168,7 @@ class CyclopeanTombEffect extends OneShotEffect {
if (controller.chooseTarget(Outcome.Neutral, target, source, game)) { if (controller.chooseTarget(Outcome.Neutral, target, source, game)) {
Permanent chosenLand = game.getPermanent(target.getFirstTarget()); Permanent chosenLand = game.getPermanent(target.getFirstTarget());
if (chosenLand != null) { if (chosenLand != null) {
Effect effect = new RemoveAllCountersTargetEffect(CounterType.MIRE); Effect effect = new RemoveAllCountersPermanentTargetEffect(CounterType.MIRE);
effect.setTargetPointer(new FixedTarget(chosenLand, game)); effect.setTargetPointer(new FixedTarget(chosenLand, game));
effect.apply(game, source); effect.apply(game, source);
landRef.remove(new MageObjectReference(chosenLand, game)); landRef.remove(new MageObjectReference(chosenLand, game));

View file

@ -1,7 +1,6 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -18,18 +17,18 @@ import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamageEvent; import mage.game.events.DamageEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author emerald000 * @author emerald000
*/ */
public final class DelayingShield extends CardImpl { public final class DelayingShield extends CardImpl {
public DelayingShield(UUID ownerId, CardSetInfo setInfo) { public DelayingShield(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}");
// If damage would be dealt to you, put that many delay counters on Delaying Shield instead. // If damage would be dealt to you, put that many delay counters on Delaying Shield instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DelayingShieldReplacementEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DelayingShieldReplacementEffect()));
@ -103,9 +102,8 @@ class DelayingShieldUpkeepEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) { if (controller != null && permanent != null) {
int numCounters = permanent.getCounters(game).getCount(CounterType.DELAY); int countersRemoved = permanent.removeAllCounters(CounterType.DELAY.getName(), source, game);
permanent.removeCounters(CounterType.DELAY.createInstance(numCounters), source, game); for (int i = countersRemoved; i > 0; i--) {
for (int i = numCounters; i > 0; i--) {
if (controller.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", source, game)) { if (controller.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", source, game)) {
Cost cost = new ManaCostsImpl<>("{1}{W}"); Cost cost = new ManaCostsImpl<>("{1}{W}");
if (cost.pay(source, game, source, source.getControllerId(), false, null)) { if (cost.pay(source, game, source, source.getControllerId(), false, null)) {

View file

@ -1,7 +1,6 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.costs.common.PayEnergyCost;
@ -21,14 +20,15 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class DieYoung extends CardImpl { public final class DieYoung extends CardImpl {
public DieYoung(UUID ownerId, CardSetInfo setInfo) { public DieYoung(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
// Choose target creature. You get {E}{E}, then you may pay any amount of {E}. The creature gets -1/-1 until end of turn for each {E} paid this way. // Choose target creature. You get {E}{E}, then you may pay any amount of {E}. The creature gets -1/-1 until end of turn for each {E} paid this way.
this.getSpellAbility().addEffect(new DieYoungEffect()); this.getSpellAbility().addEffect(new DieYoungEffect());
@ -66,7 +66,7 @@ class DieYoungEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
new GetEnergyCountersControllerEffect(2).apply(game, source); new GetEnergyCountersControllerEffect(2).apply(game, source);
int max = controller.getCounters().getCount(CounterType.ENERGY); int max = controller.getCountersCount(CounterType.ENERGY);
int numberToPayed = controller.getAmount(0, max, "How many energy counters do you like to pay? (maximum = " + max + ')', game); int numberToPayed = controller.getAmount(0, max, "How many energy counters do you like to pay? (maximum = " + max + ')', game);
if (numberToPayed > 0) { if (numberToPayed > 0) {
Cost cost = new PayEnergyCost(numberToPayed); Cost cost = new PayEnergyCost(numberToPayed);

View file

@ -86,7 +86,7 @@ class EzuriClawOfProgressEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (target != null) { if (target != null) {
int amount = controller.getCounters().getCount(CounterType.EXPERIENCE); int amount = controller.getCountersCount(CounterType.EXPERIENCE);
target.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game); target.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game);
} }
return true; return true;

View file

@ -62,7 +62,7 @@ class FeedTheInfectionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (UUID playerId : game.getOpponents(source.getControllerId())) { for (UUID playerId : game.getOpponents(source.getControllerId())) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null && player.getCounters().getCount(CounterType.POISON) >= 3) { if (player != null && player.getCountersCount(CounterType.POISON) >= 3) {
player.loseLife(3, game, source, false); player.loseLife(3, game, source, false);
} }
} }

View file

@ -9,7 +9,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.counters.Counter;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -77,13 +76,7 @@ class FinalActEffect extends OneShotEffect {
if (player == null) { if (player == null) {
continue; continue;
} }
player player.loseAllCounters(source, game);
.getCounters()
.values()
.stream()
.map(Counter::copy)
.forEach(counter -> player.removeCounters(counter.getName(), counter.getCount(), source, game));
} }
return true; return true;
} }

View file

@ -112,10 +112,7 @@ class FrayingLineEffect extends OneShotEffect {
StaticFilters.FILTER_PERMANENT_CREATURE, StaticFilters.FILTER_PERMANENT_CREATURE,
source.getControllerId(), source, game source.getControllerId(), source, game
)) { )) {
int counters = permanent.getCounters(game).getCount(CounterType.ROPE); permanent.removeAllCounters(CounterType.ROPE.getName(), source, game);
if (counters > 0) {
permanent.removeCounters(CounterType.ROPE.createInstance(counters), source, game);
}
} }
return true; return true;
} }

View file

@ -65,7 +65,7 @@ class FreyalisesWindsReplacementEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent permanentUntapping = game.getPermanent(event.getTargetId()); Permanent permanentUntapping = game.getPermanent(event.getTargetId());
if (permanentUntapping != null) { if (permanentUntapping != null) {
permanentUntapping.getCounters(game).removeAllCounters(CounterType.WIND); permanentUntapping.removeAllCounters(CounterType.WIND.getName(), source, game);
return true; return true;
} }
return false; return false;

View file

@ -63,7 +63,7 @@ class GalvanicDischargeEffect extends OneShotEffect {
return false; return false;
} }
new GetEnergyCountersControllerEffect(3).apply(game, source); new GetEnergyCountersControllerEffect(3).apply(game, source);
int numberToPay = controller.getAmount(0, controller.getCounters().getCount(CounterType.ENERGY), "How many {E} do you like to pay?", game); int numberToPay = controller.getAmount(0, controller.getCountersCount(CounterType.ENERGY), "How many {E} do you like to pay?", game);
if (numberToPay <= 0) { if (numberToPay <= 0) {
return true; return true;
} }

View file

@ -64,7 +64,7 @@ enum GethsSummonsAdjuster implements TargetAdjuster {
// corrupted opponents' graveyards // corrupted opponents' graveyards
for (UUID opponentId : game.getOpponents(ability.getControllerId(), true)) { for (UUID opponentId : game.getOpponents(ability.getControllerId(), true)) {
Player opponent = game.getPlayer(opponentId); Player opponent = game.getPlayer(opponentId);
if (opponent == null || opponent.getCounters().getCount(CounterType.POISON) < 3) { if (opponent == null || opponent.getCountersCount(CounterType.POISON) < 3) {
continue; continue;
} }
FilterCard filter = new FilterCard("creature card from " + opponent.getLogName() + "'s graveyard"); FilterCard filter = new FilterCard("creature card from " + opponent.getLogName() + "'s graveyard");

View file

@ -12,7 +12,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapAsLongAsSourceTappedEffect; import mage.abilities.effects.common.DontUntapAsLongAsSourceTappedEffect;
import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersTargetEffect; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
@ -127,7 +127,7 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect {
class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbility { class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbility {
public GiantOysterLeaveUntapDelayedTriggeredAbility(UUID abilityToCancel) { public GiantOysterLeaveUntapDelayedTriggeredAbility(UUID abilityToCancel) {
super(new RemoveAllCountersTargetEffect(CounterType.M1M1), Duration.EndOfGame, true, false); super(new RemoveAllCountersPermanentTargetEffect(CounterType.M1M1), Duration.EndOfGame, true, false);
this.addEffect(new RemoveDelayedTriggeredAbilityEffect(abilityToCancel)); this.addEffect(new RemoveDelayedTriggeredAbilityEffect(abilityToCancel));
} }

View file

@ -1,7 +1,6 @@
package mage.cards.g; package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect;
@ -17,8 +16,9 @@ import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class GiveTake extends SplitCard { public final class GiveTake extends SplitCard {
@ -65,20 +65,18 @@ class TakeEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (creature != null) {
int numberCounters = creature.getCounters(game).getCount(CounterType.P1P1);
if (numberCounters > 0) {
creature.removeCounters(CounterType.P1P1.getName(), numberCounters, source, game);
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller == null) {
controller.drawCards(numberCounters, source, game); return false;
} else {
throw new UnsupportedOperationException("Controller missing");
} }
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (creature == null) {
return false;
}
int countersRemoved = creature.removeAllCounters(CounterType.P1P1.getName(), source, game);
if (countersRemoved > 0) {
controller.drawCards(countersRemoved, source, game);
} }
return true; return true;
} }
return false;
}
} }

View file

@ -80,7 +80,7 @@ enum GlissasRetrieverAdjuster implements TargetAdjuster {
int amount = 0; int amount = 0;
for (UUID opponentId : game.getOpponents(ability.getControllerId(), true)) { for (UUID opponentId : game.getOpponents(ability.getControllerId(), true)) {
Player player = game.getPlayer(opponentId); Player player = game.getPlayer(opponentId);
if (player != null && player.getCounters().getCount(CounterType.POISON) >= 3) { if (player != null && player.getCountersCount(CounterType.POISON) >= 3) {
amount++; amount++;
} }
} }

View file

@ -141,7 +141,7 @@ class HammerJammerEffect extends OneShotEffect {
if (controller != null && permanent != null) { if (controller != null && permanent != null) {
Integer amount = (Integer) getValue("rolled"); Integer amount = (Integer) getValue("rolled");
if (amount != null) { if (amount != null) {
permanent.removeCounters(CounterType.P1P1.createInstance(permanent.getCounters(game).getCount(CounterType.P1P1)), source, game); permanent.removeAllCounters(CounterType.P1P1.getName(), source, game);
if (amount > 0) { if (amount > 0) {
permanent.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game); permanent.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game);
} }

View file

@ -149,10 +149,8 @@ class HankyuCost extends UseAttachedCost {
if (equipment == null) { if (equipment == null) {
continue; continue;
} }
int count = equipment.getCounters(game).getCount(CounterType.AIM); removedCounters = equipment.removeAllCounters(CounterType.AIM.getName(), source, game);
equipment.removeCounters(CounterType.AIM.createInstance(count), source, game);
paid = true; paid = true;
removedCounters = count;
break; break;
} }

View file

@ -2,8 +2,9 @@
package mage.cards.h; package mage.cards.h;
import java.util.UUID; import java.util.UUID;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersTargetEffect; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.HexproofAbility; import mage.abilities.keyword.HexproofAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -13,7 +14,6 @@ import mage.counters.CounterType;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class HapatrasMark extends CardImpl { public final class HapatrasMark extends CardImpl {
@ -23,7 +23,7 @@ public final class HapatrasMark extends CardImpl {
// Target creature you control gains hexproof until end of turn. Remove all -1/-1 counters from it. // Target creature you control gains hexproof until end of turn. Remove all -1/-1 counters from it.
getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn));
getSpellAbility().addEffect(new RemoveAllCountersTargetEffect(CounterType.M1M1)); getSpellAbility().addEffect(new RemoveAllCountersPermanentTargetEffect(CounterType.M1M1));
getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
} }

View file

@ -62,7 +62,7 @@ class HarnessedLightningEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
new GetEnergyCountersControllerEffect(3).apply(game, source); new GetEnergyCountersControllerEffect(3).apply(game, source);
int numberToPay = controller.getAmount(0, controller.getCounters().getCount(CounterType.ENERGY), "How many {E} do you like to pay?", game); int numberToPay = controller.getAmount(0, controller.getCountersCount(CounterType.ENERGY), "How many {E} do you like to pay?", game);
if (numberToPay > 0) { if (numberToPay > 0) {
Cost cost = new PayEnergyCost(numberToPay); Cost cost = new PayEnergyCost(numberToPay);
if (cost.pay(source, game, source, source.getControllerId(), true)) { if (cost.pay(source, game, source, source.getControllerId(), true)) {

View file

@ -79,7 +79,7 @@ class IxhelScionOfAtraxaEffect extends OneShotEffect {
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
for (UUID opponentId : game.getOpponents(source.getControllerId(), true)) { for (UUID opponentId : game.getOpponents(source.getControllerId(), true)) {
Player opponent = game.getPlayer(opponentId); Player opponent = game.getPlayer(opponentId);
if (opponent == null || opponent.getCounters().getCount(CounterType.POISON) < 3 || !opponent.getLibrary().hasCards()) { if (opponent == null || opponent.getCountersCount(CounterType.POISON) < 3 || !opponent.getLibrary().hasCards()) {
continue; continue;
} }
Card card = opponent.getLibrary().getFromTop(game); Card card = opponent.getLibrary().getFromTop(game);

View file

@ -0,0 +1,170 @@
package mage.cards.i;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.IntCompareCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author Susucr
*/
public final class IzzetGeneratorium extends CardImpl {
private static final Condition condition = new IzzetGeneratoriumCondition();
private static final Hint hint = new ValueHint("{E} paid or lost this turn", IzzetGeneratoriumValue.instance);
public IzzetGeneratorium(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}{R}");
// If you would get one or more {E}, you get that many plus one {E} instead.
this.addAbility(new SimpleStaticAbility(new IzzetGeneratoriumReplacementEffect()));
// {T}: Draw a card. Activate only if you've paid or lost four or more {E} this turn.
this.addAbility(new ActivateIfConditionActivatedAbility(
new DrawCardSourceControllerEffect(1),
new TapSourceCost(),
condition
).addHint(hint), new IzzetGeneratoriumWatcher());
}
private IzzetGeneratorium(final IzzetGeneratorium card) {
super(card);
}
@Override
public IzzetGeneratorium copy() {
return new IzzetGeneratorium(this);
}
}
class IzzetGeneratoriumReplacementEffect extends ReplacementEffectImpl {
IzzetGeneratoriumReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "if you would get one or more {E}, you get that many plus one {E} instead";
}
private IzzetGeneratoriumReplacementEffect(final IzzetGeneratoriumReplacementEffect effect) {
super(effect);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmountForCounters(CardUtil.overflowInc(event.getAmount(), 1), true);
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ADD_COUNTERS;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return source.isControlledBy(event.getTargetId())
&& CounterType.ENERGY.getName().equals(event.getData())
&& event.getAmount() > 0;
}
@Override
public IzzetGeneratoriumReplacementEffect copy() {
return new IzzetGeneratoriumReplacementEffect(this);
}
}
class IzzetGeneratoriumCondition extends IntCompareCondition {
IzzetGeneratoriumCondition() {
super(ComparisonType.OR_GREATER, 4);
}
@Override
protected int getInputValue(Game game, Ability source) {
return IzzetGeneratoriumValue.instance.calculate(game, source, null);
}
@Override
public String toString() {
return "if you've paid or lost four or more {E} this turn";
}
}
enum IzzetGeneratoriumValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return IzzetGeneratoriumWatcher.getAmountEnergyLostOrSpentThisTurn(game, sourceAbility.getControllerId());
}
@Override
public IzzetGeneratoriumValue copy() {
return this;
}
@Override
public String getMessage() {
return "{E} spent or lost this turn";
}
@Override
public String toString() {
return "X";
}
}
class IzzetGeneratoriumWatcher extends Watcher {
// player -> amount of energy spent or lost this turn
private final Map<UUID, Integer> energyLostOrSpent = new HashMap<>();
IzzetGeneratoriumWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.COUNTERS_REMOVED) {
return;
}
if (!event.getData().equals(CounterType.ENERGY.getName())) {
return;
}
int amount = event.getAmount();
if (amount <= 0) {
return;
}
energyLostOrSpent.compute(event.getTargetId(), (k, i) -> i == null ? amount : Integer.sum(i, amount));
}
@Override
public void reset() {
super.reset();
energyLostOrSpent.clear();
}
public static int getAmountEnergyLostOrSpentThisTurn(Game game, UUID playerId) {
IzzetGeneratoriumWatcher watcher = game.getState().getWatcher(IzzetGeneratoriumWatcher.class);
return watcher == null ? 0 : watcher.energyLostOrSpent.getOrDefault(playerId, 0);
}
}

View file

@ -35,9 +35,7 @@ public final class JarOfEyeballs extends CardImpl {
false, StaticFilters.FILTER_CONTROLLED_A_CREATURE false, StaticFilters.FILTER_CONTROLLED_A_CREATURE
)); ));
// {3}, {tap}, Remove all eyeball counters from Jar of Eyeballs: // {3}, {tap}, Remove all eyeball counters from Jar of Eyeballs: Look at the top X cards of your library, where X is the number of eyeball counters removed this way. Put one of them into your hand and the rest on the bottom of your library in any order.
// Look at the top X cards of your library, where X is the number of eyeball counters removed this way.
// Put one of them into your hand and the rest on the bottom of your library in any order.
SimpleActivatedAbility ability = new SimpleActivatedAbility( SimpleActivatedAbility ability = new SimpleActivatedAbility(
new LookLibraryAndPickControllerEffect(JarOfEyeballsValue.instance, 1, PutCards.HAND, PutCards.BOTTOM_ANY), new LookLibraryAndPickControllerEffect(JarOfEyeballsValue.instance, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
new GenericManaCost(3)); new GenericManaCost(3));

View file

@ -60,9 +60,9 @@ class LeechesEffect extends OneShotEffect {
return false; return false;
} }
int countPoisonCounters = targetPlayer.getCounters().getCount(CounterType.POISON); int countPoisonCounters = targetPlayer.getCountersCount(CounterType.POISON);
if (countPoisonCounters > 0) { if (countPoisonCounters > 0) {
targetPlayer.removeCounters(CounterType.POISON.getName(), countPoisonCounters, source, game); targetPlayer.loseAllCounters(CounterType.POISON.getName(), source, game);
targetPlayer.damage(countPoisonCounters, source.getSourceId(), source, game); targetPlayer.damage(countPoisonCounters, source.getSourceId(), source, game);
return true; return true;
} }

View file

@ -11,7 +11,7 @@ import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.counters.BoostCounter; import mage.counters.CounterType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate;
@ -85,7 +85,7 @@ class LesserWerewolfEffect extends OneShotEffect {
} }
if (sourcePermanent.getPower().getValue() >= 1) { if (sourcePermanent.getPower().getValue() >= 1) {
game.addEffect(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), source); game.addEffect(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), source);
new AddCountersTargetEffect(new BoostCounter(0, -1), outcome).apply(game, source); new AddCountersTargetEffect(CounterType.M0M1.createInstance(), outcome).apply(game, source);
} }
return true; return true;
} }

View file

@ -34,9 +34,7 @@ public final class LightningCoils extends CardImpl {
new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true), new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true),
false, StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN)); false, StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN));
// At the beginning of your upkeep, if Lightning Coils has five or more charge counters on it, remove all of them from it // At the beginning of your upkeep, if Lightning Coils has five or more charge counters on it, remove all of them from it and put that many 3/1 red Elemental creature tokens with haste onto the battlefield. Exile them at the beginning of the next end step.
// and put that many 3/1 red Elemental creature tokens with haste onto the battlefield.
// Exile them at the beginning of the next end step.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LightningCoilsEffect(), TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LightningCoilsEffect(), TargetController.YOU, false));
} }
@ -64,12 +62,12 @@ class LightningCoilsEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent p = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (p != null && controller != null) { if (permanent != null && controller != null) {
int counters = p.getCounters(game).getCount(CounterType.CHARGE); int counters = permanent.getCounters(game).getCount(CounterType.CHARGE);
if (counters >= 5) { if (counters >= 5) {
// remove all the counters and create that many tokens // remove all the counters and create that many tokens
p.removeCounters(CounterType.CHARGE.getName(), p.getCounters(game).getCount(CounterType.CHARGE), source, game); permanent.removeAllCounters(CounterType.CHARGE.getName(), source, game);
CreateTokenEffect effect = new CreateTokenEffect(new ElementalTokenWithHaste(), counters); CreateTokenEffect effect = new CreateTokenEffect(new ElementalTokenWithHaste(), counters);
effect.apply(game, source); effect.apply(game, source);

View file

@ -1,6 +1,5 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
@ -15,15 +14,16 @@ import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class LightningRunner extends CardImpl { public final class LightningRunner extends CardImpl {
@ -74,7 +74,7 @@ class LightningRunnerEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
new GetEnergyCountersControllerEffect(2).apply(game, source); new GetEnergyCountersControllerEffect(2).apply(game, source);
if (controller.getCounters().getCount(CounterType.ENERGY) > 7) { if (controller.getCountersCount(CounterType.ENERGY) > 7) {
Cost cost = new PayEnergyCost(8); Cost cost = new PayEnergyCost(8);
if (controller.chooseUse(outcome, if (controller.chooseUse(outcome,
"Pay {E}{E}{E}{E}{E}{E}{E}{E} to use this? ", "Pay {E}{E}{E}{E}{E}{E}{E}{E} to use this? ",

View file

@ -1,7 +1,5 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -12,16 +10,18 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoubleCountersSourceEffect; import mage.abilities.effects.common.DoubleCountersSourceEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.*;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
* @author Cguy7777 * @author Cguy7777
*/ */
@ -51,8 +51,7 @@ public final class LilyBowenRagingGrandma extends CardImpl {
CounterType.P1P1.createInstance(2)), CounterType.P1P1.createInstance(2)),
"with two +1/+1 counters on it")); "with two +1/+1 counters on it"));
// At the beginning of your upkeep, double the number of +1/+1 counters on Lily Bowen if its power is 16 or less. // At the beginning of your upkeep, double the number of +1/+1 counters on Lily Bowen if its power is 16 or less. Otherwise, remove all but one +1/+1 counter from it, then you gain 1 life for each +1/+1 counter removed this way.
// Otherwise, remove all but one +1/+1 counter from it, then you gain 1 life for each +1/+1 counter removed this way.
this.addAbility(new BeginningOfUpkeepTriggeredAbility( this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new ConditionalOneShotEffect( new ConditionalOneShotEffect(
new DoubleCountersSourceEffect(CounterType.P1P1), new DoubleCountersSourceEffect(CounterType.P1P1),
@ -93,14 +92,18 @@ class LilyBowenRagingGrandmaEffect extends OneShotEffect {
} }
// Remove all but one +1/+1 counter from it, then you gain 1 life for each +1/+1 counter removed this way. // Remove all but one +1/+1 counter from it, then you gain 1 life for each +1/+1 counter removed this way.
int count = permanent.getCounters(game).getCount(CounterType.P1P1); int countBefore = permanent.getCounters(game).getCount(CounterType.P1P1);
if (count <= 1) { if (countBefore <= 1) {
return true; return true;
} }
int countToRemove = count - 1; int countToRemove = countBefore - 1;
permanent.removeCounters(CounterType.P1P1.createInstance(countToRemove), source, game); permanent.removeCounters(CounterType.P1P1.createInstance(countToRemove), source, game);
new GainLifeEffect(countToRemove).apply(game, source); int countAfter = permanent.getCounters(game).getCount(CounterType.P1P1);
int countersRemoved = Math.max(0, countBefore - countAfter);
if (countersRemoved > 0) {
new GainLifeEffect(countersRemoved).apply(game, source);
}
return true; return true;
} }

View file

@ -1,7 +1,6 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -12,19 +11,20 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.BoostCounter; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author Derpthemeus * @author Derpthemeus
*/ */
public final class LivingArmor extends CardImpl { public final class LivingArmor extends CardImpl {
public LivingArmor(UUID ownerId, CardSetInfo setInfo) { public LivingArmor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {tap}, Sacrifice Living Armor: Put X +0/+1 counters on target creature, where X is that creature's converted mana cost. // {tap}, Sacrifice Living Armor: Put X +0/+1 counters on target creature, where X is that creature's converted mana cost.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LivingArmorEffect(), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LivingArmorEffect(), new TapSourceCost());
@ -63,7 +63,7 @@ public final class LivingArmor extends CardImpl {
Permanent creature = game.getPermanent(source.getTargets().getFirstTarget()); Permanent creature = game.getPermanent(source.getTargets().getFirstTarget());
if (creature != null) { if (creature != null) {
int amount = creature.getManaValue(); int amount = creature.getManaValue();
creature.addCounters(new BoostCounter(0, 1, amount), source.getControllerId(), source, game); creature.addCounters(CounterType.P0P1.createInstance(amount), source.getControllerId(), source, game);
return true; return true;
} }
return false; return false;

View file

@ -1,7 +1,6 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -14,21 +13,22 @@ import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author Loki * @author Loki
*/ */
public final class LudevicsTestSubject extends CardImpl { public final class LudevicsTestSubject extends CardImpl {
public LudevicsTestSubject(UUID ownerId, CardSetInfo setInfo) { public LudevicsTestSubject(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.subtype.add(SubType.LIZARD, SubType.EGG); this.subtype.add(SubType.LIZARD, SubType.EGG);
this.power = new MageInt(0); this.power = new MageInt(0);
@ -67,14 +67,16 @@ class LudevicsTestSubjectEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent p = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (p != null) { if (permanent == null) {
if (p.getCounters(game).getCount(CounterType.HATCHLING) >= 5) { return false;
p.removeCounters(CounterType.HATCHLING.getName(), p.getCounters(game).getCount(CounterType.HATCHLING), source, game); }
if (permanent.getCounters(game).getCount(CounterType.HATCHLING) >= 5) {
permanent.removeAllCounters(CounterType.HATCHLING.getName(), source, game);
TransformSourceEffect effect = new TransformSourceEffect(); TransformSourceEffect effect = new TransformSourceEffect();
return effect.apply(game, source); return effect.apply(game, source);
} }
}
return false; return false;
} }

View file

@ -82,9 +82,7 @@ enum LumberingMegaslothValue implements DynamicValue {
.stream() .stream()
.map(game::getPlayer) .map(game::getPlayer)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(Player::getCounters) .mapToInt(Player::getCountersTotalCount)
.flatMap(counters -> counters.values().stream())
.mapToInt(Counter::getCount)
.sum(); .sum();
return onPermanents + onPlayers; return onPermanents + onPlayers;
} }

View file

@ -5,9 +5,9 @@ import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -17,11 +17,9 @@ import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamagedEvent; import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -49,7 +47,7 @@ public final class MarchesaResoluteMonarch extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance()); this.addAbility(DeathtouchAbility.getInstance());
// Whenever Marchesa, Resolute Monarch attacks, remove all counters from up to one target permanent. // Whenever Marchesa, Resolute Monarch attacks, remove all counters from up to one target permanent.
Ability ability = new AttacksTriggeredAbility(new MarchesaResoluteMonarchEffect()); Ability ability = new AttacksTriggeredAbility(new RemoveAllCountersPermanentTargetEffect());
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT)); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT));
this.addAbility(ability); this.addAbility(ability);
@ -78,35 +76,6 @@ public final class MarchesaResoluteMonarch extends CardImpl {
} }
} }
class MarchesaResoluteMonarchEffect extends OneShotEffect {
MarchesaResoluteMonarchEffect() {
super(Outcome.Benefit);
staticText = "remove all counters from up to one target permanent";
}
private MarchesaResoluteMonarchEffect(final MarchesaResoluteMonarchEffect effect) {
super(effect);
}
@Override
public MarchesaResoluteMonarchEffect copy() {
return new MarchesaResoluteMonarchEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
for (String counterType : new ArrayList<>(permanent.getCounters(game).keySet())) {
permanent.getCounters(game).removeAllCounters(counterType);
}
return true;
}
}
class MarchesaResoluteMonarchWatcher extends Watcher { class MarchesaResoluteMonarchWatcher extends Watcher {
private final Set<UUID> players = new HashSet<>(); private final Set<UUID> players = new HashSet<>();

View file

@ -1,6 +1,5 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldOrDiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldOrDiesSourceTriggeredAbility;
@ -9,8 +8,8 @@ import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.counters.Counters; import mage.counters.Counters;
@ -19,8 +18,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetPermanentOrPlayer; import mage.target.common.TargetPermanentOrPlayer;
import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class MaulfistRevolutionary extends CardImpl { public final class MaulfistRevolutionary extends CardImpl {
@ -70,7 +70,7 @@ class MaulfistRevolutionaryEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) { if (player != null) {
Counters counters = player.getCounters().copy(); Counters counters = player.getCountersAsCopy();
for (Counter counter : counters.values()) { for (Counter counter : counters.values()) {
CounterType counterType = CounterType.findByName(counter.getName()); CounterType counterType = CounterType.findByName(counter.getName());
Counter counterToAdd; Counter counterToAdd;

View file

@ -78,7 +78,7 @@ class MerenOfClanNelTothEffect extends OneShotEffect {
if (player == null || card == null) { if (player == null || card == null) {
return false; return false;
} }
boolean flag = card.getManaValue() <= player.getCounters().getCount(CounterType.EXPERIENCE); boolean flag = card.getManaValue() <= player.getCountersCount(CounterType.EXPERIENCE);
return player.moveCards(card, flag ? Zone.BATTLEFIELD : Zone.HAND, source, game); return player.moveCards(card, flag ? Zone.BATTLEFIELD : Zone.HAND, source, game);
} }
} }

View file

@ -85,10 +85,7 @@ class RemoveAllMineCountersEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.LAND, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.LAND, game)) {
if (permanent != null) { if (permanent != null) {
int numToRemove = permanent.getCounters(game).getCount(CounterType.MINE); permanent.removeAllCounters(CounterType.MINE.getName(), source, game);
if (numToRemove > 0) {
permanent.removeCounters(CounterType.MINE.getName(), numToRemove, source, game);
}
} }
} }
return true; return true;

View file

@ -69,7 +69,7 @@ class MizzixOfTheIzmagnusPredicate implements Predicate<MageObject> {
if (spell != null) { if (spell != null) {
Player controller = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(spell.getControllerId());
if (controller != null) { if (controller != null) {
if (spell.getManaValue() > controller.getCounters().getCount(CounterType.EXPERIENCE)) { if (spell.getManaValue() > controller.getCountersCount(CounterType.EXPERIENCE)) {
return true; return true;
} }
} }
@ -99,7 +99,7 @@ class MizzixOfTheIzmagnusCostReductionEffect extends CostModificationEffectImpl
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
SpellAbility spellAbility = (SpellAbility) abilityToModify; SpellAbility spellAbility = (SpellAbility) abilityToModify;
CardUtil.adjustCost(spellAbility, controller.getCounters().getCount(CounterType.EXPERIENCE)); CardUtil.adjustCost(spellAbility, controller.getCountersCount(CounterType.EXPERIENCE));
return true; return true;
} }
return false; return false;

View file

@ -64,6 +64,6 @@ enum NightkinAmbusherCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player defendingPlayer = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); Player defendingPlayer = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game));
return defendingPlayer != null && defendingPlayer.getCounters().getCount(CounterType.RAD) >= 1; return defendingPlayer != null && defendingPlayer.getCountersCount(CounterType.RAD) >= 1;
} }
} }

View file

@ -1,7 +1,6 @@
package mage.cards.o; package mage.cards.o;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -19,13 +18,15 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import java.util.UUID;
/** /**
* @author Loki * @author Loki
*/ */
public final class OblivionStone extends CardImpl { public final class OblivionStone extends CardImpl {
public OblivionStone(UUID ownerId, CardSetInfo setInfo) { public OblivionStone(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {4}, {tap}: Put a fate counter on target permanent. // {4}, {tap}: Put a fate counter on target permanent.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.FATE.createInstance()), new GenericManaCost(4)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.FATE.createInstance()), new GenericManaCost(4));
@ -62,15 +63,13 @@ class OblivionStoneEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent p : game.getBattlefield().getAllActivePermanents()) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) {
if (!(p.isLand(game) || p.getCounters(game).containsKey(CounterType.FATE))) { if (!(permanent.isLand(game) || permanent.getCounters(game).containsKey(CounterType.FATE))) {
p.destroy(source, game, false); permanent.destroy(source, game, false);
} }
} }
for (Permanent p : game.getBattlefield().getAllActivePermanents()) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) {
if (p.getCounters(game).containsKey(CounterType.FATE)) { permanent.removeAllCounters(CounterType.FATE.getName(), source, game);
p.removeCounters(CounterType.FATE.getName(), p.getCounters(game).getCount(CounterType.FATE), source, game);
}
} }
return true; return true;
} }

View file

@ -64,7 +64,7 @@ class PhyresisOutbreakEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (UUID opponentId : game.getOpponents(source.getControllerId(), true)) { for (UUID opponentId : game.getOpponents(source.getControllerId(), true)) {
int totalPoison = game.getPlayer(opponentId).getCounters().getCount(CounterType.POISON); int totalPoison = game.getPlayer(opponentId).getCountersCount(CounterType.POISON);
BoostTargetEffect effect = new BoostTargetEffect(totalPoison * -1, totalPoison * -1, Duration.EndOfTurn); BoostTargetEffect effect = new BoostTargetEffect(totalPoison * -1, totalPoison * -1, Duration.EndOfTurn);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_A_CREATURE, opponentId, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_A_CREATURE, opponentId, game)) {
effect.setTargetPointer(new FixedTarget(permanent, game)); effect.setTargetPointer(new FixedTarget(permanent, game));

View file

@ -60,7 +60,7 @@ class PhyrexianAtlasEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (UUID playerId : game.getOpponents(source.getControllerId())) { for (UUID playerId : game.getOpponents(source.getControllerId())) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null && player.getCounters().getCount(CounterType.POISON) >= 3) { if (player != null && player.getCountersCount(CounterType.POISON) >= 3) {
player.loseLife(1, game, source, false); player.loseLife(1, game, source, false);
} }
} }

View file

@ -6,6 +6,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.counters.Counter;
import mage.filter.FilterOpponent; import mage.filter.FilterOpponent;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.common.FilterPermanentOrPlayer;
@ -106,17 +107,17 @@ class PriceOfBetrayalEffect extends OneShotEffect {
if (player != null) { if (player != null) {
int toRemove = 5; int toRemove = 5;
int removed = 0; int removed = 0;
String[] counterNames = player.getCounters().keySet().toArray(new String[0]); for (Counter counter : player.getCountersAsCopy().values()) {
for (String counterName : counterNames) { String counterName = counter.getName();
if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) {
if (player.getCounters().get(counterName).getCount() == 1 || (toRemove - removed == 1)) { if (player.getCountersCount(counterName) == 1 || (toRemove - removed == 1)) {
player.removeCounters(counterName, 1, source, game); player.loseCounters(counterName, 1, source, game);
removed++; removed++;
} else { } else {
int amount = controller.getAmount(1, Math.min(player.getCounters().get(counterName).getCount(), toRemove - removed), "How many?", game); int amount = controller.getAmount(1, Math.min(player.getCountersCount(counterName), toRemove - removed), "How many?", game);
if (amount > 0) { if (amount > 0) {
removed += amount; removed += amount;
player.removeCounters(counterName, amount, source, game); player.loseCounters(counterName, amount, source, game);
} }
} }
} }

View file

@ -28,22 +28,20 @@ import java.util.UUID;
*/ */
public final class QuicksilverFountain extends CardImpl { public final class QuicksilverFountain extends CardImpl {
private static final Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND);
public QuicksilverFountain(UUID ownerId, CardSetInfo setInfo) { public QuicksilverFountain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// At the beginning of each player's upkeep, that player puts a flood // At the beginning of each player's upkeep, that player puts a flood counter on target non-Island land they control of their choice. That land is an Island for as long as it has a flood counter on it.
// counter on target non-Island land they control of their choice.
// That land is an Island for as long as it has a flood counter on it.
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new QuicksilverFountainEffect(), TargetController.ANY, false, true); new QuicksilverFountainEffect(), TargetController.ANY, false, true);
ability.addTarget(new TargetLandPermanent()); ability.addTarget(new TargetLandPermanent());
ability.setTargetAdjuster(QuicksilverFountainAdjuster.instance); ability.setTargetAdjuster(QuicksilverFountainAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
// At the beginning of each end step, if all lands on the battlefield are // At the beginning of each end step, if all lands on the battlefield are Islands, remove all flood counters from them.
// Islands, remove all flood counters from them.
// Note: This applies only if Quicksilver Fountain is on the battlefield // Note: This applies only if Quicksilver Fountain is on the battlefield
Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND);
this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD,
new QuicksilverFountainEffect2(), TargetController.ANY, condition, false)); new QuicksilverFountainEffect2(), TargetController.ANY, condition, false));
} }
@ -130,7 +128,7 @@ class QuicksilverFountainEffect2 extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND, game)) { for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND, game)) {
land.removeCounters(CounterType.FLOOD.createInstance(land.getCounters(game).getCount(CounterType.FLOOD)), source, game); land.removeAllCounters(CounterType.FLOOD.getName(), source, game);
} }
return true; return true;
} }

View file

@ -74,9 +74,7 @@ class ReplicatingRingEffect extends OneShotEffect {
if (permanent == null || permanent.getCounters(game).getCount(CounterType.NIGHT) < 8) { if (permanent == null || permanent.getCounters(game).getCount(CounterType.NIGHT) < 8) {
return true; return true;
} }
permanent.removeCounters(CounterType.NIGHT.createInstance( permanent.removeAllCounters(CounterType.NIGHT.getName(), source, game);
permanent.getCounters(game).getCount(CounterType.NIGHT)
),source,game);
new ReplicatedRingToken().putOntoBattlefield(8, game, source, source.getControllerId()); new ReplicatedRingToken().putOntoBattlefield(8, game, source, source.getControllerId());
return true; return true;
} }

View file

@ -41,9 +41,7 @@ public class RogueSkycaptain extends CardImpl {
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// At the beginning of your upkeep, put a wage counter on Rogue Skycaptain. You // At the beginning of your upkeep, put a wage counter on Rogue Skycaptain. You may pay 2 for each wage counter on it. If you don't, remove all wage counters from Rogue Skycaptain and an opponent gains control of it.
// may pay 2 for each wage counter on it. If you don't, remove all wage counters
// from Rogue Skycaptain and an opponent gains control of it.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RogueSkycaptainEffect(), TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RogueSkycaptainEffect(), TargetController.YOU, false));
} }
@ -62,7 +60,8 @@ class RogueSkycaptainEffect extends OneShotEffect {
RogueSkycaptainEffect() { RogueSkycaptainEffect() {
super(Outcome.GainControl); super(Outcome.GainControl);
staticText = "put a wage counter on {this}. You may pay {2} for each wage counter on it. If you don't, remove all wage counters from {this} and an opponent gains control of it"; staticText = "put a wage counter on {this}. You may pay {2} for each wage counter on it. "
+ "If you don't, remove all wage counters from {this} and an opponent gains control of it";
} }
private RogueSkycaptainEffect(final RogueSkycaptainEffect effect) { private RogueSkycaptainEffect(final RogueSkycaptainEffect effect) {

View file

@ -96,10 +96,9 @@ class SarulfRealmEaterEffect extends OneShotEffect {
if (player == null || permanent == null) { if (player == null || permanent == null) {
return false; return false;
} }
int counterCount = permanent.getCounters(game).getCount(CounterType.P1P1); int removedThisWay = permanent.removeAllCounters(CounterType.P1P1.getName(), source, game);
permanent.removeCounters(CounterType.P1P1.createInstance(counterCount), source, game);
FilterPermanent filter = new FilterNonlandPermanent(); FilterPermanent filter = new FilterNonlandPermanent();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, counterCount + 1)); filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, removedThisWay));
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
game.getBattlefield() game.getBattlefield()

View file

@ -1,7 +1,6 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
@ -9,23 +8,23 @@ import mage.abilities.keyword.InfectAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author Loki * @author Loki
*/ */
public final class SepticRats extends CardImpl { public final class SepticRats extends CardImpl {
public SepticRats(UUID ownerId, CardSetInfo setInfo) { public SepticRats(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PHYREXIAN);
this.subtype.add(SubType.RAT); this.subtype.add(SubType.RAT);
@ -67,10 +66,10 @@ class SepticRatsTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (event.getSourceId().equals(this.getSourceId()) ) { if (event.getSourceId().equals(this.getSourceId())) {
Player target = game.getPlayer(event.getTargetId()); Player target = game.getPlayer(event.getTargetId());
if (target != null) { if (target != null) {
if (target.getCounters().getCount(CounterType.POISON) > 0) { if (target.getCountersCount(CounterType.POISON) > 0) {
return true; return true;
} }
} }

View file

@ -1,6 +1,5 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
@ -9,8 +8,8 @@ import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.counters.Counters; import mage.counters.Counters;
@ -19,8 +18,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetPermanentOrPlayer; import mage.target.common.TargetPermanentOrPlayer;
import java.util.UUID;
/** /**
*
* @author Styxo * @author Styxo
*/ */
public final class SkyshipPlunderer extends CardImpl { public final class SkyshipPlunderer extends CardImpl {
@ -69,7 +69,7 @@ class SkyshipPlundererEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) { if (player != null) {
Counters counters = player.getCounters().copy(); Counters counters = player.getCountersAsCopy();
for (Counter counter : counters.values()) { for (Counter counter : counters.values()) {
CounterType counterType = CounterType.findByName(counter.getName()); CounterType counterType = CounterType.findByName(counter.getName());
Counter counterToAdd; Counter counterToAdd;

View file

@ -1,6 +1,5 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -27,8 +26,9 @@ import mage.game.permanent.token.SaprolingToken;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class Sporogenesis extends CardImpl { public final class Sporogenesis extends CardImpl {
@ -152,7 +152,7 @@ class SporogenesisRemoveCountersEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game)) {
permanent.removeCounters(CounterType.FUNGUS.createInstance(permanent.getCounters(game).getCount(CounterType.FUNGUS)), source, game); permanent.removeAllCounters(CounterType.FUNGUS.getName(), source, game);
} }
return true; return true;
} }

View file

@ -1,19 +1,18 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.SubType; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.counters.Counter; import mage.constants.SubType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -21,8 +20,9 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class Suncleanser extends CardImpl { public final class Suncleanser extends CardImpl {
@ -38,13 +38,13 @@ public final class Suncleanser extends CardImpl {
// When Suncleanser enters the battlefield, choose one // When Suncleanser enters the battlefield, choose one
// Remove all counters from target creature. It can't have counters put on it for as long as Suncleanser remains on the battlefield. // Remove all counters from target creature. It can't have counters put on it for as long as Suncleanser remains on the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility( Ability ability = new EntersBattlefieldTriggeredAbility(
new SuncleanserRemoveCountersEffect(false), false new RemoveAllCountersPermanentTargetEffect(), false
); );
ability.addEffect(new SuncleanserPreventCountersEffect(false)); ability.addEffect(new SuncleanserPreventCountersEffect(false));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
// Target opponent loses all counters. That player can't get counters for as long as Suncleanser remains on the battlefield. // Target opponent loses all counters. That player can't get counters for as long as Suncleanser remains on the battlefield.
Mode mode = new Mode(new SuncleanserRemoveCountersEffect(true)); Mode mode = new Mode(new SuncleanserRemoveCountersPlayerEffect());
mode.addEffect(new SuncleanserPreventCountersEffect(true)); mode.addEffect(new SuncleanserPreventCountersEffect(true));
mode.addTarget(new TargetOpponent()); mode.addTarget(new TargetOpponent());
ability.addMode(mode); ability.addMode(mode);
@ -61,45 +61,31 @@ public final class Suncleanser extends CardImpl {
} }
} }
class SuncleanserRemoveCountersEffect extends OneShotEffect { class SuncleanserRemoveCountersPlayerEffect extends OneShotEffect {
SuncleanserRemoveCountersEffect(boolean player) { SuncleanserRemoveCountersPlayerEffect() {
super(Outcome.Benefit); super(Outcome.Detriment);
if (player) {
staticText = "Target opponent loses all counters"; staticText = "Target opponent loses all counters";
} else {
staticText = "Remove all counters from target creature";
}
} }
private SuncleanserRemoveCountersEffect(final SuncleanserRemoveCountersEffect effect) { private SuncleanserRemoveCountersPlayerEffect(final SuncleanserRemoveCountersPlayerEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public SuncleanserRemoveCountersEffect copy() { public SuncleanserRemoveCountersPlayerEffect copy() {
return new SuncleanserRemoveCountersEffect(this); return new SuncleanserRemoveCountersPlayerEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
for (Counter counter : permanent.getCounters(game).copy().values()) { // copy to prevent ConcurrentModificationException
permanent.removeCounters(counter, source, game);
}
return true;
}
Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) { if (player == null) {
for (Counter counter : player.getCounters().copy().values()) { // copy to prevent ConcurrentModificationException
player.removeCounters(counter.getName(), counter.getCount(), source, game);
}
return true;
}
return false; return false;
} }
player.loseAllCounters(source, game);
return true;
}
} }
class SuncleanserPreventCountersEffect extends ContinuousRuleModifyingEffectImpl { class SuncleanserPreventCountersEffect extends ContinuousRuleModifyingEffectImpl {

View file

@ -79,11 +79,7 @@ class SurvivorsMedKitEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
int count = player.getCounters().getCount(CounterType.RAD); player.loseAllCounters(CounterType.RAD.getName(), source, game);
if (count > 0) {
player.removeCounters("rad", count, source, game);
return true; return true;
} }
return false;
}
} }

View file

@ -1,6 +1,5 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BecomesTappedTriggeredAbility; import mage.abilities.common.BecomesTappedTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -21,8 +20,9 @@ import mage.filter.predicate.Predicates;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class TemporalDistortion extends CardImpl { public final class TemporalDistortion extends CardImpl {
@ -74,7 +74,7 @@ class TemporalDistortionRemovalEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(game.getActivePlayerId())) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(game.getActivePlayerId())) {
permanent.removeCounters(CounterType.HOURGLASS.createInstance(permanent.getCounters(game).getCount(CounterType.HOURGLASS)), source, game); permanent.removeAllCounters(CounterType.HOURGLASS.getName(), source, game);
} }
return true; return true;
} }

View file

@ -10,9 +10,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.counters.Counters;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.filter.predicate.permanent.CounterAnyPredicate;
import mage.game.Game; import mage.game.Game;
@ -74,11 +72,7 @@ class ThiefOfBloodEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
int countersRemoved = 0; int countersRemoved = 0;
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) {
Counters counters = permanent.getCounters(game).copy(); countersRemoved += permanent.removeAllCounters(source, game);
for (Counter counter : counters.values()) {
permanent.removeCounters(counter.getName(), counter.getCount(), source, game);
countersRemoved += counter.getCount();
}
} }
if (countersRemoved > 0) { if (countersRemoved > 0) {
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId());

View file

@ -1,26 +1,21 @@
package mage.cards.v; package mage.cards.v;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.Counter;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import java.util.UUID;
/** /**
*
* @author Loki, nantuko * @author Loki, nantuko
*/ */
public final class VampireHexmage extends CardImpl { public final class VampireHexmage extends CardImpl {
@ -35,9 +30,13 @@ public final class VampireHexmage extends CardImpl {
this.addAbility(FirstStrikeAbility.getInstance()); this.addAbility(FirstStrikeAbility.getInstance());
SimpleActivatedAbility vampireHexmageAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VampireHexmageEffect(), new SacrificeSourceCost()); // Sacrifice Vampire Hexmage: Remove all counters from target permanent.
vampireHexmageAbility.addTarget(new TargetPermanent()); Ability ability = new SimpleActivatedAbility(
this.addAbility(vampireHexmageAbility); new RemoveAllCountersPermanentTargetEffect(),
new SacrificeSourceCost()
);
ability.addTarget(new TargetPermanent());
this.addAbility(ability);
} }
private VampireHexmage(final VampireHexmage card) { private VampireHexmage(final VampireHexmage card) {
@ -49,33 +48,3 @@ public final class VampireHexmage extends CardImpl {
return new VampireHexmage(this); return new VampireHexmage(this);
} }
} }
class VampireHexmageEffect extends OneShotEffect {
VampireHexmageEffect() {
super(Outcome.Benefit);
staticText = "Remove all counters from target permanent";
}
private VampireHexmageEffect(final VampireHexmageEffect effect) {
super(effect);
}
@Override
public VampireHexmageEffect copy() {
return new VampireHexmageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
for (Counter counter : permanent.getCounters(game).copy().values()) { // copy to prevent ConcurrentModificationException
permanent.removeCounters(counter, source, game);
}
return true;
}
return false;
}
}

View file

@ -91,7 +91,7 @@ class Vault112SadisticSimulationChapterEffect extends OneShotEffect {
return false; return false;
} }
int numberToPay = controller.getAmount( int numberToPay = controller.getAmount(
0, controller.getCounters().getCount(CounterType.ENERGY), 0, controller.getCountersCount(CounterType.ENERGY),
"How many {E} do you like to pay?", game "How many {E} do you like to pay?", game
); );
if (numberToPay <= 0) { if (numberToPay <= 0) {

View file

@ -97,7 +97,7 @@ enum Vault12TheNecropolisValue implements DynamicValue {
.stream() .stream()
.map(game::getPlayer) .map(game::getPlayer)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.mapToInt(p -> p.getCounters().getCount(CounterType.RAD)) .mapToInt(p -> p.getCountersCount(CounterType.RAD))
.sum(); .sum();
} }

View file

@ -1,7 +1,6 @@
package mage.cards.v; package mage.cards.v;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
@ -25,8 +24,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class VentifactBottle extends CardImpl { public final class VentifactBottle extends CardImpl {
@ -79,11 +79,10 @@ class VentifactBottleEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (sourcePermanent != null && player != null) { if (sourcePermanent != null && player != null) {
int chargeCounters = sourcePermanent.getCounters(game).getCount(CounterType.CHARGE); int amountRemoved = sourcePermanent.removeAllCounters(CounterType.CHARGE.getName(), source, game);
sourcePermanent.removeCounters(CounterType.CHARGE.createInstance(chargeCounters), source, game);
sourcePermanent.tap(source, game); sourcePermanent.tap(source, game);
Mana mana = new Mana(); Mana mana = new Mana();
mana.setColorless(chargeCounters); mana.setColorless(amountRemoved);
player.getManaPool().addMana(mana, game, source); player.getManaPool().addMana(mana, game, source);
return true; return true;
} }

View file

@ -70,7 +70,7 @@ class VexingRadgullEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
if (!player.getCounters().containsKey(CounterType.RAD)) { if (player.getCountersCount(CounterType.RAD) == 0) {
return new AddCountersTargetEffect(CounterType.RAD.createInstance(2)) return new AddCountersTargetEffect(CounterType.RAD.createInstance(2))
.setTargetPointer(getTargetPointer().copy()) .setTargetPointer(getTargetPointer().copy())
.apply(game, source); .apply(game, source);

View file

@ -1,7 +1,5 @@
package mage.cards.v; package mage.cards.v;
import java.util.Set;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -18,6 +16,9 @@ import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.Set;
import java.util.UUID;
/** /**
* @author North * @author North
*/ */
@ -61,7 +62,7 @@ enum PoisonedCondition implements Condition {
Player opponent = game.getPlayer(opponentUuid); Player opponent = game.getPlayer(opponentUuid);
if (opponent != null if (opponent != null
&& opponent.isInGame() && opponent.isInGame()
&& opponent.getCounters().getCount(CounterType.POISON) > 0) { && opponent.getCountersCount(CounterType.POISON) > 0) {
return true; return true;
} }
} }

View file

@ -89,7 +89,7 @@ class VraskaBetrayalsStingEffect extends OneShotEffect {
if (targetPlayer == null) { if (targetPlayer == null) {
return false; return false;
} }
int totalPoison = targetPlayer.getCounters().getCount(CounterType.POISON); int totalPoison = targetPlayer.getCountersCount(CounterType.POISON);
if (totalPoison < 9) { if (totalPoison < 9) {
targetPlayer.addCounters(CounterType.POISON.createInstance(9 - totalPoison), source.getControllerId(), source, game); targetPlayer.addCounters(CounterType.POISON.createInstance(9 - totalPoison), source.getControllerId(), source, game);
} }

View file

@ -1,6 +1,5 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
@ -12,20 +11,21 @@ import mage.abilities.keyword.InfectAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author Loki * @author Loki
*/ */
public final class WhisperingSpecter extends CardImpl { public final class WhisperingSpecter extends CardImpl {
public WhisperingSpecter(UUID ownerId, CardSetInfo setInfo) { public WhisperingSpecter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PHYREXIAN);
this.subtype.add(SubType.SPECTER); this.subtype.add(SubType.SPECTER);
@ -67,7 +67,7 @@ class WhisperingSpecterEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) { if (player != null) {
int value = player.getCounters().getCount(CounterType.POISON); int value = player.getCountersCount(CounterType.POISON);
if (value > 0) { if (value > 0) {
player.discard(value, false, false, source, game); player.discard(value, false, false, source, game);
return true; return true;

View file

@ -1,7 +1,5 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.costs.common.PayEnergyCost;
@ -15,8 +13,9 @@ import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author DominionSpy * @author DominionSpy
*/ */
public final class WrathOfTheSkies extends CardImpl { public final class WrathOfTheSkies extends CardImpl {
@ -67,7 +66,7 @@ class WrathOfTheSkiesEffect extends OneShotEffect {
new GetEnergyCountersControllerEffect(xValue).apply(game, source); new GetEnergyCountersControllerEffect(xValue).apply(game, source);
} }
int numberToPay = controller.getAmount(0, controller.getCounters().getCount(CounterType.ENERGY), int numberToPay = controller.getAmount(0, controller.getCountersCount(CounterType.ENERGY),
"Pay any amount of {E}", game); "Pay any amount of {E}", game);
Cost cost = new PayEnergyCost(numberToPay); Cost cost = new PayEnergyCost(numberToPay);
if (cost.pay(source, game, source, source.getControllerId(), true)) { if (cost.pay(source, game, source, source.getControllerId(), true)) {

View file

@ -1,24 +1,23 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.ManaSpentToCastCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.FlashbackAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.AbilityWord; import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.abilities.dynamicvalue.common.ManaSpentToCastCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.token.PhyrexianWurmToken; import mage.game.permanent.token.PhyrexianWurmToken;
import java.util.UUID;
/** /**
*
* @author @stwalsh4118 * @author @stwalsh4118
*/ */
public final class Wurmquake extends CardImpl { public final class Wurmquake extends CardImpl {
@ -67,7 +66,7 @@ class WurmquakeEffect extends OneShotEffect {
new CreateTokenEffect(new PhyrexianWurmToken(xValue)).apply(game, source); new CreateTokenEffect(new PhyrexianWurmToken(xValue)).apply(game, source);
int amount = 0; int amount = 0;
for (UUID opponentId : game.getOpponents(source.getControllerId())) { for (UUID opponentId : game.getOpponents(source.getControllerId())) {
if (game.getPlayer(opponentId).getCounters().getCount(CounterType.POISON) >= 3) { if (game.getPlayer(opponentId).getCountersCount(CounterType.POISON) >= 3) {
amount++; amount++;
} }
} }

View file

@ -105,6 +105,7 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Idol of False Gods", 210, Rarity.UNCOMMON, mage.cards.i.IdolOfFalseGods.class)); cards.add(new SetCardInfo("Idol of False Gods", 210, Rarity.UNCOMMON, mage.cards.i.IdolOfFalseGods.class));
cards.add(new SetCardInfo("Island", 305, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", 305, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("It That Heralds the End", 9, Rarity.UNCOMMON, mage.cards.i.ItThatHeraldsTheEnd.class)); cards.add(new SetCardInfo("It That Heralds the End", 9, Rarity.UNCOMMON, mage.cards.i.ItThatHeraldsTheEnd.class));
cards.add(new SetCardInfo("Izzet Generatorium", 191, Rarity.UNCOMMON, mage.cards.i.IzzetGeneratorium.class));
cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class)); cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class));
cards.add(new SetCardInfo("Junk Diver", 293, Rarity.UNCOMMON, mage.cards.j.JunkDiver.class)); cards.add(new SetCardInfo("Junk Diver", 293, Rarity.UNCOMMON, mage.cards.j.JunkDiver.class));
cards.add(new SetCardInfo("K'rrik, Son of Yawgmoth", 274, Rarity.RARE, mage.cards.k.KrrikSonOfYawgmoth.class)); cards.add(new SetCardInfo("K'rrik, Son of Yawgmoth", 274, Rarity.RARE, mage.cards.k.KrrikSonOfYawgmoth.class));

View file

@ -21,7 +21,6 @@ public class PersistTest extends CardTestPlayerBase {
/** /**
* Tests Safehold Elite don't returns from Persist if already a -1/-1 * Tests Safehold Elite don't returns from Persist if already a -1/-1
* counter was put on it from another source * counter was put on it from another source
*
*/ */
@Test @Test
public void testUndyingdoesntTriggerWithMinusCounter() { public void testUndyingdoesntTriggerWithMinusCounter() {
@ -48,7 +47,7 @@ public class PersistTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Safehold Elite", 1); assertGraveyardCount(playerA, "Safehold Elite", 1);
// one poison counter from Virulent Wound // one poison counter from Virulent Wound
Assert.assertEquals(1, playerA.getCounters().getCount(CounterType.POISON)); Assert.assertEquals(1, playerA.getCountersCount(CounterType.POISON));
} }
/** /**

View file

@ -0,0 +1,95 @@
package org.mage.test.cards.single.mh3;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.players.Player;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class IzzetGeneratoriumTest extends CardTestPlayerBase {
/**
* {@link mage.cards.i.IzzetGeneratorium Izzet Generatorium} {U}{R}
* Artifact
* If you would get one or more {E} (energy counters), you get that many plus one {E} instead.
* {T}: Draw a card. Activate only if youve paid or lost four or more {E} this turn.
*/
private static final String generator = "Izzet Generatorium";
private static void checkEnergyCount(String message, Player player, int expected) {
Assert.assertEquals(message, expected, player.getCountersCount(CounterType.ENERGY));
}
@Test
public void test_Pay_Energy() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, generator);
// When Bristling Hydra enters the battlefield, you get {E}{E}{E} (three energy counters).
// Pay {E}{E}{E}: Put a +1/+1 counter on Bristling Hydra. It gains hexproof until end of turn.
addCard(Zone.HAND, playerA, "Bristling Hydra", 2);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 8);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bristling Hydra", true);
runCode("energy counter is 4", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 4));
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bristling Hydra", true);
runCode("energy counter is 8", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 8));
checkPlayableAbility("1: condition not met before activing once", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw", false);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay {E}{E}{E}");
runCode("energy counter is 5", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 5));
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("2: condition not met before activing twice", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw", false);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay {E}{E}{E}");
runCode("energy counter is 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 2));
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("3: condition met after activing twice", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw", true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, 1);
}
@Test
public void test_Lose_Energy() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, generator);
// When Bristling Hydra enters the battlefield, you get {E}{E}{E} (three energy counters).
// Pay {E}{E}{E}: Put a +1/+1 counter on Bristling Hydra. It gains hexproof until end of turn.
addCard(Zone.HAND, playerA, "Bristling Hydra");
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
// Choose one or more
// Destroy all creatures.
// Destroy all planeswalkers.
// Destroy all battles.
// Exile all graveyards.
// Each opponent loses all counters.
addCard(Zone.HAND, playerB, "Final Act");
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 6);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bristling Hydra", true);
runCode("energy counter is 4", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 4));
checkPlayableAbility("1: condition not met before losing counters", 2, PhaseStep.UPKEEP, playerA, "{T}: Draw", false);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Final Act");
setModeChoice(playerB, "5"); // each opponent loses all counters.
waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN);
runCode("energy counter is 0", 2, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 0));
checkPlayableAbility("2: condition met after losing counters", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw", true);
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, 1);
}
}

View file

@ -24,7 +24,7 @@ public class OtharriSunsGloryTest extends CardTestPlayerBase {
private static final String otharri = "Otharri, Suns' Glory"; private static final String otharri = "Otharri, Suns' Glory";
private static void checkExperienceCounter(String message, Player player, int expected) { private static void checkExperienceCounter(String message, Player player, int expected) {
Assert.assertEquals(message, expected, player.getCounters().getCount(CounterType.EXPERIENCE)); Assert.assertEquals(message, expected, player.getCountersCount(CounterType.EXPERIENCE));
} }
@Test @Test

View file

@ -29,7 +29,7 @@ public class RadCounterTriggerTest extends CardTestPlayerBase {
private static final String fallout = "Nuclear Fallout"; private static final String fallout = "Nuclear Fallout";
private static void checkRadCounterCount(String message, Player player, int expected) { private static void checkRadCounterCount(String message, Player player, int expected) {
Assert.assertEquals(message, expected, player.getCounters().getCount(CounterType.RAD)); Assert.assertEquals(message, expected, player.getCountersCount(CounterType.RAD));
} }
private static void checkGraveyardSize(String message, Player player, int expected) { private static void checkGraveyardSize(String message, Player player, int expected) {

View file

@ -2961,8 +2961,8 @@ public class TestPlayer implements Player {
} }
@Override @Override
public Counters getCounters() { public Counters getCountersAsCopy() {
return computerPlayer.getCounters(); return computerPlayer.getCountersAsCopy();
} }
@Override @Override
@ -3441,8 +3441,33 @@ public class TestPlayer implements Player {
} }
@Override @Override
public void removeCounters(String name, int amount, Ability source, Game game) { public void loseCounters(String counterName, int amount, Ability source, Game game) {
computerPlayer.removeCounters(name, amount, source, game); computerPlayer.loseCounters(counterName, amount, source, game);
}
@Override
public int loseAllCounters(Ability source, Game game) {
return computerPlayer.loseAllCounters(source, game);
}
@Override
public int loseAllCounters(String counterName, Ability source, Game game) {
return computerPlayer.loseAllCounters(counterName, source, game);
}
@Override
public int getCountersCount(CounterType counterType) {
return computerPlayer.getCountersCount(counterType);
}
@Override
public int getCountersCount(String counterName) {
return computerPlayer.getCountersCount(counterName);
}
@Override
public int getCountersTotalCount() {
return computerPlayer.getCountersTotalCount();
} }
@Override @Override

View file

@ -1143,7 +1143,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param count Expected count. * @param count Expected count.
*/ */
public void assertCounterCount(Player player, CounterType type, int count) throws AssertionError { public void assertCounterCount(Player player, CounterType type, int count) throws AssertionError {
Assert.assertEquals("(Battlefield) Counter counts are not equal (" + player.getName() + ':' + type + ')', count, player.getCounters().getCount(type)); Assert.assertEquals("(Battlefield) Counter counts are not equal (" + player.getName() + ':' + type + ')', count, player.getCountersCount(type));
} }
/** /**

View file

@ -13,6 +13,10 @@ import mage.constants.Zone;
*/ */
public class ActivateIfConditionActivatedAbility extends ActivatedAbilityImpl { public class ActivateIfConditionActivatedAbility extends ActivatedAbilityImpl {
public ActivateIfConditionActivatedAbility(Effect effect, Cost cost, Condition condition) {
this(Zone.BATTLEFIELD, effect, cost, condition, TimingRule.INSTANT);
}
public ActivateIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) { public ActivateIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) {
this(zone, effect, cost, condition, TimingRule.INSTANT); this(zone, effect, cost, condition, TimingRule.INSTANT);
} }

View file

@ -27,7 +27,7 @@ public enum AttackedPlayersPoisonedCondition implements Condition {
.distinct() .distinct()
.map(game::getPlayer) .map(game::getPlayer)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.anyMatch(player -> player.getCounters().containsKey(CounterType.POISON)); .anyMatch(player -> player.getCountersCount(CounterType.POISON) > 0);
} }
@Override @Override

View file

@ -6,7 +6,6 @@ import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint; import mage.abilities.hint.Hint;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player;
import java.util.Objects; import java.util.Objects;
@ -24,8 +23,7 @@ public enum CorruptedCondition implements Condition {
.stream() .stream()
.map(game::getPlayer) .map(game::getPlayer)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(Player::getCounters) .anyMatch(player -> player.getCountersCount(CounterType.POISON) >= 3);
.anyMatch(counters -> counters.getCount(CounterType.POISON) >= 3);
} }
@Override @Override

View file

@ -11,6 +11,8 @@ import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
import java.util.UUID;
/** /**
* @author emerald000 * @author emerald000
*/ */
@ -31,14 +33,14 @@ public class PayEnergyCost extends CostImpl {
@Override @Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
Player player = game.getPlayer(controllerId); Player player = game.getPlayer(controllerId);
return player != null && player.getCounters().getCount(CounterType.ENERGY) >= amount; return player != null && player.getCountersCount(CounterType.ENERGY) >= amount;
} }
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player player = game.getPlayer(controllerId); Player player = game.getPlayer(controllerId);
if (player != null && player.getCounters().getCount(CounterType.ENERGY) >= amount) { if (player != null && player.getCountersCount(CounterType.ENERGY) >= amount) {
player.getCounters().removeCounter(CounterType.ENERGY, amount); player.loseCounters(CounterType.ENERGY.getName(), amount, source, game);
paid = true; paid = true;
} }
return paid; return paid;

View file

@ -38,10 +38,7 @@ public class RemoveAllCountersSourceCost extends CostImpl {
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Permanent permanent = game.getPermanent(ability.getSourceId()); Permanent permanent = game.getPermanent(ability.getSourceId());
if (permanent != null) { if (permanent != null) {
this.removedCounters = permanent.getCounters(game).getCount(counterType); this.removedCounters = permanent.removeAllCounters(counterType.getName(), source, game);
if (this.removedCounters > 0) {
permanent.removeCounters(counterType.createInstance(this.removedCounters), source, game);
}
} }
this.paid = true; this.paid = true;
return true; return true;

View file

@ -20,7 +20,7 @@ public enum OpponentsPoisonCountersCount implements DynamicValue {
for (UUID playerUUID : playerList) { for (UUID playerUUID : playerList) {
Player player = game.getPlayer(playerUUID); Player player = game.getPlayer(playerUUID);
if (player != null) { if (player != null) {
amount += player.getCounters().getCount(CounterType.POISON); amount += player.getCountersCount(CounterType.POISON);
} }
} }
return amount; return amount;

View file

@ -32,7 +32,7 @@ public enum SourceControllerCountersCount implements DynamicValue {
int amount = 0; int amount = 0;
Player player = game.getPlayer(sourceAbility.getControllerId()); Player player = game.getPlayer(sourceAbility.getControllerId());
if (player != null) { if (player != null) {
amount = player.getCounters().getCount(counterType); amount = player.getCountersCount(counterType);
} }
return amount; return amount;
} }

View file

@ -35,8 +35,7 @@ public class RemoveAllCountersSourceEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null) { if (sourcePermanent != null) {
int count = sourcePermanent.getCounters(game).getCount(counterType); sourcePermanent.removeAllCounters(counterType.getName(), source, game);
sourcePermanent.removeCounters(counterType.getName(), count, source, game);
return true; return true;
} }
return false; return false;

View file

@ -76,7 +76,8 @@ public class ProliferateEffect extends OneShotEffect {
if (player == null) { if (player == null) {
continue; continue;
} }
for (Counter counter : player.getCounters().values()) { for (Counter counter : player.getCountersAsCopy().values()) {
// TODO: this does not work with ability counters that are not explicitly in CounterType. Like the Hexproof from XXX counters from Indominus Rex, Alpha
Counter newCounter = CounterType.findByName(counter.getName()).createInstance(); Counter newCounter = CounterType.findByName(counter.getName()).createInstance();
if (player.addCounters(newCounter, source.getControllerId(), source, game)) { if (player.addCounters(newCounter, source.getControllerId(), source, game)) {
game.informPlayers(player.getLogName() + " had " + newCounter.getDescription() + " added to them."); game.informPlayers(player.getLogName() + " had " + newCounter.getDescription() + " added to them.");

View file

@ -0,0 +1,53 @@
package mage.abilities.effects.common.counter;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* Removes all counters (optionally of a given counter type) from the target permanent.
*
* @author MTGfan
*/
public class RemoveAllCountersPermanentTargetEffect extends OneShotEffect {
private final CounterType counterType; // If not null, remove counters of that type only.
public RemoveAllCountersPermanentTargetEffect() {
this((CounterType) null);
}
public RemoveAllCountersPermanentTargetEffect(CounterType counterType) {
super(Outcome.Neutral);
this.counterType = counterType;
staticText = "remove all " + (counterType == null ? "" : counterType.getName() + " ") + "counters from it.";
}
public RemoveAllCountersPermanentTargetEffect(RemoveAllCountersPermanentTargetEffect effect) {
super(effect);
this.counterType = effect.counterType;
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (counterType == null) {
permanent.removeAllCounters(source, game);
} else {
permanent.removeAllCounters(counterType.getName(), source, game);
}
return true;
}
return false;
}
@Override
public RemoveAllCountersPermanentTargetEffect copy() {
return new RemoveAllCountersPermanentTargetEffect(this);
}
}

View file

@ -1,45 +0,0 @@
package mage.abilities.effects.common.counter;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author MTGfan
*/
public class RemoveAllCountersTargetEffect extends OneShotEffect {
private final CounterType counterType;
public RemoveAllCountersTargetEffect(CounterType counterType) {
super(Outcome.Neutral);
this.counterType = counterType;
staticText = "remove all " + counterType.getName() + " counters from it.";
}
public RemoveAllCountersTargetEffect(RemoveAllCountersTargetEffect effect) {
super(effect);
this.counterType = effect.counterType;
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if(permanent != null) {
int count = permanent.getCounters(game).getCount(counterType);
permanent.removeCounters(counterType.getName(), count, source, game);
return true;
}
return false;
}
@Override
public RemoveAllCountersTargetEffect copy() {
return new RemoveAllCountersTargetEffect(this);
}
}

View file

@ -88,11 +88,13 @@ public interface Card extends MageObject, Ownerable {
/** /**
* Is this an extra deck card? (such as contraptions and attractions) * Is this an extra deck card? (such as contraptions and attractions)
*
* @return true if this is an extra deck card, false otherwise * @return true if this is an extra deck card, false otherwise
*/ */
default boolean isExtraDeckCard() { default boolean isExtraDeckCard() {
return false; return false;
} }
void assignNewId(); void assignNewId();
void addInfo(String key, String value, Game game); void addInfo(String key, String value, Game game);
@ -168,17 +170,64 @@ public interface Card extends MageObject, Ownerable {
boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List<UUID> appliedEffects, boolean isEffect, int maxCounters); boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List<UUID> appliedEffects, boolean isEffect, int maxCounters);
default void removeCounters(String name, int amount, Ability source, Game game){ /**
removeCounters(name, amount, source, game, false); * Remove {@param amount} counters of the specified kind.
*/
default void removeCounters(String counterName, int amount, Ability source, Game game) {
removeCounters(counterName, amount, source, game, false);
} }
void removeCounters(String name, int amount, Ability source, Game game, boolean damage); /**
* Remove {@param amount} counters of the specified kind.
*
* @param isDamage if the counter removal is a result of being damaged (e.g. for Deification to work)
*/
void removeCounters(String counterName, int amount, Ability source, Game game, boolean isDamage);
default void removeCounters(Counter counter, Ability source, Game game) { default void removeCounters(Counter counter, Ability source, Game game) {
removeCounters(counter, source, game, false); removeCounters(counter, source, game, false);
} }
void removeCounters(Counter counter, Ability source, Game game, boolean damage); /**
* Remove all counters of any kind.
*
* @param isDamage if the counter removal is a result of being damaged (e.g. for Deification to work)
*/
void removeCounters(Counter counter, Ability source, Game game, boolean isDamage);
/**
* Remove all counters of any kind.
*
* @return the amount of counters removed this way.
*/
default int removeAllCounters(Ability source, Game game) {
return removeAllCounters(source, game, false);
}
/**
* Remove all counters of any kind.
*
* @param isDamage if the counter removal is a result of being damaged (e.g. for Deification to work)
* @return the amount of counters removed this way.
*/
int removeAllCounters(Ability source, Game game, boolean isDamage);
/**
* Remove all counters of a specific kind. Return the amount of counters removed this way.
*
* @return the amount of counters removed this way.
*/
default int removeAllCounters(String counterName, Ability source, Game game) {
return removeAllCounters(counterName, source, game, false);
}
/**
* Remove all counters of a specific kind. Return the amount of counters removed this way.
*
* @param isDamage if the counter removal is a result of being damaged (e.g. for Deification to work)
* @return the amount of counters removed this way.
*/
int removeAllCounters(String counterName, Ability source, Game game, boolean isDamage);
@Override @Override
Card copy(); Card copy();

View file

@ -803,39 +803,40 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
@Override @Override
public void removeCounters(String name, int amount, Ability source, Game game, boolean isDamage) { public void removeCounters(String counterName, int amount, Ability source, Game game, boolean isDamage) {
if (amount <= 0){ if (amount <= 0) {
return; return;
} }
if (getCounters(game).getCount(name) <= 0){ if (getCounters(game).getCount(counterName) <= 0) {
return; return;
} }
GameEvent removeCountersEvent = new RemoveCountersEvent(name, this, source, amount, isDamage); GameEvent removeCountersEvent = new RemoveCountersEvent(counterName, this, source, amount, isDamage);
if (game.replaceEvent(removeCountersEvent)){ if (game.replaceEvent(removeCountersEvent)) {
return; return;
} }
int finalAmount = 0; int finalAmount = 0;
for (int i = 0; i < removeCountersEvent.getAmount(); i++) { for (int i = 0; i < removeCountersEvent.getAmount(); i++) {
GameEvent event = new RemoveCounterEvent(name, this, source, isDamage); GameEvent event = new RemoveCounterEvent(counterName, this, source, isDamage);
if (game.replaceEvent(event)){ if (game.replaceEvent(event)) {
continue; continue;
} }
if (!getCounters(game).removeCounter(name, 1)) { if (!getCounters(game).removeCounter(counterName, 1)) {
break; break;
} }
event = new CounterRemovedEvent(name, this, source, isDamage); event = new CounterRemovedEvent(counterName, this, source, isDamage);
game.fireEvent(event); game.fireEvent(event);
finalAmount++; finalAmount++;
} }
GameEvent event = new CountersRemovedEvent(name, this, source, finalAmount, isDamage);
GameEvent event = new CountersRemovedEvent(counterName, this, source, finalAmount, isDamage);
game.fireEvent(event); game.fireEvent(event);
} }
@ -846,6 +847,24 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
} }
@Override
public int removeAllCounters(Ability source, Game game, boolean isDamage) {
int amountBefore = getCounters(game).getTotalCount();
for (Counter counter : getCounters(game).copy().values()) {
removeCounters(counter.getName(), counter.getCount(), source, game, isDamage);
}
int amountAfter = getCounters(game).getTotalCount();
return Math.max(0, amountBefore - amountAfter);
}
@Override
public int removeAllCounters(String counterName, Ability source, Game game, boolean isDamage) {
int amountBefore = getCounters(game).getCount(counterName);
removeCounters(counterName, amountBefore, source, game, isDamage);
int amountAfter = getCounters(game).getCount(counterName);
return Math.max(0, amountBefore - amountAfter);
}
@Override @Override
public String getLogName() { public String getLogName() {
if (name.isEmpty()) { if (name.isEmpty()) {

View file

@ -223,8 +223,8 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
} }
@Override @Override
public void removeCounters(String name, int amount, Ability source, Game game) { public void removeCounters(String counterName, int amount, Ability source, Game game) {
leftHalfCard.removeCounters(name, amount, source, game); leftHalfCard.removeCounters(counterName, amount, source, game);
} }
@Override @Override

View file

@ -27,35 +27,17 @@ public class Counters extends HashMap<String, Counter> implements Serializable,
return new Counters(this); return new Counters(this);
} }
public Counters addCounter(String name, int amount) {
putIfAbsent(name, new Counter(name));
this.get(name).add(amount);
return this;
}
public Counters addCounter(Counter counter) { public Counters addCounter(Counter counter) {
if (!containsKey(counter.name)) { if (!containsKey(counter.name)) {
put(counter.name, counter); put(counter.name, counter);
} else { } else {
get(counter.name).add(counter.getCount()); get(counter.name).add(counter.getCount());
} }
return this; return this;
} }
public boolean removeCounter(String name) {
return removeCounter(name, 1);
}
public boolean removeCounter(CounterType counterType, int amount) { public boolean removeCounter(CounterType counterType, int amount) {
if (this.containsKey(counterType.getName())) { return removeCounter(counterType.getName(), amount);
get(counterType.getName()).remove(amount);
if (get(counterType.getName()).count == 0) {
this.remove(counterType.getName());
}
return true;
}
return false;
} }
public boolean removeCounter(String name, int amount) { public boolean removeCounter(String name, int amount) {
@ -69,17 +51,6 @@ public class Counters extends HashMap<String, Counter> implements Serializable,
return false; return false;
} }
public void removeAllCounters(CounterType counterType) {
removeAllCounters(counterType.getName());
}
public void removeAllCounters(String name) {
if (this.containsKey(name)) {
this.remove(name);
}
}
public int getCount(String name) { public int getCount(String name) {
if (this.containsKey(name)) { if (this.containsKey(name)) {
return this.get(name).getCount(); return this.get(name).getCount();
@ -91,6 +62,10 @@ public class Counters extends HashMap<String, Counter> implements Serializable,
return getCount(counterType) > 0; return getCount(counterType) > 0;
} }
public int getTotalCount() {
return this.values().stream().mapToInt(Counter::getCount).sum();
}
public int getCount(CounterType type) { public int getCount(CounterType type) {
if (this.containsKey(type.getName())) { if (this.containsKey(type.getName())) {
return this.get(type.getName()).getCount(); return this.get(type.getName()).getCount();

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