mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
Fix drawn card being revealed during ability resolve
This commit is contained in:
@@ -1212,6 +1212,8 @@ public abstract class GameState {
|
||||
p.setLandsPlayedThisTurn(landsPlayed);
|
||||
p.setLandsPlayedLastTurn(landsPlayedLastTurn);
|
||||
|
||||
p.clearPaidForSA();
|
||||
|
||||
for (Entry<ZoneType, CardCollectionView> kv : playerCards.entrySet()) {
|
||||
PlayerZone zone = p.getZone(kv.getKey());
|
||||
if (kv.getKey() == ZoneType.Battlefield) {
|
||||
|
||||
@@ -119,6 +119,7 @@ public class Game {
|
||||
private Table<CounterType, Player, List<Pair<Card, Integer>>> countersAddedThisTurn = HashBasedTable.create();
|
||||
|
||||
private Map<Player, Card> topLibsCast = Maps.newHashMap();
|
||||
private Map<Card, Integer> facedownWhileCasting = Maps.newHashMap();
|
||||
|
||||
private Player monarch = null;
|
||||
private Player monarchBeginTurn = null;
|
||||
@@ -1113,7 +1114,29 @@ public class Game {
|
||||
topLibsCast.put(p, p.getTopXCardsFromLibrary(1).isEmpty() ? null : p.getTopXCardsFromLibrary(1).get(0));
|
||||
}
|
||||
}
|
||||
public void clearTopLibsCast() {
|
||||
public void clearTopLibsCast(SpellAbility sa) {
|
||||
// if nothing left to pay
|
||||
if (sa.getActivatingPlayer().getPaidForSA() == null) {
|
||||
topLibsCast.clear();
|
||||
for (Card c : facedownWhileCasting.keySet()) {
|
||||
// maybe it was discarded as payment?
|
||||
if (c.isInZone(ZoneType.Hand)) {
|
||||
c.forceTurnFaceUp();
|
||||
|
||||
// run triggers for cards that need reveal
|
||||
final Map<AbilityKey, Object> runParams = Maps.newHashMap();
|
||||
runParams.put(AbilityKey.Card, c);
|
||||
runParams.put(AbilityKey.Number, facedownWhileCasting.get(c));
|
||||
runParams.put(AbilityKey.Player, this);
|
||||
runParams.put(AbilityKey.CanReveal, true);
|
||||
// need to hold trigger to clear list first
|
||||
getTriggerHandler().runTrigger(TriggerType.Drawn, runParams, true);
|
||||
}
|
||||
}
|
||||
facedownWhileCasting.clear();
|
||||
}
|
||||
}
|
||||
public void addFacedownWhileCasting(Card c, int numDrawn) {
|
||||
facedownWhileCasting.put(c, Integer.valueOf(numDrawn));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public enum AbilityKey {
|
||||
AttackedTarget("AttackedTarget"),
|
||||
Blocker("Blocker"),
|
||||
Blockers("Blockers"),
|
||||
CanReveal("CanReveal"),
|
||||
CastSA("CastSA"),
|
||||
CastSACMC("CastSACMC"),
|
||||
Card("Card"),
|
||||
|
||||
@@ -1219,20 +1219,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean canDraw() {
|
||||
if (hasKeyword("You can't draw cards.")) {
|
||||
return false;
|
||||
}
|
||||
if (hasKeyword("You can't draw more than one card each turn.")) {
|
||||
return numDrawnThisTurn < 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final CardCollectionView drawCard() {
|
||||
return drawCards(1, null);
|
||||
}
|
||||
|
||||
public void surveil(int num, SpellAbility cause, CardZoneTable table) {
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.Source, cause);
|
||||
@@ -1300,12 +1286,25 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return !getZone(ZoneType.Hand).isEmpty();
|
||||
}
|
||||
|
||||
public final boolean canDraw() {
|
||||
if (hasKeyword("You can't draw cards.")) {
|
||||
return false;
|
||||
}
|
||||
if (hasKeyword("You can't draw more than one card each turn.")) {
|
||||
return numDrawnThisTurn < 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final CardCollectionView drawCard() {
|
||||
return drawCards(1, null);
|
||||
}
|
||||
|
||||
public final CardCollectionView drawCards(final int n) {
|
||||
return drawCards(n, null);
|
||||
}
|
||||
public final CardCollectionView drawCards(final int n, SpellAbility cause) {
|
||||
final CardCollection drawn = new CardCollection();
|
||||
final Map<Player, CardCollection> toReveal = Maps.newHashMap();
|
||||
|
||||
// Replacement effects
|
||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
||||
@@ -1317,6 +1316,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
// always allow drawing cards before the game actually starts (e.g. Maralen of the Mornsong Avatar)
|
||||
final boolean gameStarted = game.getAge().ordinal() > GameStage.Mulligan.ordinal();
|
||||
final Map<Player, CardCollection> toReveal = Maps.newHashMap();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (gameStarted && !canDraw()) {
|
||||
@@ -1358,7 +1358,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
List<Player> pList = Lists.newArrayList();
|
||||
|
||||
for (Player p : getAllOtherPlayers()) {
|
||||
if (c.mayPlayerLook(p)) {
|
||||
pList.add(p);
|
||||
@@ -1385,8 +1384,16 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
view.updateNumDrawnThisTurn(this);
|
||||
|
||||
// Run triggers
|
||||
final Map<AbilityKey, Object> runParams = Maps.newHashMap();
|
||||
|
||||
// CR 121.8 card was drawn as part of another sa (e.g. paying with Chromantic Sphere), hide it temporarily
|
||||
if (game.getTopLibForPlayer(this) != null && getPaidForSA() != null && cause != null && getPaidForSA() != cause.getRootAbility()) {
|
||||
c.turnFaceDown();
|
||||
game.addFacedownWhileCasting(c, numDrawnThisTurn);
|
||||
runParams.put(AbilityKey.CanReveal, false);
|
||||
}
|
||||
|
||||
// Run triggers
|
||||
runParams.put(AbilityKey.Card, c);
|
||||
runParams.put(AbilityKey.Number, numDrawnThisTurn);
|
||||
runParams.put(AbilityKey.Player, this);
|
||||
@@ -3167,6 +3174,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
// it could be empty if spell couldn't be cast
|
||||
paidForStack.poll();
|
||||
}
|
||||
public void clearPaidForSA() {
|
||||
paidForStack.clear();
|
||||
}
|
||||
|
||||
public boolean isMonarch() {
|
||||
return equals(game.getMonarch());
|
||||
|
||||
@@ -86,6 +86,18 @@ public class TriggerDrawn extends Trigger {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (runParams.containsKey(AbilityKey.CanReveal)) {
|
||||
// while drawing this is only set if false
|
||||
boolean canReveal = (boolean) runParams.get(AbilityKey.CanReveal);
|
||||
if (hasParam("ForReveal")) {
|
||||
if (!canReveal) {
|
||||
return false;
|
||||
}
|
||||
} else if (canReveal) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:2 U U
|
||||
Types:Legendary Creature Zombie God
|
||||
PT:4/5
|
||||
K:Flying
|
||||
T:Mode$ Drawn | ValidCard$ Card.YouOwn | Number$ 1 | OptionalDecider$ You | Static$ True | Execute$ DBReveal | TriggerZones$ Battlefield | TriggerDescription$ You may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast.
|
||||
T:Mode$ Drawn | ValidCard$ Card.YouOwn | Number$ 1 | OptionalDecider$ You | Static$ True | ForReveal$ True | Execute$ DBReveal | TriggerZones$ Battlefield | TriggerDescription$ You may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast.
|
||||
SVar:DBReveal:DB$ Reveal | Defined$ You | RevealDefined$ TriggeredCard | RememberRevealed$ True | SubAbility$ DBTrigger | AILogic$ Kefnet
|
||||
SVar:DBTrigger:DB$ ImmediateTrigger | RememberObjects$ RememberedCard | ConditionDefined$ Remembered | ConditionPresent$ Instant,Sorcery | SubAbility$ DBCleanup | Execute$ DBPlay | TriggerDescription$ Whenever you reveal an instant or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast.
|
||||
SVar:DBPlay:DB$ Play | Defined$ DelayTriggerRemembered | ValidSA$ Spell | PlayReduceCost$ 2 | Optional$ True | CopyCard$ True
|
||||
@@ -11,4 +11,3 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard,Exile | ValidCard$ Card.Self | Execute$ TriReturn | OptionalDecider$ You | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.
|
||||
SVar:TriReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Destination$ Library | LibraryPosition$ 2
|
||||
Oracle:Flying\nYou may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast.\nWhen God-Eternal Kefnet dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.
|
||||
|
||||
|
||||
@@ -356,12 +356,10 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
player.getManaPool().payManaFromAbility(saPaidFor, InputPayMana.this.manaCost, chosen);
|
||||
}
|
||||
onManaAbilityPaid();
|
||||
onStateChanged();
|
||||
} else {
|
||||
}
|
||||
// Need to call this to unlock
|
||||
onStateChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -36,6 +36,8 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn
|
||||
}
|
||||
|
||||
protected final void stop() {
|
||||
onStop();
|
||||
|
||||
// ensure input won't accept any user actions.
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
@@ -44,8 +46,6 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn
|
||||
}
|
||||
});
|
||||
|
||||
onStop();
|
||||
|
||||
// thread irrelevant
|
||||
if (getController().getInputQueue().getInput() != null) {
|
||||
getController().getInputQueue().removeInput(InputSyncronizedBase.this);
|
||||
|
||||
@@ -171,7 +171,7 @@ public class HumanPlaySpellAbility {
|
||||
manapool.restoreColorReplacements();
|
||||
human.decNumManaConversion();
|
||||
}
|
||||
game.clearTopLibsCast();
|
||||
game.clearTopLibsCast(ability);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ public class HumanPlaySpellAbility {
|
||||
manapool.restoreColorReplacements();
|
||||
}
|
||||
}
|
||||
game.clearTopLibsCast();
|
||||
game.clearTopLibsCast(ability);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user