Refactor Maestros Ascendancy

This commit is contained in:
tool4EvEr
2024-05-13 16:38:11 +02:00
parent 9b54ecfe12
commit 26ef0966ea
12 changed files with 45 additions and 50 deletions

View File

@@ -319,7 +319,11 @@ public final class GameActionUtil {
newSA.getMapParams().put("ValidAfterStack", o.getAbility().getParam("ValidAfterStack"));
}
if (o.getAbility().hasParam("RaiseCost")) {
newSA.getMapParams().put("RaiseCost", Integer.toString(AbilityUtils.calculateAmount(host, o.getAbility().getParam("RaiseCost"), o.getAbility())));
String raise = o.getAbility().getParam("RaiseCost");
if (o.getAbility().hasSVar(raise)) {
raise = Integer.toString(AbilityUtils.calculateAmount(host, raise, o.getAbility()));
}
newSA.getMapParams().put("RaiseCost", raise);
}
final SpellAbilityRestriction sar = newSA.getRestrictions();

View File

@@ -449,13 +449,13 @@ public class PlayEffect extends SpellAbilityEffect {
if (sa.hasParam("ReplaceGraveyard")) {
if (!sa.hasParam("ReplaceGraveyardValid")
|| tgtSA.isValid(sa.getParam("ReplaceGraveyardValid").split(","), controller, source, sa)) {
addReplaceGraveyardEffect(tgtCard, sa, tgtSA, sa.getParam("ReplaceGraveyard"), moveParams);
addReplaceGraveyardEffect(tgtCard, source, sa, tgtSA, sa.getParam("ReplaceGraveyard"));
}
}
// For Illusionary Mask effect
if (sa.hasParam("ReplaceIlluMask")) {
addIllusionaryMaskReplace(tgtCard, sa, moveParams);
addIllusionaryMaskReplace(tgtCard, sa);
}
// Add controlled by player to target SA so when the spell is resolving, the controller would be changed again
@@ -500,8 +500,7 @@ public class PlayEffect extends SpellAbilityEffect {
}
}
protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, SpellAbility tgtSA, String zone, Map<AbilityKey, Object> moveParams) {
final Card hostCard = sa.getHostCard();
public static void addReplaceGraveyardEffect(Card c, Card hostCard, SpellAbility sa, SpellAbility tgtSA, String zone) {
final Game game = hostCard.getGame();
final Player controller = sa.getActivatingPlayer();
final String name = hostCard.getName() + "'s Effect";
@@ -535,7 +534,7 @@ public class PlayEffect extends SpellAbilityEffect {
game.getAction().moveToCommand(eff, sa);
}
protected void addIllusionaryMaskReplace(Card c, SpellAbility sa, Map<AbilityKey, Object> moveParams) {
protected void addIllusionaryMaskReplace(Card c, SpellAbility sa) {
final Card hostCard = sa.getHostCard();
final Game game = hostCard.getGame();
final Player controller = sa.getActivatingPlayer();

View File

@@ -3777,8 +3777,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
return result;
}
public final void setMayPlay(final Player player, final boolean withoutManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) {
this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, altManaCost, altIsAdditional, withFlash, grantZonePermissions));
public final void setMayPlay(final Player player, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) {
this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, altManaCost, withFlash, grantZonePermissions));
this.updateMayPlay();
}
public final void removeMayPlay(final StaticAbility sta) {

View File

@@ -3954,7 +3954,7 @@ public class CardFactoryUtil {
String effect = "Mode$ AttackVigilance | ValidCard$ Card.Self | Secondary$ True | Description$ Vigilance (" + inst.getReminderText() + ")";
inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic));
} else if (keyword.equals("MayFlashSac")) {
String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self | Secondary$ True | MayPlay$ True"
String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self | Secondary$ True | MayPlay$ True | MayPlayDontGrantZonePermissions$ True"
+ " | MayPlayNotSorcerySpeed$ True | MayPlayWithFlash$ True | MayPlayText$ Sacrifice at the next cleanup step"
+ " | AffectedZone$ Exile,Graveyard,Hand,Library,Stack | Description$ " + inst.getReminderText();
inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic));

View File

