a few more getId fixes

This commit is contained in:
Evan Kranzler 2022-02-26 10:23:13 -05:00
parent 2025bca358
commit cf9a2f936a
5 changed files with 183 additions and 254 deletions

View file

@ -1,13 +1,9 @@
package mage.cards.h;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.InvertCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.HasteAbility;
@ -17,22 +13,21 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.counters.CounterType;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.Spell;
import mage.watchers.Watcher;
import java.util.*;
/**
*
* @author jeffwadsworth
* @author TheElk801
*/
public final class HotheadedGiant extends CardImpl {
public HotheadedGiant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
this.subtype.add(SubType.GIANT);
this.subtype.add(SubType.WARRIOR);
@ -43,8 +38,10 @@ public final class HotheadedGiant extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// Hotheaded Giant enters the battlefield with two -1/-1 counters on it unless you've cast another red spell this turn.
Condition condition = new CastRedSpellThisTurnCondition();
this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), new InvertCondition(condition), ""), "with two -1/-1 counters on it unless you've cast another red spell this turn"), new HotHeadedGiantWatcher(this.getId()));
this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(
new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)),
HotheadedGiantWatcher::checkSpell, ""
), "with two -1/-1 counters on it unless you've cast another red spell this turn"), new HotheadedGiantWatcher());
}
@ -58,50 +55,40 @@ public final class HotheadedGiant extends CardImpl {
}
}
class CastRedSpellThisTurnCondition implements Condition {
class HotheadedGiantWatcher extends Watcher {
@Override
public boolean apply(Game game, Ability source) {
HotHeadedGiantWatcher watcher = game.getState().getWatcher(HotHeadedGiantWatcher.class, source.getControllerId());
if (watcher != null) {
return watcher.conditionMet();
}
return false;
}
}
private final Map<UUID, List<MageObjectReference>> spellMap = new HashMap<>();
private static final List<MageObjectReference> emptyList = new ArrayList<>();
class HotHeadedGiantWatcher extends Watcher {
private static final FilterSpell filter = new FilterSpell();
static {
filter.add(new ColorPredicate(ObjectColor.RED));
}
private UUID cardId;
public HotHeadedGiantWatcher(UUID cardId) {
super(WatcherScope.PLAYER);
this.cardId = cardId;
HotheadedGiantWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (condition == true) { //no need to check - condition has already occured
if (event.getType() != EventType.SPELL_CAST) {
return;
}
if (event.getType() == GameEvent.EventType.SPELL_CAST
&& controllerId.equals(event.getPlayerId())) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) {
condition = true;
}
Spell spell = game.getSpell(event.getSourceId());
if (spell != null && spell.getColor(game).isRed()) {
spellMap.computeIfAbsent(event.getPlayerId(), x -> new ArrayList<>())
.add(new MageObjectReference(event.getSourceId(), game));
}
}
@Override
public void reset() {
super.reset();
condition = false;
spellMap.clear();
}
static boolean checkSpell(Game game, Ability source) {
return game.getState()
.getWatcher(HotheadedGiantWatcher.class)
.spellMap
.getOrDefault(source.getControllerId(), emptyList)
.stream()
.noneMatch(mor -> !mor.getSourceId().equals(source.getSourceId())
|| mor.getZoneChangeCounter() != source.getSourceObjectZoneChangeCounter());
}
}

View file

@ -1,8 +1,5 @@
package mage.cards.r;
import java.util.Objects;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.Condition;
@ -14,30 +11,30 @@ import mage.abilities.effects.common.DestroySourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetAnyTarget;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author MarcoMarin
* @author TheElk801
*/
public final class RocketLauncher extends CardImpl {
public RocketLauncher(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
Watcher watcher = new RocketLauncherWatcher(this.getId());
// {2}: Rocket Launcher deals 1 damage to any target. Destroy Rocket Launcher at the beginning of the next end step. Activate this ability only if you've controlled Rocket Launcher continuously since the beginning of your most recent turn.
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD,
new DamageTargetEffect(1), new GenericManaCost(2), ControlledTurnCondition.instance);
Ability ability = new ConditionalActivatedAbility(
Zone.BATTLEFIELD, new DamageTargetEffect(1),
new GenericManaCost(2), RocketLauncherCondition.instance);
ability.addTarget(new TargetAnyTarget());
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DestroySourceEffect(true))));
this.addAbility(ability, watcher);
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DestroySourceEffect(true))
).setText("destroy {this} at the beginning of the next end step"));
this.addAbility(ability);
}
private RocketLauncher(final RocketLauncher card) {
@ -50,56 +47,12 @@ public final class RocketLauncher extends CardImpl {
}
}
class RocketLauncherWatcher extends Watcher {
private boolean changedControllerOR1stTurn;
private UUID cardId = null;
public RocketLauncherWatcher(UUID cardId) {
super(WatcherScope.GAME);
this.changedControllerOR1stTurn = true;
this.cardId = cardId;
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.CLEANUP_STEP_POST) {
changedControllerOR1stTurn = false;
}
if (event.getType() == GameEvent.EventType.LOST_CONTROL &&
Objects.equals(event.getTargetId(), cardId)) {
changedControllerOR1stTurn = true;
}
}
@Override
public void reset() {
super.reset();
changedControllerOR1stTurn = true; //when is this reset called? may cause problems if in mid-life
}
public boolean isChangedControllerOR1stTurn() {
return changedControllerOR1stTurn;
}
}
enum ControlledTurnCondition implements Condition {
enum RocketLauncherCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
RocketLauncherWatcher watcher = game.getState().getWatcher(RocketLauncherWatcher.class);
return watcher != null && !watcher.isChangedControllerOR1stTurn();
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
return permanent != null && !permanent.wasControlledFromStartOfControllerTurn();
}
@Override
public String toString() {
return "Permanent hasn't changed controller NOR entered this turn";
}
}

View file

@ -1,19 +1,14 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageObjectReference;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.WatcherScope;
import mage.filter.FilterSpell;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
@ -26,9 +21,10 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.*;
/**
*
* @author jeffwadsworth
* @author TheElk801
*/
public final class SoulReap extends CardImpl {
@ -38,17 +34,13 @@ public final class SoulReap extends CardImpl {
filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN)));
}
private static final String rule = "Its controller loses 3 life if you've cast another black spell this turn";
public SoulReap(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
// Destroy target nongreen creature. Its controller loses 3 life if you've cast another black spell this turn.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new SoulReapEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SoulReapEffect(), new CastBlackSpellThisTurnCondition(), rule));
this.getSpellAbility().addWatcher(new SoulReapWatcher(this.getId()));
this.getSpellAbility().addWatcher(new SoulReapWatcher());
}
private SoulReap(final SoulReap card) {
@ -61,59 +53,12 @@ public final class SoulReap extends CardImpl {
}
}
class CastBlackSpellThisTurnCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
SoulReapWatcher watcher = game.getState().getWatcher(SoulReapWatcher.class, source.getControllerId());
if (watcher != null) {
return watcher.conditionMet();
}
return false;
}
}
class SoulReapWatcher extends Watcher {
private static final FilterSpell filter = new FilterSpell();
static {
filter.add(new ColorPredicate(ObjectColor.BLACK));
}
private UUID cardId;
public SoulReapWatcher(UUID cardId) {
super(WatcherScope.PLAYER);
this.cardId = cardId;
}
@Override
public void watch(GameEvent event, Game game) {
if (condition == true) { //no need to check - condition has already occured
return;
}
if (event.getType() == GameEvent.EventType.SPELL_CAST
&& controllerId.equals(event.getPlayerId())) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) {
condition = true;
}
}
}
@Override
public void reset() {
super.reset();
condition = false;
}
}
class SoulReapEffect extends OneShotEffect {
public SoulReapEffect() {
super(Outcome.Detriment);
this.staticText = "Its controller loses 3 life if you've cast another black spell this turn";
this.staticText = "destroy target nongreen creature. Its controller " +
"loses 3 life if you've cast another black spell this turn";
}
public SoulReapEffect(final SoulReapEffect effect) {
@ -127,14 +72,56 @@ class SoulReapEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent creature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
if (creature != null) {
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (creature == null) {
return false;
}
creature.destroy(source, game);
if (!SoulReapWatcher.checkSpell(source, game)) {
return true;
}
Player controller = game.getPlayer(creature.getControllerId());
if (controller != null) {
controller.loseLife(3, game, source, false);
}
return true;
}
}
class SoulReapWatcher extends Watcher {
private final Map<UUID, List<MageObjectReference>> spellMap = new HashMap<>();
private static final List<MageObjectReference> emptyList = new ArrayList<>();
SoulReapWatcher() {
super(WatcherScope.GAME);
}
return false;
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != EventType.SPELL_CAST) {
return;
}
Spell spell = game.getSpell(event.getSourceId());
if (spell != null && spell.getColor(game).isBlack()) {
spellMap.computeIfAbsent(event.getPlayerId(), x -> new ArrayList<>())
.add(new MageObjectReference(event.getSourceId(), game));
}
}
@Override
public void reset() {
super.reset();
spellMap.clear();
}
static boolean checkSpell(Ability source, Game game) {
return game.getState()
.getWatcher(SoulReapWatcher.class)
.spellMap
.getOrDefault(source.getControllerId(), emptyList)
.stream()
.anyMatch(mor -> !mor.getSourceId().equals(source.getSourceId())
|| mor.getZoneChangeCounter() != source.getSourceObjectZoneChangeCounter());
}
}

