Fix facedown permanent with adventure (#4355)

* Restore adventure text when card not in play

* Remove obsolete code

* Fix crash with Cybership

* Fix NPE
This commit is contained in:
tool4ever
2023-12-15 09:58:30 +01:00
committed by GitHub
parent 023e41c8a0
commit 90c3a13e3d
10 changed files with 21 additions and 37 deletions

View File

@@ -635,8 +635,7 @@ public class AttachAi extends SpellAbilityAi {
} }
// Cards that trigger on dealing damage // Cards that trigger on dealing damage
private static Card attachAICuriosityPreference(final SpellAbility sa, final List<Card> list, final boolean mandatory, private static Card attachAICuriosityPreference(final SpellAbility sa, final List<Card> list, final boolean mandatory, final Card attachSource) {
final Card attachSource) {
Card chosen = null; Card chosen = null;
int priority = 0; int priority = 0;
for (Card card : list) { for (Card card : list) {
@@ -690,7 +689,6 @@ public class AttachAi extends SpellAbilityAi {
} }
} }
return chosen; return chosen;
} }
/** /**

View File

@@ -23,8 +23,8 @@ import forge.game.zone.ZoneType;
public class FogAi extends SpellAbilityAi { public class FogAi extends SpellAbilityAi {
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) * @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/ */
@Override @Override
protected boolean canPlayAI(Player ai, SpellAbility sa) { protected boolean canPlayAI(Player ai, SpellAbility sa) {
final Game game = ai.getGame(); final Game game = ai.getGame();
@@ -121,7 +121,7 @@ public class FogAi extends SpellAbilityAi {
int fogs = 0; int fogs = 0;
for (Card c : ai.getCardsActivatableInExternalZones(false)) { for (Card c : ai.getCardsActivatableInExternalZones(false)) {
for (SpellAbility ability : c.getSpellAbilities()) { for (SpellAbility ability : c.getSpellAbilities()) {
if (ability.getApi().equals(ApiType.Fog)) { if (ApiType.Fog.equals(ability.getApi())) {
fogs++; fogs++;
break; break;
} }
@@ -130,7 +130,7 @@ public class FogAi extends SpellAbilityAi {
for (Card c : ai.getCardsIn(ZoneType.Hand)) { for (Card c : ai.getCardsIn(ZoneType.Hand)) {
for (SpellAbility ability : c.getSpellAbilities()) { for (SpellAbility ability : c.getSpellAbilities()) {
if (ability.getApi().equals(ApiType.Fog)) { if (ApiType.Fog.equals(ability.getApi())) {
fogs++; fogs++;
break; break;
} }

View File

@@ -510,11 +510,6 @@ public class GameAction {
} }
} }
// if an adventureCard is put from Stack somewhere else, need to reset to Original State
if (copied.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) {
copied.setState(CardStateName.Original, false);
}
GameEntityCounterTable table = new GameEntityCounterTable(); GameEntityCounterTable table = new GameEntityCounterTable();
if (mergedCards != null) { if (mergedCards != null) {
@@ -992,11 +987,11 @@ public class GameAction {
if (!lki.getController().equals(lki.getOwner())) { if (!lki.getController().equals(lki.getOwner())) {
game.getTriggerHandler().registerActiveLTBTrigger(lki); game.getTriggerHandler().registerActiveLTBTrigger(lki);
} }
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.CardLKI, lki);
runParams.put(AbilityKey.Origin, c.getZone().getZoneType().name());
game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, false);
} }
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.CardLKI, lki);
runParams.put(AbilityKey.Origin, c.getZone().getZoneType().name());
game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, false);
} }
} }

View File

@@ -143,13 +143,13 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
for (final GameOutcome game : gamesPlayed) { for (final GameOutcome game : gamesPlayed) {
RegisteredPlayer player = game.getWinningPlayer(); RegisteredPlayer player = game.getWinningPlayer();
int amount = winCount.containsKey(player) ? winCount.get(player) : 0; int amount = winCount.getOrDefault(player, 0);
winCount.put(player, amount + 1); winCount.put(player, amount + 1);
} }
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (Entry<RegisteredPlayer, String> entry : players.entrySet()) { for (Entry<RegisteredPlayer, String> entry : players.entrySet()) {
int amount = winCount.containsKey(entry.getKey()) ? winCount.get(entry.getKey()) : 0; int amount = winCount.getOrDefault(entry.getKey(), 0);
sb.append(entry.getValue()).append(": ").append(amount).append(" "); sb.append(entry.getValue()).append(": ").append(amount).append(" ");
} }

View File

@@ -58,8 +58,6 @@ public enum PlanarDice {
} }
PlanarDice res = results.get(0); PlanarDice res = results.get(0);
PlanarDice trigRes = res;
final Map<AbilityKey, Object> resRepParams = AbilityKey.mapFromAffected(roller); final Map<AbilityKey, Object> resRepParams = AbilityKey.mapFromAffected(roller);
resRepParams.put(AbilityKey.Result, res); resRepParams.put(AbilityKey.Result, res);
@@ -67,14 +65,14 @@ public enum PlanarDice {
case NotReplaced: case NotReplaced:
break; break;
case Updated: { case Updated: {
trigRes = (PlanarDice) resRepParams.get(AbilityKey.Result); res = (PlanarDice) resRepParams.get(AbilityKey.Result);
break; break;
} }
} }
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(roller); Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(roller);
runParams.put(AbilityKey.Result, trigRes); runParams.put(AbilityKey.Result, res);
game.getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false); game.getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams, false);
// Also run normal RolledDie and RolledDieOnce triggers // Also run normal RolledDie and RolledDieOnce triggers
for (int r = 0; r < rolls; r++) { for (int r = 0; r < rolls; r++) {
@@ -98,7 +96,6 @@ public enum PlanarDice {
* @return enum equivalent * @return enum equivalent
*/ */
public static PlanarDice smartValueOf(String value) { public static PlanarDice smartValueOf(String value) {
final String valToCompate = value.trim(); final String valToCompate = value.trim();
for (final PlanarDice v : PlanarDice.values()) { for (final PlanarDice v : PlanarDice.values()) {
if (v.name().compareToIgnoreCase(valToCompate) == 0) { if (v.name().compareToIgnoreCase(valToCompate) == 0) {

View File

@@ -38,7 +38,6 @@ public abstract class TriggerReplacementBase extends CardTraitBase implements II
public Set<ZoneType> getActiveZone() { public Set<ZoneType> getActiveZone() {
return validHostZones; return validHostZones;
} }
public void setActiveZone(EnumSet<ZoneType> zones) { public void setActiveZone(EnumSet<ZoneType> zones) {
validHostZones = zones; validHostZones = zones;
} }

View File

@@ -374,9 +374,8 @@ public class DigEffect extends SpellAbilityEffect {
for (Card c : movedCards) { for (Card c : movedCards) {
final ZoneType origin = c.getZone().getZoneType(); final ZoneType origin = c.getZone().getZoneType();
final PlayerZone zone = c.getOwner().getZone(destZone1);
if (zone.is(ZoneType.Library) || zone.is(ZoneType.PlanarDeck) || zone.is(ZoneType.SchemeDeck)) { if (destZone1.equals(ZoneType.Library) || destZone1.equals(ZoneType.PlanarDeck) || destZone1.equals(ZoneType.SchemeDeck)) {
c = game.getAction().moveTo(destZone1, c, libraryPosition, sa); c = game.getAction().moveTo(destZone1, c, libraryPosition, sa);
} else { } else {
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
@@ -410,7 +409,7 @@ public class DigEffect extends SpellAbilityEffect {
host.removeRemembered(c); host.removeRemembered(c);
animate.setSVar("unanimateTimestamp", String.valueOf(game.getTimestamp())); animate.setSVar("unanimateTimestamp", String.valueOf(game.getTimestamp()));
} }
c = game.getAction().moveTo(zone, c, sa, moveParams); c = game.getAction().moveTo(c.getController().getZone(destZone1), c, sa, moveParams);
if (destZone1.equals(ZoneType.Battlefield)) { if (destZone1.equals(ZoneType.Battlefield)) {
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) { if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
combatChanged = true; combatChanged = true;

View File

@@ -2682,11 +2682,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
continue; continue;
} }
// skip Basic Spells
if (sa.isSpell() && sa.isBasicSpell()) {
continue;
}
// should not print Spelldescription for Morph // should not print Spelldescription for Morph
if (sa.isCastFaceDown()) { if (sa.isCastFaceDown()) {
continue; continue;
@@ -2704,6 +2699,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sbSA.append(": "); sbSA.append(": ");
sbSA.append(sAbility); sbSA.append(sAbility);
sAbility = sbSA.toString(); sAbility = sbSA.toString();
} else if (sa.isSpell() && sa.isBasicSpell()) {
continue;
} }
if (sa.getManaPart() != null) { if (sa.getManaPart() != null) {

View File

@@ -1,8 +1,7 @@
Name:Blood for Bones Name:Blood for Bones
ManaCost:3 B ManaCost:3 B
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Cost$ 3 B Sac<1/Creature> | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn | PrimaryPrompt$ Choose a creature card to return to the battlefield | ChangeTypeDesc$ creature | RememberChanged$ True | SubAbility$ DBChangeZone | SpellDescription$ Return a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand. A:SP$ ChangeZone | Cost$ 3 B Sac<1/Creature> | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn | PrimaryPrompt$ Choose a creature card to return to the battlefield | ChangeTypeDesc$ creature | SubAbility$ DBChangeZone | SpellDescription$ Return a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn+IsNotRemembered | PrimaryPrompt$ Choose another creature card to return to your hand | ChangeNumDesc$ another | ChangeTypeDesc$ creature | SubAbility$ DBCleanup SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn | PrimaryPrompt$ Choose another creature card to return to your hand | ChangeNumDesc$ another | ChangeTypeDesc$ creature
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:Random AI:RemoveDeck:Random
Oracle:As an additional cost to cast this spell, sacrifice a creature.\nReturn a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand. Oracle:As an additional cost to cast this spell, sacrifice a creature.\nReturn a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand.

View File

@@ -8,7 +8,7 @@ SVar:TrigToken:AB$ Token | Cost$ 1 ExileAnyGrave<1/Card.TriggeredNewCard> | Toke
SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | Duration$ Permanent | Triggers$ CDTrigger SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | Duration$ Permanent | Triggers$ CDTrigger
SVar:CDTrigger:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigSac | TriggerZones$ Battlefield | TriggerDescription$ When this creature deals combat damage to a player, sacrifice it and return the exiled card to the battlefield tapped. SVar:CDTrigger:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigSac | TriggerZones$ Battlefield | TriggerDescription$ When this creature deals combat damage to a player, sacrifice it and return the exiled card to the battlefield tapped.
SVar:TrigSac:DB$ Sacrifice | SubAbility$ DBReturn SVar:TrigSac:DB$ Sacrifice | SubAbility$ DBReturn
SVar:DBReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | Tapped$ True SVar:DBReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | Tapped$ True | GainControl$ True
DeckNeeds:Type$Vampire DeckNeeds:Type$Vampire
DeckHas:Ability$Token|Sacrifice DeckHas:Ability$Token|Sacrifice
Oracle:Ward—Discard a card.\nWhenever another nontoken Vampire you control dies, you may pay {1} and exile it. If you do, create a 1/1 black Bat creature token with flying. It gains "When this creature deals combat damage to a player, sacrifice it and return the exiled card to the battlefield tapped." Oracle:Ward—Discard a card.\nWhenever another nontoken Vampire you control dies, you may pay {1} and exile it. If you do, create a 1/1 black Bat creature token with flying. It gains "When this creature deals combat damage to a player, sacrifice it and return the exiled card to the battlefield tapped."