@@ -23,12 +23,11 @@ public final class CardPlayOption {
private final boolean withFlash;
private final boolean grantsZonePermissions;
private final Cost altManaCost;
private final boolean altIsAdditional;
public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash, final boolean grantZonePermissions) {
this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, altManaCost, altIsAdditional, withFlash, grantZonePermissions);
public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions) {
this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, altManaCost, withFlash, grantZonePermissions);
}
private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash,
private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final Cost altManaCost, final boolean withFlash,
final boolean grantZonePermissions) {
this.player = player;
this.sta = sta;
@@ -36,7 +35,6 @@ public final class CardPlayOption {
this.withFlash = withFlash;
this.grantsZonePermissions = grantZonePermissions;
this.altManaCost = altManaCost;
this.altIsAdditional = altIsAdditional;
}
@@ -102,14 +100,9 @@ public final class CardPlayOption {
switch (getPayManaCost()) {
case YES:
if (altManaCost != null) {
if (altIsAdditional) {
String desc = sta.getParam("Description");
sb.append(" (").append(desc, desc.indexOf("by "), desc.indexOf("."));
} else {
String insteadCost = getFormattedAltManaCost();
insteadCost = insteadCost.replace("Pay ","");
sb.append(" (by paying ").append(insteadCost).append(" instead of paying its mana cost");
}
String insteadCost = getFormattedAltManaCost();
insteadCost = insteadCost.replace("Pay ","");
sb.append(" (by paying ").append(insteadCost).append(" instead of paying its mana cost");
if (isWithFlash()) {
sb.append(" and as though it has flash");
}
@@ -120,6 +113,10 @@ public final class CardPlayOption {
} else if (isIgnoreManaCostColor()) {
sb.append(" (may spend mana as though it were mana of any color to cast it)");
}
if (sta.hasParam("RaiseCost")) {
String desc = sta.getParam("Description");
sb.append(" (").append(desc, desc.indexOf("by ") + desc.indexOf("pay "), desc.indexOf(".")).append(")");
}
break;
case NO:
sb.append(" (without paying its mana cost");

View File

@@ -84,15 +84,16 @@ public class CostAdjustment {
}
}
}
if (sa.hasParam("RaiseCost")) {
String raise = sa.getParam("RaiseCost");
ManaCost mc;
Cost inc;
if (sa.hasSVar(raise)) {
mc = ManaCost.get(AbilityUtils.calculateAmount(host, raise, sa));
inc = new Cost(ManaCost.get(AbilityUtils.calculateAmount(host, raise, sa)), false);
} else {
mc = new ManaCost(new ManaCostParser(raise));
inc = new Cost(raise, false);
}
result.add(new Cost(mc, false));
result.add(inc);
}
// Raise cost

View File

@@ -938,15 +938,11 @@ public final class StaticAbilityContinuous {
if (controllerMayPlay && (mayPlayLimit == null || stAb.getMayPlayTurn() < mayPlayLimit)) {
String mayPlayAltCost = mayPlayAltManaCost;
boolean additional = mayPlayAltCost != null && mayPlayAltCost.contains("RegularCost");
if (mayPlayAltCost != null) {
if (mayPlayAltCost.contains("ConvertedManaCost")) {
final String costcmc = Integer.toString(affectedCard.getCMC());
mayPlayAltCost = mayPlayAltCost.replace("ConvertedManaCost", costcmc);
} else if (additional) {
final String regCost = affectedCard.getManaCost().getShortString();
mayPlayAltCost = mayPlayAltManaCost.replace("RegularCost", regCost);
}
}
@@ -954,7 +950,7 @@ public final class StaticAbilityContinuous {
AbilityUtils.getDefinedPlayers(affectedCard, params.get("MayPlayPlayer"), stAb).get(0) :
controller;
affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost,
mayPlayAltCost != null ? new Cost(mayPlayAltCost, false, affectedCard.equals(hostCard)) : null, additional, mayPlayWithFlash,
mayPlayAltCost != null ? new Cost(mayPlayAltCost, false, affectedCard.equals(hostCard)) : null, mayPlayWithFlash,
mayPlayGrantZonePermissions, stAb);
// If the MayPlay effect only affected itself, check if it is in graveyard and give other player who cast Shaman's Trance MayPlay
@@ -962,7 +958,7 @@ public final class StaticAbilityContinuous {
for (final Player p : game.getPlayers()) {
if (p.hasKeyword("Shaman's Trance") && mayPlayController != p) {
affectedCard.setMayPlay(p, mayPlayWithoutManaCost,
mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null, additional,
mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null,
mayPlayWithFlash, mayPlayGrantZonePermissions, stAb);
}
}

View File

@@ -40,6 +40,7 @@ import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.PlayEffect;
import forge.game.card.Card;
import forge.game.card.CardCopyService;
import forge.game.event.EventValueChangeType;
@@ -85,7 +86,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
private final List<Card> thisTurnCast = Lists.newArrayList();
private List<Card> lastTurnCast = Lists.newArrayList();
private final List<SpellAbility> abilitiesActivatedThisTurn = Lists.newArrayList();
private final List<SpellAbility> thisTurnActivated = Lists.newArrayList();
private Card curResolvingCard = null;
private final Map<String, List<GameCommand>> commandList = Maps.newHashMap();
@@ -493,6 +494,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
if (sp.isSpell() && sp.getMayPlay() != null) {
sp.getMayPlay().incMayPlayTurn();
if (sp.getMayPlay().hasParam("ReplaceGraveyard")) {
PlayEffect.addReplaceGraveyardEffect(sp.getHostCard(), sp.getMayPlay().getHostCard(), sp, sp, sp.getMayPlay().getParam("ReplaceGraveyard"));
}
}
si = si == null ? new SpellAbilityStackInstance(sp, id) : si;
@@ -503,7 +507,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
Set<Integer> sources = new TreeSet<>();
for (SpellAbilityStackInstance s : stack) {
if (s.isSpell()) {
distinctSources += 1;
distinctSources++;
} else {
sources.add(s.getSourceCard().getId());
}
@@ -895,11 +899,14 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
public final List<Card> getSpellsCastThisTurn() {
return thisTurnCast;
}
public final List<Card> getSpellsCastLastTurn() {
return lastTurnCast;
}
public final void onNextTurn() {
final Player active = game.getPhaseHandler().getPlayerTurn();
game.getStackZone().resetCardsAddedThisTurn();
this.abilitiesActivatedThisTurn.clear();
this.thisTurnActivated.clear();
if (thisTurnCast.isEmpty()) {
lastTurnCast = Lists.newArrayList();
active.resetSpellCastSinceBegOfYourLastTurn();
@@ -914,17 +921,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
game.updateStackForView();
}
public final List<Card> getSpellsCastLastTurn() {
return lastTurnCast;
}
public void addAbilityActivatedThisTurn(SpellAbility sa, final Card source) {
source.addAbilityActivated(sa);
abilitiesActivatedThisTurn.add(sa.copy(CardCopyService.getLKICopy(source), true));
thisTurnActivated.add(sa.copy(CardCopyService.getLKICopy(source), true));
}
public List<SpellAbility> getAbilityActivatedThisTurn() {
return abilitiesActivatedThisTurn;
return thisTurnActivated;
}
public final void addCastCommand(final String valid, final GameCommand c) {

View File

@@ -6,7 +6,7 @@ K:Flying
K:Trample
K:etbCounter:SHIELD:1
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time.
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn+nonLand | AffectedZone$ Library | MayPlay$ True | MayPlayAltManaCost$ RegularCost RemoveAnyCounter<1/Any/Creature.YouCtrl/a creature you control> | Description$ You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs.
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn+nonLand | AffectedZone$ Library | MayPlay$ True | RaiseCost$ RemoveAnyCounter<1/Any/Creature.YouCtrl/a creature you control> | Description$ You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs.
DeckHas:Ability$Counters
DeckHints:Ability$Counters|Proliferate
Oracle:Flying, trample\nFalco Spara, Pactweaver enters the battlefield with a shield counter on it.\nYou may look at the top card of your library any time.\nYou may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs.

View File

@@ -3,7 +3,5 @@ ManaCost:1 U B R
Types:Legendary Creature Human Wizard
PT:3/4
K:Flying
S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | MayPlay$ True | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ During each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead.
R:Event$ Moved | ValidLKI$ Card.CastSa Spell.MayPlaySource | Origin$ Stack | Destination$ Graveyard | ReplaceWith$ MoveExile
SVar:MoveExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Stack | Destination$ Exile
S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | ReplaceGraveyard$ Exile | MayPlay$ True | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ During each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead.
Oracle:Flying\nDuring each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead.

View File

@@ -1,7 +1,5 @@
Name:Maestros Ascendancy
ManaCost:U B R
Types:Enchantment
S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | MayPlay$ True | MayPlayAltManaCost$ RegularCost Sac<1/Creature> | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead.
R:Event$ Moved | ValidLKI$ Card.CastSa Spell.MayPlaySource | Origin$ Stack | Destination$ Graveyard | ReplaceWith$ MoveExile
SVar:MoveExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Stack | Destination$ Exile
S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | ReplaceGraveyard$ Exile | MayPlay$ True | RaiseCost$ Sac<1/Creature> | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead.
Oracle:Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead.

View File

@@ -4,7 +4,6 @@ Types:Creature Human Cleric
PT:1/1
K:A deck can have any number of cards named CARDNAME.
A:AB$ ChangeZone | Cost$ B Sac<6/Creature.namedShadowborn Apostle/creatures named Shadowborn Apostle> | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.Demon | ChangeNum$ 1 | SpellDescription$ Search your library for a Demon creature card, put it onto the battlefield, then shuffle.
DeckNeeds:Name$Shadowborn Apostle
DeckNeeds:Type$Demon
DeckNeeds:Name$Shadowborn Apostle & Type$Demon
DeckHints:Name$Shadowborn Demon
Oracle:A deck can have any number of cards named Shadowborn Apostle.\n{B}, Sacrifice six creatures named Shadowborn Apostle: Search your library for a Demon creature card, put it onto the battlefield, then shuffle.