ManifestDread as separate Effect (#6151)

This commit is contained in:
Hans Mackowiak
2024-09-16 12:36:31 +02:00
committed by GitHub
parent 6e3c17a2a8
commit 7b9e2a6735
31 changed files with 161 additions and 91 deletions

View File

@@ -116,6 +116,7 @@ public enum ApiType {
Mana (ManaEffect.class),
ManaReflected (ManaReflectedEffect.class),
Manifest (ManifestEffect.class),
ManifestDread (ManifestDreadEffect.class),
Meld (MeldEffect.class),
Mill (MillEffect.class),
MoveCounter (CountersMoveEffect.class),

View File

@@ -22,79 +22,69 @@ public abstract class ManifestBaseEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card source = sa.getHostCard();
final Player activator = sa.getActivatingPlayer();
final Game game = source.getGame();
// Usually a number leaving possibility for X, Sacrifice X land: Manifest X creatures.
final int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(source, sa.getParam("Amount"), sa) : 1;
final int times = sa.hasParam("Times") ? AbilityUtils.calculateAmount(source, sa.getParam("Times"), sa) : 1;
for (int i = 0; i < times; i++) {
for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) {
CardCollection tgtCards;
Card toGrave = null;
boolean fromLibrary = false;
if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) {
ZoneType choiceZone = ZoneType.Hand;
if (sa.hasParam("ChoiceZone")) {
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
fromLibrary = choiceZone.equals(ZoneType.Library);
}
CardCollectionView choices = p.getCardsIn(choiceZone);
if (sa.hasParam("Choices")) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa);
}
if (choices.isEmpty()) {
continue;
}
for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) {
manifestLoop(sa, p, amount);
}
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : getDefaultMessage() + " ";
protected void manifestLoop(SpellAbility sa, Player p, final int amount) {
tgtCards = new CardCollection(p.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null));
} else if (sa.hasParam("Dread")) {
tgtCards = p.getTopXCardsFromLibrary(2);
if (!tgtCards.isEmpty()) {
Card manifest = p.getController().chooseSingleEntityForEffect(tgtCards, sa, getDefaultMessage(), null);
tgtCards.remove(manifest);
toGrave = tgtCards.isEmpty() ? null : tgtCards.getFirst();
tgtCards = new CardCollection(manifest);
}
fromLibrary = true;
} else if ("TopOfLibrary".equals(sa.getParamOrDefault("Defined", "TopOfLibrary"))) {
tgtCards = p.getTopXCardsFromLibrary(amount);
fromLibrary = true;
} else {
tgtCards = getTargetCards(sa);
if (Iterables.all(tgtCards, CardPredicates.inZone(ZoneType.Library))) {
fromLibrary = true;
}
}
final Card source = sa.getHostCard();
final Player activator = sa.getActivatingPlayer();
final Game game = source.getGame();
if (sa.hasParam("Shuffle")) {
CardLists.shuffle(tgtCards);
}
if (fromLibrary) {
for (Card c : tgtCards) {
// CR 701.34d If an effect instructs a player to manifest multiple cards from their library, those cards are manifested one at a time.
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
internalEffect(c, p, sa, moveParams);
if (sa.hasParam("Dread") && toGrave != null) {
game.getAction().moveToGraveyard(toGrave, sa, moveParams);
toGrave = null;
}
triggerList.triggerChangesZoneAll(game, sa);
}
} else {
// manifest from other zones should be done at the same time
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
for (Card c : tgtCards) {
internalEffect(c, p, sa, moveParams);
}
triggerList.triggerChangesZoneAll(game, sa);
}
CardCollection tgtCards;
boolean fromLibrary = false;
if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) {
ZoneType choiceZone = ZoneType.Hand;
if (sa.hasParam("ChoiceZone")) {
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
fromLibrary = choiceZone.equals(ZoneType.Library);
}
CardCollectionView choices = p.getCardsIn(choiceZone);
if (sa.hasParam("Choices")) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa);
}
if (choices.isEmpty()) {
return;
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : getDefaultMessage() + " ";
tgtCards = new CardCollection(p.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null));
} else if ("TopOfLibrary".equals(sa.getParamOrDefault("Defined", "TopOfLibrary"))) {
tgtCards = p.getTopXCardsFromLibrary(amount);
fromLibrary = true;
} else {
tgtCards = getTargetCards(sa);
if (Iterables.all(tgtCards, CardPredicates.inZone(ZoneType.Library))) {
fromLibrary = true;
}
}
if (sa.hasParam("Shuffle")) {
CardLists.shuffle(tgtCards);
}
if (fromLibrary) {
for (Card c : tgtCards) {
// CR 701.34d If an effect instructs a player to manifest multiple cards from their library, those cards are manifested one at a time.
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
internalEffect(c, p, sa, moveParams);
triggerList.triggerChangesZoneAll(game, sa);
}
} else {
// manifest from other zones should be done at the same time
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
for (Card c : tgtCards) {
internalEffect(c, p, sa, moveParams);
}
triggerList.triggerChangesZoneAll(game, sa);
}
}

View File

@@ -0,0 +1,41 @@
package forge.game.ability.effects;
import java.util.Map;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
public class ManifestDreadEffect extends ManifestEffect {
@Override
protected void manifestLoop(SpellAbility sa, Player p, final int amount) {
final Game game = p.getGame();
for (int i = 0; i < amount; i++) {
CardCollection tgtCards = p.getTopXCardsFromLibrary(2);
Card manifest = null;
Card toGrave = null;
if (!tgtCards.isEmpty()) {
manifest = p.getController().chooseSingleEntityForEffect(tgtCards, sa, getDefaultMessage(), null);
tgtCards.remove(manifest);
toGrave = tgtCards.isEmpty() ? null : tgtCards.getFirst();
// CR 701.34d If an effect instructs a player to manifest multiple cards from their library, those cards are manifested one at a time.
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
internalEffect(manifest, p, sa, moveParams);
if (toGrave != null) {
toGrave = game.getAction().moveToGraveyard(toGrave, sa, moveParams);
}
triggerList.triggerChangesZoneAll(game, sa);
}
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
runParams.put(AbilityKey.Card, toGrave);
game.getTriggerHandler().runTrigger(TriggerType.ManifestDread, runParams, true);
}
}
}

View File

@@ -9,10 +9,11 @@ import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
public class ManifestEffect extends ManifestBaseEffect {
@Override
protected String getDefaultMessage() {
return Localizer.getInstance().getMessage("lblChooseCardToManifest");
}
@Override
protected Card internalEffect(Card c, Player p, SpellAbility sa, Map<AbilityKey, Object> moveParams) {
final Card source = sa.getHostCard();
Card rem = c.manifest(p, sa, moveParams);

View File

@@ -0,0 +1,35 @@
package forge.game.trigger;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
public class TriggerManifestDread extends Trigger {
public TriggerManifestDread(Map<String, String> params, Card host, boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false;
}
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObject(AbilityKey.NewCard, runParams.get(AbilityKey.Card));
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
// TODO Auto-generated method stub
return "";
}
}

View File

@@ -97,6 +97,7 @@ public enum TriggerType {
LosesGame(TriggerLosesGame.class),
ManaAdded(TriggerManaAdded.class),
ManaExpend(TriggerManaExpend.class),
ManifestDread(TriggerManifestDread.class),
Mentored(TriggerMentored.class),
Milled(TriggerMilled.class),
MilledOnce(TriggerMilledOnce.class),