Fix Wheel of Potential (#5983)

* Wheel of Potential revision

* Logic cleanup

---------

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.60>
This commit is contained in:
tool4ever
2024-08-24 11:25:36 +00:00
committed by GitHub
parent 6a503ccdbd
commit 30a358dda1
9 changed files with 26 additions and 42 deletions

View File

@@ -64,7 +64,6 @@ import forge.util.Aggregates;
import forge.util.ComparatorUtil; import forge.util.ComparatorUtil;
import forge.util.Expressions; import forge.util.Expressions;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb; import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
@@ -437,11 +436,11 @@ public class AiController {
} }
landList = CardLists.filter(landList, c -> { landList = CardLists.filter(landList, c -> {
CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield);
if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) { if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) {
return false; return false;
} }
String name = c.getName(); String name = c.getName();
CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield);
if (c.getType().isLegendary() && !name.equals("Flagstones of Trokair")) { if (c.getType().isLegendary() && !name.equals("Flagstones of Trokair")) {
if (Iterables.any(battlefield, CardPredicates.nameEquals(name))) { if (Iterables.any(battlefield, CardPredicates.nameEquals(name))) {
return false; return false;
@@ -461,11 +460,8 @@ public class AiController {
} }
// don't play the land if it has cycling and enough lands are available // don't play the land if it has cycling and enough lands are available
final FCollectionView<SpellAbility> spellAbilities = c.getSpellAbilities(); if (c.hasKeyword(Keyword.CYCLING)) {
for (final SpellAbility sa : spellAbilities) { return false;
if (sa.isCycling()) {
return false;
}
} }
} }
return Iterables.any(c.getAllPossibleAbilities(player, true), SpellAbility::isLandAbility); return Iterables.any(c.getAllPossibleAbilities(player, true), SpellAbility::isLandAbility);

View File

@@ -14,7 +14,6 @@ import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.cost.CostPart; import forge.game.cost.CostPart;
import forge.game.cost.CostPayEnergy; import forge.game.cost.CostPayEnergy;
import forge.game.cost.CostPutCounter; import forge.game.cost.CostPutCounter;
@@ -32,18 +31,12 @@ public class ComputerUtilAbility {
if (!game.getStack().isEmpty() || !game.getPhaseHandler().getPhase().isMain()) { if (!game.getStack().isEmpty() || !game.getPhaseHandler().getPhase().isMain()) {
return null; return null;
} }
final CardCollection hand = new CardCollection(player.getCardsIn(ZoneType.Hand)); CardCollection landList = new CardCollection(player.getCardsIn(ZoneType.Hand));
hand.addAll(player.getCardsIn(ZoneType.Exile));
CardCollection landList = CardLists.filter(hand, Presets.LANDS);
//filter out cards that can't be played //filter out cards that can't be played
landList = CardLists.filter(landList, c -> { landList = CardLists.filter(landList, c -> {
if (!c.getSVar("NeedsToPlay").isEmpty()) { if (!c.hasPlayableLandFace()) {
final String needsToPlay = c.getSVar("NeedsToPlay"); return false;
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), needsToPlay, c.getController(), c, null);
if (list.isEmpty()) {
return false;
}
} }
return player.canPlayLand(c, false, c.getFirstSpellAbility()); return player.canPlayLand(c, false, c.getFirstSpellAbility());
}); });
@@ -54,7 +47,7 @@ public class ComputerUtilAbility {
landsNotInHand.add(player.getCardsIn(ZoneType.Library).get(0)); landsNotInHand.add(player.getCardsIn(ZoneType.Library).get(0));
} }
for (final Card crd : landsNotInHand) { for (final Card crd : landsNotInHand) {
if (!(crd.isLand() || (crd.isFaceDown() && crd.getState(CardStateName.Original).getType().isLand()))) { if (!(crd.hasPlayableLandFace() || (crd.isFaceDown() && crd.getState(CardStateName.Original).getType().isLand()))) {
continue; continue;
} }
if (!crd.mayPlay(player).isEmpty()) { if (!crd.mayPlay(player).isEmpty()) {

View File

@@ -2,7 +2,6 @@ package forge.game;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@@ -93,11 +92,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
if (event.sa.getTargetRestrictions() != null) { if (event.sa.getTargetRestrictions() != null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
List<TargetChoices> targets = event.sa.getAllTargetChoices(); for (TargetChoices ch : event.sa.getAllTargetChoices()) {
// Include the TargetChoices from the stack instance, since the real target choices
// are on that object at this point (see SpellAbilityStackInstance constructor).
targets.add(event.si.getTargetChoices());
for (TargetChoices ch : targets) {
if (null != ch) { if (null != ch) {
sb.append(ch); sb.append(ch);
} }

View File

@@ -5524,6 +5524,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return isInstant() || isSorcery() || (isAura() && !isInZone(ZoneType.Battlefield)); return isInstant() || isSorcery() || (isAura() && !isInZone(ZoneType.Battlefield));
} }
public final boolean hasPlayableLandFace() { return isLand() || (isModal() && getState(CardStateName.Modal).getType().isLand()); }
public final boolean isLand() { return getType().isLand(); } public final boolean isLand() { return getType().isLand(); }
public final boolean isBasicLand() { return getType().isBasicLand(); } public final boolean isBasicLand() { return getType().isBasicLand(); }
public final boolean isSnow() { return getType().isSnow(); } public final boolean isSnow() { return getType().isSnow(); }

View File

@@ -22,7 +22,6 @@ import java.util.Comparator;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.card.CardStateName;
import forge.game.CardTraitBase; import forge.game.CardTraitBase;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
@@ -379,7 +378,7 @@ public final class CardPredicates {
/** /**
* a Predicate<Card> to get all lands. * a Predicate<Card> to get all lands.
*/ */
public static final Predicate<Card> LANDS = c -> c.isLand() || (!c.isInZone(ZoneType.Battlefield) && c.isModal() && c.getState(CardStateName.Modal).getType().isLand()); public static final Predicate<Card> LANDS = c -> c.isLand();
/** /**
* a Predicate<Card> to get all mana-producing lands. * a Predicate<Card> to get all mana-producing lands.
*/ */

View File

@@ -2,7 +2,7 @@ Name:Ignite the Future
ManaCost:3 R ManaCost:3 R
Types:Sorcery Types:Sorcery
A:SP$ Dig | Defined$ You | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top three cards of your library. Until the end of your next turn, you may play those cards. If this spell was cast from a graveyard, you may play cards this way without paying their mana costs. A:SP$ Dig | Defined$ You | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top three cards of your library. Until the end of your next turn, you may play those cards. If this spell was cast from a graveyard, you may play cards this way without paying their mana costs.
SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | ForgetOnMoved$ Exile | Duration$ UntilTheEndOfYourNextTurn | ConditionDefined$ Self | ConditionPresent$ Card.wasCastFromGraveyard | ConditionCompare$ EQ0 | SubAbility$ DBEffect2 SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | ForgetOnMoved$ Exile | Duration$ UntilTheEndOfYourNextTurn | SubAbility$ DBEffect2
SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card. SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card.
SVar:DBEffect2:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play2 | ForgetOnMoved$ Exile | Duration$ UntilTheEndOfYourNextTurn | ConditionDefined$ Self | ConditionPresent$ Card.wasCastFromGraveyard | ConditionCompare$ EQ1 | SubAbility$ DBCleanup SVar:DBEffect2:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play2 | ForgetOnMoved$ Exile | Duration$ UntilTheEndOfYourNextTurn | ConditionDefined$ Self | ConditionPresent$ Card.wasCastFromGraveyard | ConditionCompare$ EQ1 | SubAbility$ DBCleanup
SVar:Play2:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card without paying their mana costs. SVar:Play2:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card without paying their mana costs.

View File

@@ -2,16 +2,15 @@ Name:Nahiri's Lithoforming
ManaCost:X R R ManaCost:X R R
Types:Sorcery Types:Sorcery
A:SP$ Sacrifice | SacValid$ Land | Amount$ X | RememberSacrificed$ True | SubAbility$ DBDraw | StackDescription$ SpellDescription | SpellDescription$ Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter tapped this turn. A:SP$ Sacrifice | SacValid$ Land | Amount$ X | RememberSacrificed$ True | SubAbility$ DBDraw | StackDescription$ SpellDescription | SpellDescription$ Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter tapped this turn.
SVar:DBDraw:DB$ Draw | NumCards$ Y | SubAbility$ DBStoreSVar | StackDescription$ None SVar:DBDraw:DB$ Draw | NumCards$ Y | SubAbility$ DBEffect | StackDescription$ None
SVar:DBStoreSVar:DB$ StoreSVar | SVar$ XLands | Type$ CountSVar | Expression$ X | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | SetChosenNumber$ X | StaticAbilities$ PlayMoreLand | ReplacementEffects$ LandETB | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | StaticAbilities$ PlayMoreLand | ReplacementEffects$ LandETB | SubAbility$ DBCleanup SVar:PlayMoreLand:Mode$ Continuous | Affected$ You | AdjustLandPlays$ Z | EffectZone$ Command | Description$ You may play X additional lands this turn.
SVar:PlayMoreLand:Mode$ Continuous | Affected$ You | AdjustLandPlays$ XLands | EffectZone$ Command | Description$ You may play X additional lands this turn.
SVar:LandETB:Event$ Moved | ValidCard$ Land.YouCtrl | Destination$ Battlefield | ReplaceWith$ ETBTapped | ReplacementResult$ Updated | Description$ Lands you control enter tapped this turn. SVar:LandETB:Event$ Moved | ValidCard$ Land.YouCtrl | Destination$ Battlefield | ReplaceWith$ ETBTapped | ReplacementResult$ Updated | Description$ Lands you control enter tapped this turn.
SVar:ETBTapped:DB$ Tap | ETB$ True | Defined$ ReplacedCard SVar:ETBTapped:DB$ Tap | ETB$ True | Defined$ ReplacedCard
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$xPaid SVar:X:Count$xPaid
SVar:Y:Count$RememberedSize SVar:Y:Count$RememberedSize
SVar:XLands:Number$0 SVar:Z:Count$ChosenNumber
DeckHas:Ability$Sacrifice DeckHas:Ability$Sacrifice
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter tapped this turn. Oracle:Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter tapped this turn.

View File

@@ -3,8 +3,8 @@ ManaCost:3 U
Types:Legendary Creature Human Scientist Types:Legendary Creature Human Scientist
PT:3/4 PT:3/4
S:Mode$ Continuous | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size. S:Mode$ Continuous | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size.
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigImmediateTrig | OptionalDecider$ You | TriggerDescription$ Sonic Booster — Whenever CARDNAME attacks, sacrifice X artifacts. When you sacrifice one or more artifacts this way, tap up to X target creatures and you draw X cards. T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigImmediateTrig | OptionalDecider$ You | TriggerDescription$ Sonic Booster — Whenever CARDNAME attacks, sacrifice any number artifacts. When you sacrifice one or more artifacts this way, tap up to that many target creatures and draw that many cards.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Sac<X/Artifact> | Execute$ TrigTap | TriggerDescription$ When you sacrifice one or more artifacts this way, tap up to X target creatures and you draw X cards. SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Sac<X/Artifact> | Execute$ TrigTap | TriggerDescription$ When you sacrifice one or more artifacts this way, tap up to that many target creatures and draw that many cards.
SVar:TrigTap:DB$ Tap | TargetMin$ 0 | TargetMax$ X | TgtPrompt$ Select up to X target creatures to tap | ValidTgts$ Creature | SubAbility$ TrigDraw SVar:TrigTap:DB$ Tap | TargetMin$ 0 | TargetMax$ X | TgtPrompt$ Select up to X target creatures to tap | ValidTgts$ Creature | SubAbility$ TrigDraw
SVar:TrigDraw:DB$ Draw | NumCards$ X SVar:TrigDraw:DB$ Draw | NumCards$ X
SVar:X:Count$xPaid SVar:X:Count$xPaid
@@ -12,4 +12,4 @@ K:Doctor's companion
SVar:HasAttackEffect:TRUE SVar:HasAttackEffect:TRUE
DeckHas:Ability$Sacrifice DeckHas:Ability$Sacrifice
DeckNeeds:Type$Artifact DeckNeeds:Type$Artifact
Oracle:You have no maximum hand size.\nSonic Booster — Whenever Nyssa of Traken attacks, sacrifice X artifacts. When you sacrifice one or more artifacts this way, tap up to X target creatures and you draw X cards.\nDoctor's companion (You can have two commanders if the other is the Doctor.) Oracle:You have no maximum hand size.\nSonic Booster — Whenever Nyssa of Traken attacks, sacrifice any number of artifacts. When you sacrifice one or more artifacts this way, tap up to that many target creatures and draw that many cards.\nDoctor's companion (You can have two commanders if the other is the Doctor.)

View File

@@ -1,18 +1,18 @@
Name:Wheel of Potential Name:Wheel of Potential
ManaCost:2 R ManaCost:2 R
Types:Sorcery Types:Sorcery
A:SP$ PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 3 | SubAbility$ ChooseX | StackDescription$ REP You get_{p:You} gets & you_ | SpellDescription$ You get {E}{E}{E} (three energy counters), then you may pay X {E}.,,,,,, A:SP$ PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 3 | SubAbility$ ChooseX | StackDescription$ REP You get_{p:You} gets & you_ | SpellDescription$ You get {E}{E}{E} (three energy counters), then you may pay any amount of {E}.,,,,,,
SVar:ChooseX:DB$ ChooseNumber | Max$ Count$YourCountersEnergy | ListTitle$ amount of energy to pay | SubAbility$ Pay | StackDescription$ None SVar:ChooseX:DB$ ChooseNumber | Max$ Count$YourCountersEnergy | ListTitle$ amount of energy to pay | SubAbility$ Pay | StackDescription$ None
SVar:Pay:DB$ Pump | UnlessCost$ Mandatory PayEnergy<X> | UnlessPayer$ You | UnlessSwitched$ True | SubAbility$ Choose | StackDescription$ None SVar:Pay:DB$ Pump | UnlessCost$ Mandatory PayEnergy<X> | UnlessPayer$ You | UnlessSwitched$ True | SubAbility$ Choose | StackDescription$ None
SVar:Choose:DB$ GenericChoice | TempRemember$ Chooser | ShowChoice$ ExceptSelf | Defined$ Player | Choices$ ExileDraw,No | SubAbility$ DBExile | StackDescription$ SpellDescription | SpellDescription$ Each player may exile their hand and draw X cards. SVar:Choose:DB$ GenericChoice | TempRemember$ Chooser | ShowChoice$ ExceptSelf | Defined$ Player | Choices$ ExileDraw,No | SubAbility$ Exile | StackDescription$ SpellDescription | SpellDescription$ Each player may exile their hand and draw cards equal to the amount of {E} paid this way.
SVar:ExileDraw:DB$ Pump | Defined$ Remembered | NoteCards$ Self | NoteCardsFor$ ExileDraw | SpellDescription$ Exile your hand and draw X cards. SVar:ExileDraw:DB$ Pump | Defined$ Remembered | NoteCards$ Self | NoteCardsFor$ ExileDraw | SpellDescription$ Exile your hand and draw X cards.
SVar:No:DB$ Pump | SpellDescription$ Keep your hand. SVar:No:DB$ Pump | SpellDescription$ Keep your hand.
SVar:ExileDraw:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Exile | ChangeType$ Card.OwnedBy Player.NotedForExile | RememberChanged$ True | SubAbility$ Draw | StackDescription$ None SVar:Exile:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Exile | Defined$ Player.NotedForExileDraw | RememberChanged$ True | SubAbility$ Draw | StackDescription$ None
SVar:Draw:DB$ Draw | Defined$ Player.NotedForExile | NumCards$ X | SubAbility$ Effect | StackDescription$ None SVar:Draw:DB$ Draw | Defined$ Player.NotedForExileDraw | NumCards$ X | SubAbility$ Effect | StackDescription$ None
SVar:Effect:DB$ Effect | ConditionCheckSVar$ X | ConditionSVarCompare$ GE7 | RememberObjects$ Remembered.YouOwn | StaticAbilities$ Play | Duration$ UntilTheEndOfYourNextTurn | ForgetOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ If X is 7 or more, you may play cards you own exiled this way until the end of your next turn. SVar:Effect:DB$ Effect | ConditionCheckSVar$ X | ConditionSVarCompare$ GE7 | RememberObjects$ Remembered.YouOwn | StaticAbilities$ Play | Duration$ UntilTheEndOfYourNextTurn | ForgetOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ If 7 or more {E} was paid this way, you may play cards you own exiled this way until the end of your next turn.
SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.YouOwn+IsRemembered | AffectedZone$ Exile | Description$ You may play cards you own exiled this way until the end of your next turn. SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.YouOwn+IsRemembered | AffectedZone$ Exile | Description$ You may play cards you own exiled this way until the end of your next turn.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBClearNotes SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBClearNotes
SVar:DBClearNotes:DB$ Pump | Defined$ Player | ClearNotedCardsFor$ Exile SVar:DBClearNotes:DB$ Pump | Defined$ Player | ClearNotedCardsFor$ ExileDraw
SVar:X:Count$ChosenNumber SVar:X:Count$ChosenNumber
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:You get {E}{E}{E} (three energy counters), then you may pay X {E}.\nEach player may exile their hand and draw X cards. If X is 7 or more, you may play cards you own exiled this way until the end of your next turn. Oracle:You get {E}{E}{E} (three energy counters), then you may pay any amount of {E}.\nEach player may exile their hand and draw cards equal to the amount of {E} paid this way. If 7 or more {E} was paid this way, you may play cards you own exiled this way until the end of your next turn.