View file

@ -1,38 +1,31 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.Spell;
import mage.watchers.Watcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author jeffwadsworth
* @author TheElk801
*/
public final class TalarasBattalion extends CardImpl {
public TalarasBattalion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.subtype.add(SubType.ELF);
this.subtype.add(SubType.WARRIOR);
@ -43,7 +36,10 @@ public final class TalarasBattalion extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Cast Talara's Battalion only if you've cast another green spell this turn.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new TalarasBattalionEffect()), new TalarasBattalionWatcher(this.getId()));
this.addAbility(new CastOnlyIfConditionIsTrueAbility(
TalarasBattalionWatcher::checkSpell,
"cast {this} only if you've cast another green spell this turn"
), new TalarasBattalionWatcher());
}
@ -57,82 +53,32 @@ public final class TalarasBattalion extends CardImpl {
}
}
class TalarasBattalionEffect extends ContinuousRuleModifyingEffectImpl {
TalarasBattalionEffect() {
super(Duration.EndOfGame, Outcome.Detriment);
staticText = "Cast this spell only if you've cast another green spell this turn";
}
TalarasBattalionEffect(final TalarasBattalionEffect effect) {
super(effect);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.CAST_SPELL
&& event.getSourceId().equals(source.getSourceId())) {
CastGreenSpellThisTurnCondition condition = new CastGreenSpellThisTurnCondition();
return (!condition.apply(game, source));
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public TalarasBattalionEffect copy() {
return new TalarasBattalionEffect(this);
}
}
class CastGreenSpellThisTurnCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
TalarasBattalionWatcher watcher = game.getState().getWatcher(TalarasBattalionWatcher.class, source.getControllerId());
if (watcher != null) {
return watcher.conditionMet();
}
return false;
}
}
class TalarasBattalionWatcher extends Watcher {
private static final FilterSpell filter = new FilterSpell();
private final Set<UUID> playerSet = new HashSet<>();
static {
filter.add(new ColorPredicate(ObjectColor.GREEN));
}
private final UUID cardId;
public TalarasBattalionWatcher(UUID cardId) {
super(WatcherScope.PLAYER);
this.cardId = cardId;
TalarasBattalionWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (condition == true) { //no need to check - condition has already occured
if (event.getType() != EventType.SPELL_CAST) {
return;
}
if (event.getType() == GameEvent.EventType.SPELL_CAST
&& controllerId.equals(event.getPlayerId())) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) {
condition = true;
}
Spell spell = game.getSpell(event.getSourceId());
if (spell != null && spell.getColor(game).isGreen()) {
playerSet.add(spell.getControllerId());
}
}
@Override
public void reset() {
super.reset();
condition = false;
playerSet.clear();
}
static boolean checkSpell(Game game, Ability source) {
return game.getState().getWatcher(TalarasBattalionWatcher.class).playerSet.contains(source.getControllerId());
}
}

View file

@ -0,0 +1,56 @@
package org.mage.test.cards.single.eve;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class SoulReapTest extends CardTestPlayerBase {
private static final String reap = "Soul Reap";
private static final String lion = "Silvercoat Lion";
private static final String rats = "Muck Rats";
@Test
public void t() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, reap);
addCard(Zone.HAND, playerA, rats);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rats);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, reap, lion);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, lion, 0);
assertPermanentCount(playerA, rats, 1);
assertGraveyardCount(playerA, lion, 1);
assertGraveyardCount(playerA, reap, 1);
assertLife(playerA, 20 - 3);
}
@Test
public void t2() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, reap);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, reap, lion);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, lion, 0);
assertGraveyardCount(playerA, lion, 1);
assertGraveyardCount(playerA, reap, 1);
assertLife(playerA, 20);
}
}