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 static mage.constants.Constants.*;
import mage.constants.ManaType;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.designations.DesignationType;
import mage.utils.timer.PriorityTimer;
import mage.view.*;
@ -186,6 +184,18 @@ public class PlayerPanelExt extends javax.swing.JPanel {
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) {
this.player = player;
int pastLife = player.getLife();
@ -226,10 +236,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
changedFontLife = false;
}
setTextForLabel("life", lifeLabel, life, playerLife, true);
setTextForLabel("poison", poisonLabel, poison, player.getCounters().getCount(CounterType.POISON), false);
setTextForLabel("energy", energyLabel, energy, player.getCounters().getCount(CounterType.ENERGY), false);
setTextForLabel("experience", experienceLabel, experience, player.getCounters().getCount(CounterType.EXPERIENCE), false);
setTextForLabel("rad", radLabel, rad, player.getCounters().getCount(CounterType.RAD), false);
setTextForLabel("poison", poisonLabel, poison, counterOfName(player, "poison"), false);
setTextForLabel("energy", energyLabel, energy, counterOfName(player, "energy"), false);
setTextForLabel("experience", experienceLabel, experience, counterOfName(player, "experience"), false);
setTextForLabel("rad", radLabel, rad, counterOfName(player, "rad"), false);
setTextForLabel("hand zone", handLabel, hand, player.getHandCount(), true);
int libraryCards = player.getLibraryCount();
if (libraryCards > 99) {
@ -417,7 +427,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
}
// counters
for (Counter counter : player.getCounters().values()) {
for (CounterView counter : player.getCounters()) {
tooltipText.append("<br/>").append(counter.getName()).append(" counters: ").append(counter.getCount());
}

View file

@ -1,7 +1,7 @@
package mage.view;
import mage.cards.Card;
import mage.counters.Counters;
import mage.counters.Counter;
import mage.designations.Designation;
import mage.game.ExileZone;
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 isHuman; // human or computer
private final int life;
private final Counters counters;
private final List<CounterView> counters;
private final int wins;
private final int winsNeeded;
private final int libraryCount;
@ -64,7 +64,6 @@ public class PlayerView implements Serializable {
this.controlled = player.getId().equals(createdForPlayerId);
this.isHuman = player.isHuman();
this.life = player.getLife();
this.counters = player.getCounters();
this.wins = player.getMatchPlayer().getWins();
this.winsNeeded = player.getMatchPlayer().getWinsNeeded();
this.libraryCount = player.getLibrary().size();
@ -158,6 +157,10 @@ public class PlayerView implements Serializable {
for (Designation designation : player.getDesignations()) {
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) {
@ -187,7 +190,7 @@ public class PlayerView implements Serializable {
return this.life;
}
public Counters getCounters() {
public List<CounterView> getCounters() {
return this.counters;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,7 +21,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Susucr
*/
public final class BewitchingLeechcraft extends CardImpl {
@ -87,10 +86,12 @@ class BewitchingLeechcraftReplacementEffect extends ReplacementEffectImpl {
if (!applies(event, source, game)) {
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 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

View file

@ -3,21 +3,16 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @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.
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());
this.addAbility(ability);
}
@ -50,35 +45,3 @@ public final class BlitzLeech extends CardImpl {
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) {
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
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);
}
if (creature == null) {

View file

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

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
@ -18,8 +16,9 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.TargetSpell;
import java.util.UUID;
/**
*
* @author @stwalsh4118
*/
public final class BringTheEnding extends CardImpl {
@ -70,7 +69,7 @@ class BringTheEndingCounterEffect extends OneShotEffect {
UUID controllerId = game.getControllerId(targetId);
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());
return hardCounterEffect.apply(game, source);
} else {

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
@ -18,18 +16,15 @@ import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterAttackingOrBlockingCreature;
import mage.game.Game;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author zeffirojoe
*/
public final class CattiBrieOfMithralHall extends CardImpl {
@ -56,15 +51,12 @@ public final class CattiBrieOfMithralHall extends CardImpl {
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever Catti-brie of Mithral Hall attacks, put a +1/+1 counter on it for
// each Equipment attached to it.
// Whenever Catti-brie of Mithral Hall attacks, put a +1/+1 counter on it for each Equipment attached to it.
EquipmentAttachedCount amount = new EquipmentAttachedCount();
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")));
// {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.
// {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.
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}"));
damageAbility.addTarget(new TargetCreaturePermanent(filter));

View file

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

View file

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

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
@ -20,8 +19,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author L_J
*/
public final class Corrosion extends CardImpl {
@ -112,7 +112,7 @@ class CorrosionRemoveCountersEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
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;
}

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
@ -14,8 +13,9 @@ import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSpell;
import java.util.UUID;
/**
*
* @author Loki
*/
public final class CorruptedResolve extends CardImpl {
@ -54,9 +54,10 @@ class CorruptedResolveEffect extends OneShotEffect {
Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source));
if (spell != null) {
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 false;
}

View file

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

View file

@ -1,7 +1,6 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -18,12 +17,12 @@ import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class DelayingShield extends CardImpl {
@ -103,9 +102,8 @@ class DelayingShieldUpkeepEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
int numCounters = permanent.getCounters(game).getCount(CounterType.DELAY);
permanent.removeCounters(CounterType.DELAY.createInstance(numCounters), source, game);
for (int i = numCounters; i > 0; i--) {
int countersRemoved = permanent.removeAllCounters(CounterType.DELAY.getName(), source, game);
for (int i = countersRemoved; i > 0; i--) {
if (controller.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", source, game)) {
Cost cost = new ManaCostsImpl<>("{1}{W}");
if (cost.pay(source, game, source, source.getControllerId(), false, null)) {

View file

@ -1,7 +1,6 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayEnergyCost;
@ -21,8 +20,9 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class DieYoung extends CardImpl {
@ -66,7 +66,7 @@ class DieYoungEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
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);
if (numberToPayed > 0) {
Cost cost = new PayEnergyCost(numberToPayed);

View file

@ -86,7 +86,7 @@ class EzuriClawOfProgressEffect extends OneShotEffect {
if (controller != null) {
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
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);
}
return true;

View file

@ -62,7 +62,7 @@ class FeedTheInfectionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
for (UUID playerId : game.getOpponents(source.getControllerId())) {
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);
}
}

View file

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

View file

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

View file

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

View file

@ -63,7 +63,7 @@ class GalvanicDischargeEffect extends OneShotEffect {
return false;
}
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) {
return true;
}

View file

@ -64,7 +64,7 @@ enum GethsSummonsAdjuster implements TargetAdjuster {
// corrupted opponents' graveyards
for (UUID opponentId : game.getOpponents(ability.getControllerId(), true)) {
Player opponent = game.getPlayer(opponentId);
if (opponent == null || opponent.getCounters().getCount(CounterType.POISON) < 3) {
if (opponent == null || opponent.getCountersCount(CounterType.POISON) < 3) {
continue;
}
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.RemoveDelayedTriggeredAbilityEffect;
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.CardSetInfo;
import mage.constants.*;
@ -127,7 +127,7 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect {
class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbility {
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));
}

View file

@ -1,7 +1,6 @@
package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
@ -17,8 +16,9 @@ import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class GiveTake extends SplitCard {
@ -65,20 +65,18 @@ class TakeEffect extends OneShotEffect {
@Override
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());
if (controller != null) {
controller.drawCards(numberCounters, source, game);
} else {
throw new UnsupportedOperationException("Controller missing");
if (controller == null) {
return false;
}
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 false;
}
}

View file

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

View file

@ -141,7 +141,7 @@ class HammerJammerEffect extends OneShotEffect {
if (controller != null && permanent != null) {
Integer amount = (Integer) getValue("rolled");
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) {
permanent.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game);
}

View file

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

View file

@ -2,8 +2,9 @@
package mage.cards.h;
import java.util.UUID;
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.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -13,7 +14,6 @@ import mage.counters.CounterType;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author fireshoes
*/
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.
getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn));
getSpellAbility().addEffect(new RemoveAllCountersTargetEffect(CounterType.M1M1));
getSpellAbility().addEffect(new RemoveAllCountersPermanentTargetEffect(CounterType.M1M1));
getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
}

View file

@ -62,7 +62,7 @@ class HarnessedLightningEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
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) {
Cost cost = new PayEnergyCost(numberToPay);
if (cost.pay(source, game, source, source.getControllerId(), true)) {

View file

@ -79,7 +79,7 @@ class IxhelScionOfAtraxaEffect extends OneShotEffect {
Cards cards = new CardsImpl();
for (UUID opponentId : game.getOpponents(source.getControllerId(), true)) {
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;
}
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
));
// {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.
// {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.
SimpleActivatedAbility ability = new SimpleActivatedAbility(
new LookLibraryAndPickControllerEffect(JarOfEyeballsValue.instance, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
new GenericManaCost(3));

View file

@ -60,9 +60,9 @@ class LeechesEffect extends OneShotEffect {
return false;
}
int countPoisonCounters = targetPlayer.getCounters().getCount(CounterType.POISON);
int countPoisonCounters = targetPlayer.getCountersCount(CounterType.POISON);
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);
return true;
}

View file

@ -11,7 +11,7 @@ import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.BoostCounter;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate;
@ -85,7 +85,7 @@ class LesserWerewolfEffect extends OneShotEffect {
}
if (sourcePermanent.getPower().getValue() >= 1) {
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;
}

View file

@ -34,9 +34,7 @@ public final class LightningCoils extends CardImpl {
new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true),
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
// 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.
// 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.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LightningCoilsEffect(), TargetController.YOU, false));
}
@ -64,12 +62,12 @@ class LightningCoilsEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent p = game.getPermanent(source.getSourceId());
if (p != null && controller != null) {
int counters = p.getCounters(game).getCount(CounterType.CHARGE);
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && controller != null) {
int counters = permanent.getCounters(game).getCount(CounterType.CHARGE);
if (counters >= 5) {
// 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);
effect.apply(game, source);

View file

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

View file

@ -1,7 +1,5 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
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.GainLifeEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.*;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author Cguy7777
*/
@ -51,8 +51,7 @@ public final class LilyBowenRagingGrandma extends CardImpl {
CounterType.P1P1.createInstance(2)),
"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.
// Otherwise, remove all but one +1/+1 counter from it, then you gain 1 life for each +1/+1 counter removed this way.
// 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.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new ConditionalOneShotEffect(
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.
int count = permanent.getCounters(game).getCount(CounterType.P1P1);
if (count <= 1) {
int countBefore = permanent.getCounters(game).getCount(CounterType.P1P1);
if (countBefore <= 1) {
return true;
}
int countToRemove = count - 1;
int countToRemove = countBefore - 1;
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;
}

View file

@ -1,7 +1,6 @@
package mage.cards.l;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -12,13 +11,14 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.BoostCounter;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Derpthemeus
*/
public final class LivingArmor extends CardImpl {
@ -63,7 +63,7 @@ public final class LivingArmor extends CardImpl {
Permanent creature = game.getPermanent(source.getTargets().getFirstTarget());
if (creature != null) {
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 false;

View file

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

View file

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

View file

@ -5,9 +5,9 @@ import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
@ -17,11 +17,9 @@ import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.watchers.Watcher;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@ -49,7 +47,7 @@ public final class MarchesaResoluteMonarch extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance());
// 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));
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 {
private final Set<UUID> players = new HashSet<>();

View file

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

View file

@ -78,7 +78,7 @@ class MerenOfClanNelTothEffect extends OneShotEffect {
if (player == null || card == null) {
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);
}
}

View file

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

View file

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

View file

@ -64,6 +64,6 @@ enum NightkinAmbusherCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
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;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -19,6 +18,8 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author Loki
*/
@ -62,15 +63,13 @@ class OblivionStoneEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
for (Permanent p : game.getBattlefield().getAllActivePermanents()) {
if (!(p.isLand(game) || p.getCounters(game).containsKey(CounterType.FATE))) {
p.destroy(source, game, false);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) {
if (!(permanent.isLand(game) || permanent.getCounters(game).containsKey(CounterType.FATE))) {
permanent.destroy(source, game, false);
}
}
for (Permanent p : game.getBattlefield().getAllActivePermanents()) {
if (p.getCounters(game).containsKey(CounterType.FATE)) {
p.removeCounters(CounterType.FATE.getName(), p.getCounters(game).getCount(CounterType.FATE), source, game);
}
for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) {
permanent.removeAllCounters(CounterType.FATE.getName(), source, game);
}
return true;
}

View file

@ -64,7 +64,7 @@ class PhyresisOutbreakEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
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);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_A_CREATURE, opponentId, game)) {
effect.setTargetPointer(new FixedTarget(permanent, game));

View file

@ -60,7 +60,7 @@ class PhyrexianAtlasEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
for (UUID playerId : game.getOpponents(source.getControllerId())) {
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);
}
}

View file

@ -6,6 +6,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.counters.Counter;
import mage.filter.FilterOpponent;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterPermanentOrPlayer;
@ -106,17 +107,17 @@ class PriceOfBetrayalEffect extends OneShotEffect {
if (player != null) {
int toRemove = 5;
int removed = 0;
String[] counterNames = player.getCounters().keySet().toArray(new String[0]);
for (String counterName : counterNames) {
for (Counter counter : player.getCountersAsCopy().values()) {
String counterName = counter.getName();
if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) {
if (player.getCounters().get(counterName).getCount() == 1 || (toRemove - removed == 1)) {
player.removeCounters(counterName, 1, source, game);
if (player.getCountersCount(counterName) == 1 || (toRemove - removed == 1)) {
player.loseCounters(counterName, 1, source, game);
removed++;
} 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) {
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 {
private static final Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND);
public QuicksilverFountain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// 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.
// 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.
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new QuicksilverFountainEffect(), TargetController.ANY, false, true);
ability.addTarget(new TargetLandPermanent());
ability.setTargetAdjuster(QuicksilverFountainAdjuster.instance);
this.addAbility(ability);
// At the beginning of each end step, if all lands on the battlefield are
// Islands, remove all flood counters from them.
// At the beginning of each end step, if all lands on the battlefield are Islands, remove all flood counters from them.
// Note: This applies only if Quicksilver Fountain is on the battlefield
Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND);
this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD,
new QuicksilverFountainEffect2(), TargetController.ANY, condition, false));
}
@ -130,7 +128,7 @@ class QuicksilverFountainEffect2 extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
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;
}

View file

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

View file

@ -41,9 +41,7 @@ public class RogueSkycaptain extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// 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.
// 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.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RogueSkycaptainEffect(), TargetController.YOU, false));
}
@ -62,7 +60,8 @@ class RogueSkycaptainEffect extends OneShotEffect {
RogueSkycaptainEffect() {
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) {

View file

@ -96,10 +96,9 @@ class SarulfRealmEaterEffect extends OneShotEffect {
if (player == null || permanent == null) {
return false;
}
int counterCount = permanent.getCounters(game).getCount(CounterType.P1P1);
permanent.removeCounters(CounterType.P1P1.createInstance(counterCount), source, game);
int removedThisWay = permanent.removeAllCounters(CounterType.P1P1.getName(), source, game);
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);
Cards cards = new CardsImpl();
game.getBattlefield()

View file

@ -1,7 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
@ -9,17 +8,17 @@ import mage.abilities.keyword.InfectAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author Loki
*/
public final class SepticRats extends CardImpl {
@ -70,7 +69,7 @@ class SepticRatsTriggeredAbility extends TriggeredAbilityImpl {
if (event.getSourceId().equals(this.getSourceId())) {
Player target = game.getPlayer(event.getTargetId());
if (target != null) {
if (target.getCounters().getCount(CounterType.POISON) > 0) {
if (target.getCountersCount(CounterType.POISON) > 0) {
return true;
}
}

View file

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

View file

@ -1,6 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -27,8 +26,9 @@ import mage.game.permanent.token.SaprolingToken;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author L_J
*/
public final class Sporogenesis extends CardImpl {
@ -152,7 +152,7 @@ class SporogenesisRemoveCountersEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
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;
}

View file

@ -1,19 +1,18 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.constants.SubType;
import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.counters.Counter;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@ -21,8 +20,9 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class Suncleanser extends CardImpl {
@ -38,13 +38,13 @@ public final class Suncleanser extends CardImpl {
// 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.
Ability ability = new EntersBattlefieldTriggeredAbility(
new SuncleanserRemoveCountersEffect(false), false
new RemoveAllCountersPermanentTargetEffect(), false
);
ability.addEffect(new SuncleanserPreventCountersEffect(false));
ability.addTarget(new TargetCreaturePermanent());
// 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.addTarget(new TargetOpponent());
ability.addMode(mode);
@ -61,45 +61,31 @@ public final class Suncleanser extends CardImpl {
}
}
class SuncleanserRemoveCountersEffect extends OneShotEffect {
class SuncleanserRemoveCountersPlayerEffect extends OneShotEffect {
SuncleanserRemoveCountersEffect(boolean player) {
super(Outcome.Benefit);
if (player) {
SuncleanserRemoveCountersPlayerEffect() {
super(Outcome.Detriment);
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);
}
@Override
public SuncleanserRemoveCountersEffect copy() {
return new SuncleanserRemoveCountersEffect(this);
public SuncleanserRemoveCountersPlayerEffect copy() {
return new SuncleanserRemoveCountersPlayerEffect(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;
}
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) {
for (Counter counter : player.getCounters().copy().values()) { // copy to prevent ConcurrentModificationException
player.removeCounters(counter.getName(), counter.getCount(), source, game);
}
return true;
}
if (player == null) {
return false;
}
player.loseAllCounters(source, game);
return true;
}
}
class SuncleanserPreventCountersEffect extends ContinuousRuleModifyingEffectImpl {

View file

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

View file

@ -1,6 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BecomesTappedTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -21,8 +20,9 @@ import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class TemporalDistortion extends CardImpl {
@ -74,7 +74,7 @@ class TemporalDistortionRemovalEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
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;
}

View file

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

View file

@ -1,26 +1,21 @@
package mage.cards.v;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
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.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
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 java.util.UUID;
/**
*
* @author Loki, nantuko
*/
public final class VampireHexmage extends CardImpl {
@ -35,9 +30,13 @@ public final class VampireHexmage extends CardImpl {
this.addAbility(FirstStrikeAbility.getInstance());
SimpleActivatedAbility vampireHexmageAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VampireHexmageEffect(), new SacrificeSourceCost());
vampireHexmageAbility.addTarget(new TargetPermanent());
this.addAbility(vampireHexmageAbility);
// Sacrifice Vampire Hexmage: Remove all counters from target permanent.
Ability ability = new SimpleActivatedAbility(
new RemoveAllCountersPermanentTargetEffect(),
new SacrificeSourceCost()
);
ability.addTarget(new TargetPermanent());
this.addAbility(ability);
}
private VampireHexmage(final VampireHexmage card) {
@ -49,33 +48,3 @@ public final class VampireHexmage extends CardImpl {
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;
}
int numberToPay = controller.getAmount(
0, controller.getCounters().getCount(CounterType.ENERGY),
0, controller.getCountersCount(CounterType.ENERGY),
"How many {E} do you like to pay?", game
);
if (numberToPay <= 0) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,5 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayEnergyCost;
@ -15,8 +13,9 @@ import mage.counters.CounterType;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author DominionSpy
*/
public final class WrathOfTheSkies extends CardImpl {
@ -67,7 +66,7 @@ class WrathOfTheSkiesEffect extends OneShotEffect {
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);
Cost cost = new PayEnergyCost(numberToPay);
if (cost.pay(source, game, source, source.getControllerId(), true)) {

View file

@ -1,24 +1,23 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability;
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.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType;
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.game.Game;
import mage.game.permanent.token.PhyrexianWurmToken;
import java.util.UUID;
/**
*
* @author @stwalsh4118
*/
public final class Wurmquake extends CardImpl {
@ -67,7 +66,7 @@ class WurmquakeEffect extends OneShotEffect {
new CreateTokenEffect(new PhyrexianWurmToken(xValue)).apply(game, source);
int amount = 0;
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++;
}
}

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("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("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("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));

View file

@ -21,7 +21,6 @@ public class PersistTest extends CardTestPlayerBase {
/**
* Tests Safehold Elite don't returns from Persist if already a -1/-1
* counter was put on it from another source
*
*/
@Test
public void testUndyingdoesntTriggerWithMinusCounter() {
@ -48,7 +47,7 @@ public class PersistTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Safehold Elite", 1);
// 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 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

View file

@ -29,7 +29,7 @@ public class RadCounterTriggerTest extends CardTestPlayerBase {
private static final String fallout = "Nuclear Fallout";
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) {

View file

@ -2961,8 +2961,8 @@ public class TestPlayer implements Player {
}
@Override
public Counters getCounters() {
return computerPlayer.getCounters();
public Counters getCountersAsCopy() {
return computerPlayer.getCountersAsCopy();
}
@Override
@ -3441,8 +3441,33 @@ public class TestPlayer implements Player {
}
@Override
public void removeCounters(String name, int amount, Ability source, Game game) {
computerPlayer.removeCounters(name, amount, source, game);
public void loseCounters(String counterName, int amount, Ability source, Game 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

View file

@ -1143,7 +1143,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param count Expected count.
*/
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 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) {
this(zone, effect, cost, condition, TimingRule.INSTANT);
}

View file

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

View file

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

View file

@ -11,6 +11,8 @@ import mage.util.CardUtil;
import java.util.UUID;
import java.util.UUID;
/**
* @author emerald000
*/
@ -31,14 +33,14 @@ public class PayEnergyCost extends CostImpl {
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
Player player = game.getPlayer(controllerId);
return player != null && player.getCounters().getCount(CounterType.ENERGY) >= amount;
return player != null && player.getCountersCount(CounterType.ENERGY) >= amount;
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player player = game.getPlayer(controllerId);
if (player != null && player.getCounters().getCount(CounterType.ENERGY) >= amount) {
player.getCounters().removeCounter(CounterType.ENERGY, amount);
if (player != null && player.getCountersCount(CounterType.ENERGY) >= amount) {
player.loseCounters(CounterType.ENERGY.getName(), amount, source, game);
paid = true;
}
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) {
Permanent permanent = game.getPermanent(ability.getSourceId());
if (permanent != null) {
this.removedCounters = permanent.getCounters(game).getCount(counterType);
if (this.removedCounters > 0) {
permanent.removeCounters(counterType.createInstance(this.removedCounters), source, game);
}
this.removedCounters = permanent.removeAllCounters(counterType.getName(), source, game);
}
this.paid = true;
return true;

View file

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

View file

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

View file

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

View file

@ -76,7 +76,8 @@ public class ProliferateEffect extends OneShotEffect {
if (player == null) {
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();
if (player.addCounters(newCounter, source.getControllerId(), source, game)) {
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)
*
* @return true if this is an extra deck card, false otherwise
*/
default boolean isExtraDeckCard() {
return false;
}
void assignNewId();
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);
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) {
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
Card copy();

View file

@ -803,17 +803,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
}
@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) {
return;
}
if (getCounters(game).getCount(name) <= 0){
if (getCounters(game).getCount(counterName) <= 0) {
return;
}
GameEvent removeCountersEvent = new RemoveCountersEvent(name, this, source, amount, isDamage);
GameEvent removeCountersEvent = new RemoveCountersEvent(counterName, this, source, amount, isDamage);
if (game.replaceEvent(removeCountersEvent)) {
return;
}
@ -821,21 +821,22 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
int finalAmount = 0;
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)) {
continue;
}
if (!getCounters(game).removeCounter(name, 1)) {
if (!getCounters(game).removeCounter(counterName, 1)) {
break;
}
event = new CounterRemovedEvent(name, this, source, isDamage);
event = new CounterRemovedEvent(counterName, this, source, isDamage);
game.fireEvent(event);
finalAmount++;
}
GameEvent event = new CountersRemovedEvent(name, this, source, finalAmount, isDamage);
GameEvent event = new CountersRemovedEvent(counterName, this, source, finalAmount, isDamage);
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
public String getLogName() {
if (name.isEmpty()) {

View file

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

View file

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

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