mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
refactor: improved search in stack
This commit is contained in:
parent
26adccdfd5
commit
384ce67cc3
20 changed files with 101 additions and 119 deletions
|
|
@ -398,7 +398,10 @@ public class ComputerPlayer6 extends ComputerPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resolve(SimulationNode2 node, int depth, Game game) {
|
protected void resolve(SimulationNode2 node, int depth, Game game) {
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
|
if (stackObject == null) {
|
||||||
|
throw new IllegalStateException("Catch empty stack on resolve (something wrong with sim code)");
|
||||||
|
}
|
||||||
if (stackObject instanceof StackAbility) {
|
if (stackObject instanceof StackAbility) {
|
||||||
// AI hint for search effects (calc all possible cards for best score)
|
// AI hint for search effects (calc all possible cards for best score)
|
||||||
SearchEffect effect = getSearchEffect((StackAbility) stackObject);
|
SearchEffect effect = getSearchEffect((StackAbility) stackObject);
|
||||||
|
|
|
||||||
|
|
@ -638,8 +638,8 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
// Check check if the spell being paid for cares about the color of mana being paid
|
// Check check if the spell being paid for cares about the color of mana being paid
|
||||||
// See: https://github.com/magefree/mage/issues/9070
|
// See: https://github.com/magefree/mage/issues/9070
|
||||||
boolean caresAboutManaColor = false;
|
boolean caresAboutManaColor = false;
|
||||||
if (!game.getStack().isEmpty() && game.getStack().getFirst() instanceof Spell) {
|
if (game.getStack().getFirstOrNull() instanceof Spell) {
|
||||||
Spell spellBeingCast = (Spell) game.getStack().getFirst();
|
Spell spellBeingCast = (Spell) game.getStack().getFirstOrNull();
|
||||||
if (!spellBeingCast.isResolving() && spellBeingCast.getControllerId().equals(this.getId())) {
|
if (!spellBeingCast.isResolving() && spellBeingCast.getControllerId().equals(this.getId())) {
|
||||||
CardImpl card = (CardImpl) game.getCard(spellBeingCast.getSourceId());
|
CardImpl card = (CardImpl) game.getCard(spellBeingCast.getSourceId());
|
||||||
caresAboutManaColor = card.caresAboutManaColor(game);
|
caresAboutManaColor = card.caresAboutManaColor(game);
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,7 @@ class AstralDriftTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (game.getState().getStack().isEmpty()) {
|
StackObject item = game.getState().getStack().getFirstOrNull();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
StackObject item = game.getState().getStack().getFirst();
|
|
||||||
if (!(item instanceof StackAbility
|
if (!(item instanceof StackAbility
|
||||||
&& item.getStackAbility() instanceof CyclingAbility)) {
|
&& item.getStackAbility() instanceof CyclingAbility)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,9 @@ class CobraTrapWatcher extends Watcher {
|
||||||
if (event.getType() == GameEvent.EventType.DESTROYED_PERMANENT) {
|
if (event.getType() == GameEvent.EventType.DESTROYED_PERMANENT) {
|
||||||
Permanent perm = game.getPermanentOrLKIBattlefield(event.getTargetId()); // can regenerate or be indestructible
|
Permanent perm = game.getPermanentOrLKIBattlefield(event.getTargetId()); // can regenerate or be indestructible
|
||||||
if (perm != null && !perm.isCreature(game)) {
|
if (perm != null && !perm.isCreature(game)) {
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject spell = game.getStack().getStackObject(event.getSourceId());
|
||||||
StackObject spell = game.getStack().getStackObject(event.getSourceId());
|
if (spell != null && game.getOpponents(perm.getControllerId()).contains(spell.getControllerId())) {
|
||||||
if (spell != null && game.getOpponents(perm.getControllerId()).contains(spell.getControllerId())) {
|
players.add(perm.getControllerId());
|
||||||
players.add(perm.getControllerId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.r;
|
package mage.cards.r;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
|
|
@ -10,20 +8,20 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class RainOfGore extends CardImpl {
|
public final class RainOfGore extends CardImpl {
|
||||||
|
|
||||||
public RainOfGore(UUID ownerId, CardSetInfo setInfo) {
|
public RainOfGore(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{R}");
|
||||||
|
|
||||||
|
|
||||||
// If a spell or ability would cause its controller to gain life, that player loses that much life instead.
|
// If a spell or ability would cause its controller to gain life, that player loses that much life instead.
|
||||||
|
|
@ -71,13 +69,10 @@ class RainOfGoreEffect extends ReplacementEffectImpl {
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
return event.getType() == GameEvent.EventType.GAIN_LIFE;
|
return event.getType() == GameEvent.EventType.GAIN_LIFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
return stackObject != null && stackObject.isControlledBy(event.getPlayerId());
|
||||||
return stackObject.isControlledBy(event.getPlayerId());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,13 +120,8 @@ enum SoulSculptorCondition implements Condition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
return stackObject != null && !stackObject.getCardType(game).contains(CardType.CREATURE);
|
||||||
if (stackObject != null) {
|
|
||||||
return !stackObject.getCardType(game).contains(CardType.CREATURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -94,18 +95,22 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
Spell spell = (Spell) game.getStack().getFirst();
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
if (!spell.isCopy() && !spell.isCountered()) {
|
if (stackObject instanceof Spell) {
|
||||||
Card sourceCard = game.getCard(spellId);
|
Spell spell = (Spell) stackObject;
|
||||||
if (sourceCard != null && Zone.STACK.equals(game.getState().getZone(spellId))) {
|
if (!spell.isCopy() && !spell.isCountered()) {
|
||||||
Player player = game.getPlayer(sourceCard.getOwnerId());
|
Card sourceCard = game.getCard(spellId);
|
||||||
if (player != null) {
|
if (sourceCard != null && Zone.STACK.equals(game.getState().getZone(spellId))) {
|
||||||
player.moveCards(sourceCard, Zone.HAND, source, game);
|
Player player = game.getPlayer(sourceCard.getOwnerId());
|
||||||
discard();
|
if (player != null) {
|
||||||
return true;
|
player.moveCards(sourceCard, Zone.HAND, source, game);
|
||||||
|
discard();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,8 +139,8 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect
|
||||||
if (zEvent.getFromZone() == Zone.STACK
|
if (zEvent.getFromZone() == Zone.STACK
|
||||||
&& zEvent.getToZone() == Zone.GRAVEYARD
|
&& zEvent.getToZone() == Zone.GRAVEYARD
|
||||||
&& event.getTargetId().equals(spellId)) {
|
&& event.getTargetId().equals(spellId)) {
|
||||||
if (game.getStack().getFirst() instanceof Spell) {
|
if (game.getStack().getFirstOrNull() instanceof Spell) {
|
||||||
Card cardOfSpell = ((Spell) game.getStack().getFirst()).getCard();
|
Card cardOfSpell = ((Spell) game.getStack().getFirstOrNull()).getCard();
|
||||||
return cardOfSpell.getMainCard().getId().equals(spellId);
|
return cardOfSpell.getMainCard().getId().equals(spellId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,12 +99,10 @@ enum FirstSpellCastFromNotHandEachTurnCondition implements Condition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
if (game.getStack().isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TheTwelfthDoctorWatcher watcher = game.getState().getWatcher(TheTwelfthDoctorWatcher.class);
|
TheTwelfthDoctorWatcher watcher = game.getState().getWatcher(TheTwelfthDoctorWatcher.class);
|
||||||
StackObject so = game.getStack().getFirst();
|
StackObject so = game.getStack().getFirstOrNull();
|
||||||
return watcher != null
|
return so != null
|
||||||
|
&& watcher != null
|
||||||
&& TheTwelfthDoctorWatcher.checkSpell(so, game);
|
&& TheTwelfthDoctorWatcher.checkSpell(so, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,11 @@ class ValiantRescuerTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
ValiantRescuerWatcher watcher = game.getState().getWatcher(ValiantRescuerWatcher.class);
|
ValiantRescuerWatcher watcher = game.getState().getWatcher(ValiantRescuerWatcher.class);
|
||||||
if (watcher == null
|
if (watcher == null
|
||||||
|| !watcher.checkSpell(event.getPlayerId(), event.getSourceId())
|
|| !watcher.checkSpell(event.getPlayerId(), event.getSourceId())
|
||||||
|| game.getState().getStack().isEmpty()
|
|
||||||
|| !event.getPlayerId().equals(this.getControllerId())
|
|| !event.getPlayerId().equals(this.getControllerId())
|
||||||
|| event.getSourceId().equals(this.getSourceId())) {
|
|| event.getSourceId().equals(this.getSourceId())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StackObject item = game.getState().getStack().getFirst();
|
StackObject item = game.getState().getStack().getFirstOrNull();
|
||||||
return item instanceof StackAbility
|
return item instanceof StackAbility
|
||||||
&& item.getStackAbility() instanceof CyclingAbility;
|
&& item.getStackAbility() instanceof CyclingAbility;
|
||||||
}
|
}
|
||||||
|
|
@ -106,11 +105,10 @@ class ValiantRescuerWatcher extends Watcher {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void watch(GameEvent event, Game game) {
|
public void watch(GameEvent event, Game game) {
|
||||||
if (event.getType() != GameEvent.EventType.ACTIVATED_ABILITY
|
if (event.getType() != GameEvent.EventType.ACTIVATED_ABILITY) {
|
||||||
|| game.getState().getStack().isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StackObject item = game.getState().getStack().getFirst();
|
StackObject item = game.getState().getStack().getFirstOrNull();
|
||||||
if (item instanceof StackAbility
|
if (item instanceof StackAbility
|
||||||
&& item.getStackAbility() instanceof CyclingAbility) {
|
&& item.getStackAbility() instanceof CyclingAbility) {
|
||||||
playerMap.computeIfAbsent(event.getPlayerId(), u -> new HashMap<>());
|
playerMap.computeIfAbsent(event.getPlayerId(), u -> new HashMap<>());
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ package mage.cards.w;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.keyword.CascadeAbility;
|
import mage.abilities.keyword.CascadeAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
|
@ -11,14 +14,12 @@ import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
|
import mage.players.Player;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.condition.Condition;
|
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
|
||||||
import mage.players.Player;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
|
|
@ -35,7 +36,7 @@ public final class WildMagicSorcerer extends CardImpl {
|
||||||
|
|
||||||
// The first spell you cast from exile each turn has cascade.
|
// The first spell you cast from exile each turn has cascade.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
this.addAbility(new SimpleStaticAbility(
|
||||||
new WildMagicSorcererGainCascadeFirstSpellCastFromExileEffect()),
|
new WildMagicSorcererGainCascadeFirstSpellCastFromExileEffect()),
|
||||||
new WildMagicSorcererWatcher());
|
new WildMagicSorcererWatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,12 +97,10 @@ enum FirstSpellCastFromExileEachTurnCondition implements Condition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
if (game.getStack().isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
WildMagicSorcererWatcher watcher = game.getState().getWatcher(WildMagicSorcererWatcher.class);
|
WildMagicSorcererWatcher watcher = game.getState().getWatcher(WildMagicSorcererWatcher.class);
|
||||||
StackObject so = game.getStack().getFirst();
|
StackObject so = game.getStack().getFirstOrNull();
|
||||||
return watcher != null
|
return so != null
|
||||||
|
&& watcher != null
|
||||||
&& WildMagicSorcererWatcher.checkSpell(so, game);
|
&& WildMagicSorcererWatcher.checkSpell(so, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ public class DisguiseTest extends CardTestPlayerBase {
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dog Walker using Disguise");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dog Walker using Disguise");
|
||||||
runCode("face up on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
runCode("face up on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
Assert.assertEquals("stack, server - can't find spell", 1, currentGame.getStack().size());
|
Assert.assertEquals("stack, server - can't find spell", 1, currentGame.getStack().size());
|
||||||
SpellAbility spellAbility = (SpellAbility) currentGame.getStack().getFirst().getStackAbility();
|
SpellAbility spellAbility = (SpellAbility) currentGame.getStack().getFirstOrNull().getStackAbility();
|
||||||
Assert.assertEquals("stack, server - can't find spell", "Cast Dog Walker using Disguise", spellAbility.getName());
|
Assert.assertEquals("stack, server - can't find spell", "Cast Dog Walker using Disguise", spellAbility.getName());
|
||||||
CardView spellView = getGameView(playerA).getStack().values().stream().findFirst().orElse(null);
|
CardView spellView = getGameView(playerA).getStack().values().stream().findFirst().orElse(null);
|
||||||
Assert.assertNotNull("stack, client: can't find spell", spellView);
|
Assert.assertNotNull("stack, client: can't find spell", spellView);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public class DisturbTest extends CardTestPlayerBase {
|
||||||
checkStackObject("on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb", 1);
|
checkStackObject("on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb", 1);
|
||||||
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
// Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same)
|
// Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same)
|
||||||
Spell spell = (Spell) game.getStack().getFirst();
|
Spell spell = (Spell) game.getStack().getFirstOrNull();
|
||||||
Assert.assertEquals("Hook-Haunt Drifter", spell.getName());
|
Assert.assertEquals("Hook-Haunt Drifter", spell.getName());
|
||||||
Assert.assertEquals(1, spell.getCardType(game).size());
|
Assert.assertEquals(1, spell.getCardType(game).size());
|
||||||
Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0));
|
Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0));
|
||||||
|
|
@ -91,7 +91,7 @@ public class DisturbTest extends CardTestPlayerBase {
|
||||||
checkStackObject("on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Waildrifter using Disturb", 1);
|
checkStackObject("on stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Waildrifter using Disturb", 1);
|
||||||
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
// Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same)
|
// Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same)
|
||||||
Spell spell = (Spell) game.getStack().getFirst();
|
Spell spell = (Spell) game.getStack().getFirstOrNull();
|
||||||
Assert.assertEquals("Waildrifter", spell.getName());
|
Assert.assertEquals("Waildrifter", spell.getName());
|
||||||
Assert.assertEquals(1, spell.getCardType(game).size());
|
Assert.assertEquals(1, spell.getCardType(game).size());
|
||||||
Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0));
|
Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0));
|
||||||
|
|
@ -187,7 +187,7 @@ public class DisturbTest extends CardTestPlayerBase {
|
||||||
// cast with disturb
|
// cast with disturb
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb");
|
||||||
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
Spell spell = (Spell) game.getStack().getFirst();
|
Spell spell = (Spell) game.getStack().getFirstOrNull();
|
||||||
Assert.assertEquals("mana value must be from main side", 2, spell.getManaValue());
|
Assert.assertEquals("mana value must be from main side", 2, spell.getManaValue());
|
||||||
Assert.assertEquals("mana cost to pay must be modified", "{U}", spell.getSpellAbility().getManaCostsToPay().getText());
|
Assert.assertEquals("mana cost to pay must be modified", "{U}", spell.getSpellAbility().getManaCostsToPay().getText());
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -334,11 +334,8 @@ public class TestPlayer implements Player {
|
||||||
return true;
|
return true;
|
||||||
} else if (groups[2].startsWith("spellOnTopOfStack=")) {
|
} else if (groups[2].startsWith("spellOnTopOfStack=")) {
|
||||||
String spellOnTopOFStack = groups[2].substring(18);
|
String spellOnTopOFStack = groups[2].substring(18);
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
return stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack);
|
||||||
return stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if (groups[2].startsWith("manaInPool=")) {
|
} else if (groups[2].startsWith("manaInPool=")) {
|
||||||
String manaInPool = groups[2].substring(11);
|
String manaInPool = groups[2].substring(11);
|
||||||
int amountOfMana = Integer.parseInt(manaInPool);
|
int amountOfMana = Integer.parseInt(manaInPool);
|
||||||
|
|
|
||||||
|
|
@ -53,11 +53,9 @@ public abstract class SpecialAction extends ActivatedAbilityImpl {
|
||||||
if (isManaAction()) {
|
if (isManaAction()) {
|
||||||
// limit play mana abilities by steps
|
// limit play mana abilities by steps
|
||||||
int currentStepOrder = 0;
|
int currentStepOrder = 0;
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
if (stackObject instanceof Spell) {
|
||||||
if (stackObject instanceof Spell) {
|
currentStepOrder = ((Spell) stackObject).getCurrentActivatingManaAbilitiesStep().getStepOrder();
|
||||||
currentStepOrder = ((Spell) stackObject).getCurrentActivatingManaAbilitiesStep().getStepOrder();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (currentStepOrder > manaAbility.useOnActivationManaAbilityStep().getStepOrder()) {
|
if (currentStepOrder > manaAbility.useOnActivationManaAbilityStep().getStepOrder()) {
|
||||||
return ActivationStatus.getFalse();
|
return ActivationStatus.getFalse();
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,7 @@ public class CycleAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (game.getState().getStack().isEmpty()) {
|
StackObject item = game.getState().getStack().getFirstOrNull();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
StackObject item = game.getState().getStack().getFirst();
|
|
||||||
return item instanceof StackAbility
|
return item instanceof StackAbility
|
||||||
&& item.getStackAbility() instanceof CyclingAbility;
|
&& item.getStackAbility() instanceof CyclingAbility;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,11 @@ public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (game.getState().getStack().isEmpty()
|
if (!event.getPlayerId().equals(this.getControllerId())
|
||||||
|| !event.getPlayerId().equals(this.getControllerId())
|
|
||||||
|| (event.getSourceId().equals(this.getSourceId()) && excludeSource)) {
|
|| (event.getSourceId().equals(this.getSourceId()) && excludeSource)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StackObject item = game.getState().getStack().getFirst();
|
StackObject item = game.getState().getStack().getFirstOrNull();
|
||||||
return item instanceof StackAbility
|
return item instanceof StackAbility
|
||||||
&& item.getStackAbility() instanceof CyclingAbility;
|
&& item.getStackAbility() instanceof CyclingAbility;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,25 +18,24 @@ public enum SunburstCount implements DynamicValue {
|
||||||
@Override
|
@Override
|
||||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if (!game.getStack().isEmpty()) {
|
|
||||||
StackObject spell = game.getStack().getFirst();
|
StackObject spell = game.getStack().getFirstOrNull();
|
||||||
if (spell instanceof Spell && ((Spell) spell).getSourceId().equals(sourceAbility.getSourceId())) {
|
if (spell instanceof Spell && spell.getSourceId().equals(sourceAbility.getSourceId())) {
|
||||||
Mana mana = ((Spell) spell).getSpellAbility().getManaCostsToPay().getUsedManaToPay();
|
Mana mana = ((Spell) spell).getSpellAbility().getManaCostsToPay().getUsedManaToPay();
|
||||||
if (mana.getBlack() > 0) {
|
if (mana.getBlack() > 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (mana.getBlue() > 0) {
|
if (mana.getBlue() > 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (mana.getGreen() > 0) {
|
if (mana.getGreen() > 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (mana.getRed() > 0) {
|
if (mana.getRed() > 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (mana.getWhite() > 0) {
|
if (mana.getWhite() > 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
|
|
|
||||||
|
|
@ -513,13 +513,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
||||||
// If the top card of your library changes while you’re casting a spell, playing a land, or activating an ability,
|
// If the top card of your library changes while you’re casting a spell, playing a land, or activating an ability,
|
||||||
// you can’t look at the new top card until you finish doing so. This means that if you cast the top card of
|
// you can’t look at the new top card until you finish doing so. This means that if you cast the top card of
|
||||||
// your library, you can’t look at the next one until you’re done paying for that spell. (2019-05-03)
|
// your library, you can’t look at the next one until you’re done paying for that spell. (2019-05-03)
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
return !(stackObject instanceof Spell)
|
||||||
return !(stackObject instanceof Spell)
|
|| !Zone.LIBRARY.equals(((Spell) stackObject).getFromZone())
|
||||||
|| !Zone.LIBRARY.equals(((Spell) stackObject).getFromZone())
|
|| stackObject.getStackAbility().getManaCostsToPay().isPaid(); // mana payment finished
|
||||||
|| stackObject.getStackAbility().getManaCostsToPay().isPaid(); // mana payment finished
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -44,19 +44,16 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
||||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||||
// check if player is in the process of playing spell costs and they are no longer allowed to use
|
// check if player is in the process of playing spell costs and they are no longer allowed to use
|
||||||
// activated mana abilities (e.g. because they started to use improvise or convoke)
|
// activated mana abilities (e.g. because they started to use improvise or convoke)
|
||||||
if (!game.getStack().isEmpty()) {
|
StackObject stackObject = game.getStack().getFirstOrNull();
|
||||||
StackObject stackObject = game.getStack().getFirst();
|
if (stackObject instanceof Spell) {
|
||||||
if (stackObject instanceof Spell) {
|
switch (((Spell) stackObject).getCurrentActivatingManaAbilitiesStep()) {
|
||||||
switch (((Spell) stackObject).getCurrentActivatingManaAbilitiesStep()) {
|
case BEFORE:
|
||||||
case BEFORE:
|
case NORMAL:
|
||||||
case NORMAL:
|
break;
|
||||||
break;
|
case AFTER:
|
||||||
case AFTER:
|
return ActivationStatus.getFalse();
|
||||||
return ActivationStatus.getFalse();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.canActivate(playerId, game);
|
return super.canActivate(playerId, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,16 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated // must use getFirstOrNull instead
|
||||||
|
public StackObject getFirst() {
|
||||||
|
return super.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackObject getFirstOrNull() {
|
||||||
|
return this.isEmpty() ? null : this.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean remove(StackObject object, Game game) {
|
public boolean remove(StackObject object, Game game) {
|
||||||
for (StackObject spell : this) {
|
for (StackObject spell : this) {
|
||||||
if (spell.getId().equals(object.getId())) {
|
if (spell.getId().equals(object.getId())) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue