Compare commits

..

1 Commits

Author SHA1 Message Date
Hans Mackowiak
3d425fea05 Show Mayhem in flashback zone 2025-10-05 14:07:37 +02:00
33 changed files with 119 additions and 57 deletions

View File

@@ -12,13 +12,15 @@ import forge.game.spellability.SpellAbility;
public class FlipACoinAi extends SpellAbilityAi {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#checkApiLogic(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
protected AiAbilityDecision checkApiLogic(Player ai, SpellAbility sa) {
protected AiAbilityDecision canPlay(Player ai, SpellAbility sa) {
if (sa.hasParam("AILogic")) {
String ailogic = sa.getParam("AILogic");
if (ailogic.equals("PhaseOut")) {
if (ailogic.equals("Never")) {
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
} else if (ailogic.equals("PhaseOut")) {
if (!ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(sa.getHostCard())) {
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
}

View File

@@ -522,8 +522,6 @@ public class AbilityUtils {
}
} else if (calcX[0].equals("OriginalHost")) {
val = xCount(ability.getOriginalHost(), calcX[1], ability);
} else if (calcX[0].equals("DungeonsCompleted")) {
val = handlePaid(player.getCompletedDungeons(), calcX[1], card, ability);
} else if (calcX[0].startsWith("ExiledWith")) {
val = handlePaid(card.getExiledCards(), calcX[1], card, ability);
} else if (calcX[0].startsWith("Convoked")) {
@@ -3423,7 +3421,6 @@ public class AbilityUtils {
}
public static int playerXProperty(final Player player, final String s, final Card source, CardTraitBase ctb) {
final String[] l = s.split("/");
final String m = CardFactoryUtil.extractOperators(s);
@@ -3610,10 +3607,46 @@ public class AbilityUtils {
return doXMath(player.hasBeenDealtCombatDamageSinceLastTurn() ? 1 : 0, m, source, ctb);
}
if (value.equals("DungeonsCompleted")) {
return doXMath(player.getCompletedDungeons().size(), m, source, ctb);
}
if (value.equals("RingTemptedYou")) {
return doXMath(player.getNumRingTemptedYou(), m, source, ctb);
}
if (value.startsWith("DungeonCompletedNamed")) {
String [] full = value.split("_");
String name = full[1];
int completed = 0;
List<Card> dungeons = player.getCompletedDungeons();
for (Card c : dungeons) {
if (c.getName().equals(name)) {
++completed;
}
}
return doXMath(completed, m, source, ctb);
}
if (value.equals("DifferentlyNamedDungeonsCompleted")) {
int amount = 0;
List<Card> dungeons = player.getCompletedDungeons();
for (int i = 0; i < dungeons.size(); ++i) {
Card d1 = dungeons.get(i);
boolean hasSameName = false;
for (int j = i - 1; j >= 0; --j) {
Card d2 = dungeons.get(j);
if (d1.getName().equals(d2.getName())) {
hasSameName = true;
break;
}
}
if (!hasSameName) {
++amount;
}
}
return doXMath(amount, m, source, ctb);
}
if (value.equals("AttractionsVisitedThisTurn")) {
return doXMath(player.getAttractionsVisitedThisTurn(), m, source, ctb);
}
@@ -3700,8 +3733,8 @@ public class AbilityUtils {
return CardUtil.getColorsFromCards(paidList).countColors();
}
if (string.startsWith("DifferentCardNames")) {
return doXMath(CardLists.getDifferentNamesCount(paidList), CardFactoryUtil.extractOperators(string), source, ctb);
if (string.equals("DifferentCardNames")) {
return CardLists.getDifferentNamesCount(paidList);
}
if (string.equals("DifferentColorPair")) {

View File

@@ -56,7 +56,7 @@ public class PlayerZone extends Zone {
boolean graveyardCastable = c.hasKeyword(Keyword.FLASHBACK) ||
c.hasKeyword(Keyword.RETRACE) || c.hasKeyword(Keyword.JUMP_START) || c.hasKeyword(Keyword.ESCAPE) ||
c.hasKeyword(Keyword.DISTURB);
c.hasKeyword(Keyword.DISTURB) || c.hasKeyword(Keyword.MAYHEM);
boolean exileCastable = c.isForetold() || c.isOnAdventure();
for (final SpellAbility sa : c.getSpellAbilities()) {
final ZoneType restrictZone = sa.getRestrictions().getZone();

View File

@@ -147,13 +147,10 @@ public class AdventureEventData implements Serializable {
return draft;
}
private static final Predicate<CardEdition> filterPioneer = FModel.getFormats().getPioneer().editionLegalPredicate;
private static final Predicate<CardEdition> filterModern = FModel.getFormats().getModern().editionLegalPredicate;
private static final Predicate<CardEdition> filterVintage = FModel.getFormats().getVintage().editionLegalPredicate;
private static final Predicate<CardEdition> filterStandard = FModel.getFormats().getStandard().editionLegalPredicate;
private static final Predicate<CardEdition> filterPioneer =
FModel.getFormats().getPioneer().editionLegalPredicate.and(filterStandard.negate());
private static final Predicate<CardEdition> filterModern =
FModel.getFormats().getModern().editionLegalPredicate.and(FModel.getFormats().getPioneer().editionLegalPredicate.negate());
private static final Predicate<CardEdition> filterVintage =
FModel.getFormats().getVintage().editionLegalPredicate.and(FModel.getFormats().getModern().editionLegalPredicate.negate());
public static Predicate<CardEdition> selectSetPool() {
// Should we negate any of these to avoid overlap?

View File

@@ -224,17 +224,17 @@ public class VStack extends FDropDown {
activeItem.getLeft() + VStack.CARD_WIDTH * FCardPanel.TARGET_ORIGIN_FACTOR_X + VStack.PADDING + VStack.BORDER_THICKNESS,
activeItem.getTop() + VStack.CARD_HEIGHT * FCardPanel.TARGET_ORIGIN_FACTOR_Y + VStack.PADDING + VStack.BORDER_THICKNESS);
PlayerView activator = activeStackInstance == null ? null : activeStackInstance.getActivatingPlayer();
PlayerView activator = activeStackInstance.getActivatingPlayer();
arrowOrigin = arrowOrigin.add(screenPos.x, screenPos.y);
StackItemView instance = activeStackInstance;
while (instance != null) {
for (CardView c : instance.getTargetCards()) {
TargetingOverlay.ArcConnection conn = activator != null && activator.isOpponentOf(c.getController()) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.ArcConnection conn = activator.isOpponentOf(c.getController()) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.drawArrow(g, arrowOrigin, VCardDisplayArea.CardAreaPanel.get(c).getTargetingArrowOrigin(), conn);
}
for (PlayerView p : instance.getTargetPlayers()) {
TargetingOverlay.ArcConnection conn = activator != null && activator.isOpponentOf(p) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.ArcConnection conn = activator.isOpponentOf(p) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.drawArrow(g, arrowOrigin, MatchScreen.getPlayerPanel(p).getAvatar().getTargetingArrowOrigin(), conn);
}
instance = instance.getSubInstance();

View File

@@ -5,7 +5,7 @@ PT:5/5
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ X | SVarCompare$ LT1 | Execute$ TrigBounce | TriggerDescription$ When CARDNAME enters, if you haven't completed Tomb of Annihilation, return CARDNAME to its owner's hand and venture into the dungeon.
SVar:TrigBounce:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBVenture
SVar:DBVenture:DB$ Venture
SVar:X:DungeonsCompleted$Valid Card.namedTomb of Annihilation
SVar:X:PlayerCountPropertyYou$DungeonCompletedNamed_Tomb of Annihilation
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigRepeat | TriggerDescription$ Whenever CARDNAME attacks, for each opponent, you create a 2/2 black Zombie creature token unless that player sacrifices a creature.
SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Opponent | RepeatSubAbility$ DBToken
SVar:DBToken:DB$ Token | TokenScript$ b_2_2_zombie | UnlessCost$ Sac<1/Creature> | UnlessPayer$ Player.IsRemembered

View File

@@ -19,9 +19,9 @@ Types:Legendary Creature Avatar Ally
PT:6/6
K:Flying
S:Mode$ ReduceCost | ValidCard$ Card | Type$ Spell | Activator$ You | Amount$ 1 | Color$ W U B R G | Description$ Spells you cast cost {W}{U}{B}{R}{G} less to cast. (This can reduce generic costs.)
T:Mode$ Phase | Phase$ Upkeep | TriggerZones$ Battlefield | Execute$ TrigTransform | OptionalDecider$ You | TriggerDescription$ At the beginning of each upkeep, you may transform CARDNAME. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.
SVar:TrigTransform:DB$ SetState | Defined$ Self | Mode$ Transform | RememberChanged$ True | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBDraw
T:Mode$ Phase | Phase$ Upkeep | TriggerZones$ Battlefield | Execute$ TrigToken | OptionalDecider$ You | TriggerDescription$ At the beginning of each upkeep, you may transform CARDNAME. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.
SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform | RememberChanged$ True | SubAbility$ DBGainLife
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw | NumCards$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 4 | CounterNum$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBCleanup

View File

@@ -6,7 +6,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
T:Mode$ Attacks | ValidCard$ Card.Self | CheckSVar$ X | SVarCompare$ GE1 | Execute$ DBChangeZone | TriggerDescription$ Whenever CARDNAME attacks, return up to one creature card with mana value 3 or less from your graveyard to the battlefield if you've completed a dungeon.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | ChangeType$ Creature.YouOwn+cmcLE3
SVar:DBVenture:DB$ Venture | Defined$ You
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
DeckHints:Ability$Mill|Discard
DeckHas:Ability$Graveyard
Oracle:When Barrowin of Clan Undurr enters, venture into the dungeon. (Enter the first room or advance to the next room.)\nWhenever Barrowin of Clan Undurr attacks, return up to one creature card with mana value 3 or less from your graveyard to the battlefield if you've completed a dungeon.

View File

@@ -3,7 +3,7 @@ ManaCost:no cost
Types:Land Desert
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | RestrictValid$ Spell.Mount | SpellDescription$ Add one mana of any color. Spend this mana only to cast a Mount spell.
A:AB$ PeekAndReveal | Cost$ 3 T | PeekAmount$ 1 | RevealValid$ Card.Mount | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBChangeZone | AILogic$ AtOppEOT | SpellDescription$ Look at the top card of your library. If it's a Mount card, you may reveal it and put it into your hand. If you don't put it into your hand, you may put it on the bottom of your library.
A:AB$ PeekAndReveal | Cost$ 3 T | PeekAmount$ 1 | RevealValid$ Card.Mount | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBChangeZone | SpellDescription$ Look at the top card of your library. If it's a Mount card, you may reveal it and put it into your hand. If you don't put it into your hand, you may put it on the bottom of your library.
SVar:DBChangeZone:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2
SVar:DBChangeZone2:DB$ ChangeZone | Optional$ True | Defined$ TopOfLibrary | Origin$ Library | Destination$ Library | LibraryPosition$ -1 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -13,6 +13,6 @@ SVar:STPlay2:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | A
SVar:DBEffect:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | ForgetOnMoved$ Exile
SVar:STPlay:Mode$ Continuous | MayPlay$ True | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play that card this turn.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
SVar:HasAttackEffect:TRUE
Oracle:Trample\nWhen Caves of Chaos Adventurer enters, you take the initiative.\nWhenever Caves of Chaos Adventurer attacks, exile the top card of your library. If you've completed a dungeon, you may play that card this turn without paying its mana cost. Otherwise, you may play that card this turn.

View File

@@ -5,5 +5,5 @@ PT:0/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBVenture | TriggerDescription$ When CARDNAME enters, venture into the dungeon. (Enter the first room or advance to the next room.)
SVar:DBVenture:DB$ Venture | Defined$ You
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 3 | AddKeyword$ Flying | CheckSVar$ X | SVarCompare$ GE1 | Description$ As long as you've completed a dungeon, CARDNAME gets +3/+0 and has flying.
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:When Cloister Gargoyle enters, venture into the dungeon. (Enter the first room or advance to the next room.)\nAs long as you've completed a dungeon, Cloister Gargoyle gets +3/+0 and has flying.

View File

@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$
SVar:TrigVenture:DB$ Venture
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | CheckSVar$ X | Execute$ TrigAnimate | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of combat on your turn, if you've completed a dungeon, up to one target creature becomes a Bird with base power and toughness 1/1 and flying until end of turn.
SVar:TrigAnimate:DB$ Animate | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target creature | Power$ 1 | Toughness$ 1 | Types$ Bird | RemoveCreatureTypes$ True | Keywords$ Flying
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Flying\nWhen Eccentric Apprentice enters, venture into the dungeon. (Enter the first room or advance to the next room.)\nAt the beginning of combat on your turn, if you've completed a dungeon, up to one target creature becomes a Bird with base power and toughness 1/1 and flying until end of turn.

View File

@@ -9,5 +9,5 @@ SVar:IsLegendary:Count$ValidHand Creature.Legendary+IsRemembered
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ Effect | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Emblem — Ellywick Tumblestrum | Image$ emblem_ellywick_tumblestrum | StaticAbilities$ STOverrun | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed."
SVar:STOverrun:Mode$ Continuous | Affected$ Creature.YouCtrl | AffectedZone$ Battlefield | AddPower$ X | AddToughness$ X | AddKeyword$ Trample & Haste | Description$ Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed.
SVar:X:DungeonsCompleted$DifferentCardNames/Twice
SVar:X:PlayerCountPropertyYou$DifferentlyNamedDungeonsCompleted/Twice
Oracle:[+1]: Venture into the dungeon. (Enter the first room or advance to the next room.)\n[-2]: Look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. If it's legendary, you gain 3 life. Put the rest on the bottom of your library in a random order.\n[-7]: You get an emblem with "Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed."

View File

@@ -3,5 +3,5 @@ ManaCost:2 W
Types:Creature Dwarf Ranger
PT:2/3
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Double Strike | CheckSVar$ X | SVarCompare$ GE1 | Description$ As long as you've completed a dungeon, CARDNAME has double strike.
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:As long as you've completed a dungeon, Gloom Stalker has double strike.

View File

@@ -7,5 +7,5 @@ T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefiel
SVar:TrigDraw:DB$ Draw | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw | ConditionCheckSVar$ X
K:Choose a Background
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Ward {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)\nAt the beginning of your end step, if you have the initiative, draw a card. Draw another card if you've completed a dungeon.\nChoose a Background (You can have a Background as a second commander.)

View File

@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters or attacks, venture into the dungeon. (Enter the first room or advance to the next room.)
SVar:DBVenture:DB$ Venture | Defined$ You
S:Mode$ Continuous | Affected$ Creature.YouCtrl+Other | AddPower$ 1 | AddToughness$ 1 | CheckSVar$ X | SVarCompare$ GE1 | Description$ Other creatures you control get +1/+1 as long as you've completed a dungeon.
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Vigilance\nWhenever Nadaar, Selfless Paladin enters or attacks, venture into the dungeon. (Enter the first room or advance to the next room.)\nOther creatures you control get +1/+1 as long as you've completed a dungeon.

View File

@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$
SVar:TrigVenture:DB$ Venture
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ -X | AddToughness$ -X | Description$ Enchanted creature gets -2/-2. It gets -5/-5 instead as long as you've completed a dungeon.
SVar:X:Count$Compare Y GE1.5.2
SVar:Y:DungeonsCompleted$Amount
SVar:Y:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Enchant creature\nWhen Precipitous Drop enters, venture into the dungeon. (Enter the first room or advance to the next room.)\nEnchanted creature gets -2/-2. It gets -5/-5 instead as long as you've completed a dungeon.

View File

@@ -10,7 +10,7 @@ SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ HIT | SubA
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigLoseLife | CheckSVar$ X | TriggerDescription$ Whenever CARDNAME attacks, if you've completed a dungeon, defending player loses 1 life for each card they own in exile with a hit counter on it.
SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredDefendingPlayer | LifeAmount$ Y
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
SVar:Y:TriggeredDefendingPlayer$ValidExile Card.YouOwn+counters_GE1_HIT
SVar:HasAttackEffect:TRUE
DeckHints:Name$Etrata, the Silencer|Mari, the Killing Quill

View File

@@ -8,5 +8,5 @@ SVar:TrigInitiative:DB$ TakeInitiative
T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, target attacking creature gains deathtouch until end of turn. If you've completed a dungeon, that creature also gets +5/+0 and gains first strike and menace until end of turn.
SVar:TrigPump:DB$ Pump | KW$ Deathtouch | TgtPrompt$ Select target attacking creature | ValidTgts$ Creature.attacking | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | ConditionCheckSVar$ X | NumAtt$ +5 | KW$ First Strike & Menace | Defined$ Targeted
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Deathtouch\nWhen Rilsa Rael, Kingpin enters, you take the initiative.\nWhenever you attack, target attacking creature gains deathtouch until end of turn. If you've completed a dungeon, that creature also gets +5/+0 and gains first strike and menace until end of turn.

View File

@@ -5,7 +5,7 @@ PT:5/5
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ X | SVarCompare$ LT1 | Execute$ TrigBounce | TriggerDescription$ When CARDNAME enters, if you haven't completed Tomb of Annihilation, return CARDNAME to its owner's hand and venture into the dungeon.
SVar:TrigBounce:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBVenture
SVar:DBVenture:DB$ Venture
SVar:X:DungeonsCompleted$Valid Card.namedTomb of Annihilation
SVar:X:PlayerCountPropertyYou$DungeonCompletedNamed_Tomb of Annihilation
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME attacks, create a number of 2/2 black Zombie creature tokens equal to the number of opponents you have.
SVar:TrigToken:DB$ Token | TokenAmount$ Y | TokenScript$ b_2_2_zombie | TokenOwner$ You
SVar:Y:PlayerCountOpponents$Amount

View File

@@ -5,5 +5,5 @@ PT:0/3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBVenture | TriggerDescription$ When CARDNAME enters, venture into the dungeon.
SVar:DBVenture:DB$ Venture | Defined$ You
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 3 | AddKeyword$ Flying | CheckSVar$ X | SVarCompare$ GE1 | Description$ As long as you've completed a dungeon, CARDNAME gets +3/+0 and has flying.
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:When Cloister Gargoyle enters, venture into the dungeon.\nAs long as you've completed a dungeon, Cloister Gargoyle gets +3/+0 and has flying.

View File

@@ -9,5 +9,5 @@ SVar:IsLegendary:Count$ValidHand Creature.Legendary+IsRemembered
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ Effect | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Emblem — Ellywick Tumblestrum | Image$ emblem_ellywick_tumblestrum | StaticAbilities$ STOverrun | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed."
SVar:STOverrun:Mode$ Continuous | Affected$ Creature.YouCtrl | AffectedZone$ Battlefield | AddPower$ X | AddToughness$ X | AddKeyword$ Trample & Haste | Description$ Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed.
SVar:X:DungeonsCompleted$DifferentCardNames/Twice
SVar:X:PlayerCountPropertyYou$DifferentlyNamedDungeonsCompleted/Twice
Oracle:[+1]: Venture into the dungeon.\n[-2]: Look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. If it's legendary, you gain 3 life. Put the rest on the bottom of your library in a random order.\n[-6]: You get an emblem with "Creatures you control have trample and haste and get +2/+2 for each differently named dungeon you've completed."

View File

@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$
SVar:TrigVenture:DB$ Venture
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ -X | AddToughness$ -X | Description$ Enchanted creature gets -2/-2. It gets -5/-5 instead as long as you've completed a dungeon.
SVar:X:Count$Compare Y GE1.5.2
SVar:Y:DungeonsCompleted$Amount
SVar:Y:PlayerCountPropertyYou$DungeonsCompleted
Oracle:Enchant creature\nWhen Precipitous Drop enters, venture into the dungeon.\nEnchanted creature gets -2/-2. It gets -5/-5 instead as long as you've completed a dungeon.

View File

@@ -6,7 +6,7 @@ K:Menace
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | CheckDefinedPlayer$ You.hasInitiative | Execute$ TrigTreasure | TriggerDescription$ At the beginning of your end step, if you have the initiative, create a Treasure token. If you've completed a dungeon, create three of those tokens instead.
SVar:TrigTreasure:DB$ Token | TokenAmount$ X | TokenScript$ c_a_treasure_sac
SVar:X:Count$Compare Y GE1.3.1
SVar:Y:DungeonsCompleted$Amount
SVar:Y:PlayerCountPropertyYou$DungeonsCompleted
K:Choose a Background
AI:RemoveDeck:Random
DeckHas:Ability$Token|Sacrifice & Type$Artifact|Treasure

View File

@@ -8,5 +8,5 @@ SVar:X:Count$Initiative.2.1
A:AB$ DigUntil | Cost$ 3 T | Valid$ Card.nonLand | ValidDescription$ nonland | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPlay | CheckSVar$ Y | NoPutDesc$ True | SpellDescription$ Exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost. Activate only if you've completed a dungeon.
SVar:DBPlay:DB$ Play | Defined$ Remembered | DefinedDesc$ that card | ValidSA$ Spell | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Y:DungeonsCompleted$Amount
SVar:Y:PlayerCountPropertyYou$DungeonsCompleted
Oracle:When Sarevok's Tome enters, you take the initiative.\n{T}: Add {C}. If you have the initiative, add {C}{C} instead.\n{3}, {T}: Exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost. Activate only if you've completed a dungeon.

View File

@@ -2,7 +2,7 @@ Name:The Gold Saucer
ManaCost:no cost
Types:Land Town
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ FlipACoin | Cost$ 2 T | WinSubAbility$ DBToken | AILogic$ AtOppEOT | SpellDescription$ Flip a coin. If you win the flip, create a Treasure token.
A:AB$ FlipACoin | Cost$ 2 T | WinSubAbility$ DBToken | SpellDescription$ Flip a coin. If you win the flip, create a Treasure token.
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You
A:AB$ Draw | Cost$ 3 T Sac<2/Artifact> | SpellDescription$ Draw a card.
DeckHas:Ability$Token

View File

@@ -8,7 +8,6 @@ SVar:DBExile:DB$ ChangeZone | ValidTgts$ Opponent | ChangeType$ Card.NamedCard |
SVar:DBTransform:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBReturn | SpellDescription$ Exile this Saga, then return it to the battlefield transformed under your control.
SVar:DBReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | Transformed$ True | GainControl$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AlternateMode:DoubleFaced
Oracle:(As this Saga enters and after your draw step, add a lore counter.)\nI — Destroy all creatures.\nII — Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. Then that player shuffles.\nIII — Exile this Saga, then return it to the battlefield transformed under your control.
ALTERNATE

View File

@@ -6,7 +6,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:TrigInitiative:DB$ TakeInitiative
T:Mode$ SpellCast | ValidCard$ Card.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigCopy | ActivatorThisTurnCast$ EQ2 | ValidActivatingPlayer$ You | TriggerDescription$ Whenever you cast your second spell each turn, copy it. If you've completed a dungeon, copy that spell twice instead. You may choose new targets for the copies. (A copy of a permanent spell becomes a token.)
SVar:TrigCopy:DB$ CopySpellAbility | Amount$ Y | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
SVar:Y:Count$Compare X GE1.2.1
DeckHas:Ability$Token
Oracle:When Tomb of Horrors Adventurer enters, you take the initiative.\nWhenever you cast your second spell each turn, copy it. If you've completed a dungeon, copy that spell twice instead. You may choose new targets for the copies. (A copy of a permanent spell becomes a token.)

View File

@@ -6,6 +6,6 @@ K:Vigilance
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigInitiative | TriggerDescription$ When CARDNAME enters, you take the initiative.
SVar:TrigInitiative:DB$ TakeInitiative
A:AB$ Mana | Cost$ T | Produced$ G | Amount$ Y | SpellDescription$ Add {G}{G}. If you've completed a dungeon, add six {G} instead.
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
SVar:Y:Count$Compare X GE1.6.2
Oracle:Vigilance\nWhen Undermountain Adventurer enters, you take the initiative.\n{T}: Add {G}{G}. If you've completed a dungeon, add six {G} instead.

View File

@@ -2,8 +2,8 @@ Name:Garland, Royal Kidnapper
ManaCost:2 U B
Types:Legendary Creature Human Knight
PT:3/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When NICKNAME enters, target opponent becomes the monarch.
SVar:TrigMonarch:DB$ BecomeMonarch | ValidTgts$ Opponent
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When NICKNAME enters, you become the monarch.
SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You
T:Mode$ BecomeMonarch | ValidPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigEffect | TriggerDescription$ Whenever an opponent becomes the monarch, gain control of target creature that player controls for as long as they're the monarch.
SVar:TrigEffect:DB$ Effect | ImprintCards$ Targeted | ValidTgts$ Creature.ControlledBy TriggeredPlayer | TgtPrompt$ Choose target creature that player controls | RememberObjects$ TriggeredPlayer | Triggers$ ExileMe | StaticAbilities$ GainControl | Duration$ Permanent
SVar:GainControl:Mode$ Continuous | Affected$ Card.IsImprinted | CheckSVar$ X | SVarCompare$ EQ1 | GainControl$ You | Description$ You gain control of that creature for as long as that player is the monarch.
@@ -12,4 +12,4 @@ SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$
SVar:X:PlayerCountRememberedPlayer$HasPropertyisMonarch
S:Mode$ Continuous | Affected$ Creature.YouCtrl+YouDontOwn| AddPower$ 2 | AddToughness$ 2 | Description$ Creatures you control but don't own get +2/+2 and can't be sacrificed.
S:Mode$ CantSacrifice | ValidCard$ Creature.YouCtrl+YouDontOwn | Secondary$ True | SpellDescription$ Creatures you control but don't own get +2/+2 and can't be sacrificed.
Oracle:When Garland enters, target opponent becomes the monarch.\nWhenever an opponent becomes the monarch, gain control of target creature that player controls for as long as they're the monarch.\nCreatures you control but don't own get +2/+2 and can't be sacrificed.
Oracle:When Garland enters, you become the monarch.\nWhenever an opponent becomes the monarch, gain control of target creature that player controls for as long as they're the monarch.\nCreatures you control but don't own get +2/+2 and can't be sacrificed.

View File

@@ -8,5 +8,5 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Opponent | TriggerZones$ Battlefiel
SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | TrueSubAbility$ DBUntapAll | FalseSubAbility$ DBUntap
SVar:DBUntapAll:DB$ UntapAll | ValidCards$ Creature.YouCtrl
SVar:DBUntap:DB$ Untap | UntapExactly$ True | UntapType$ Creature.YouCtrl+tapped | Amount$ 1
SVar:X:DungeonsCompleted$Amount
SVar:X:PlayerCountPropertyYou$DungeonsCompleted
Oracle:When White Plume Adventurer enters battlefield, you take the initiative.\nAt the beginning of each opponent's upkeep, untap a creature you control. If you've completed a dungeon, untap all creatures you control instead.

View File

@@ -99,10 +99,7 @@ public final class BoosterUtils {
if (userPrefs != null && userPrefs.getPoolType() == StartingPoolPreferences.PoolType.BOOSTERS) {
Predicate<CardEdition> editionLegalPredicate = formatStartingPool == null
? cardEdition -> true
: formatStartingPool.editionLegalPredicate;
for (InventoryItem inventoryItem : generateRandomBoosterPacks(userPrefs.getNumberOfBoosters(), editionLegalPredicate)) {
for (InventoryItem inventoryItem : generateRandomBoosterPacks(userPrefs.getNumberOfBoosters(), formatStartingPool.editionLegalPredicate)) {
cards.addAll(((BoosterPack) inventoryItem).getCards());
}

View File

@@ -62,6 +62,7 @@ import forge.util.storage.IStorage;
public class QuestEventDraft implements IQuestEvent {
public static class QuestDraftPrizes {
public int credits;
public List<BoosterPack> boosterPacks;
public List<PaperCard> individualCards;
@@ -84,6 +85,7 @@ public class QuestEventDraft implements IQuestEvent {
public void addSelectedCard(final PaperCard card) {
FModel.getQuest().getCards().addSingleCard(card, 1);
}
}
public static final String UNDETERMINED = "quest_draft_undetermined_place";
@@ -231,6 +233,7 @@ public class QuestEventDraft implements IQuestEvent {
}
public void setWinner(final String playerName) {
if (QuestDraftUtils.TOURNAMENT_TOGGLE) {
TournamentPairing pairing = bracket.getNextPairing();
for(TournamentPlayer player : pairing.getPairedPlayers()) {
@@ -287,6 +290,7 @@ public class QuestEventDraft implements IQuestEvent {
* Generates the prizes for the player and saves them to the current quest.
*/
public QuestDraftPrizes collectPrizes() {
final int place = getPlayerPlacement();
int prizePool = entryFee * 9;
@@ -341,9 +345,11 @@ public class QuestEventDraft implements IQuestEvent {
}
return null;
}
private QuestDraftPrizes generateFirstPlacePrizes(final int prizePool) {
int credits = 2 * (prizePool / 3); //First place gets 2/3 the total prize pool
final List<PaperCard> cards = new ArrayList<>();
final List<BoosterPack> boosters = new ArrayList<>();
@@ -360,9 +366,11 @@ public class QuestEventDraft implements IQuestEvent {
awardSelectedRare(prizes);
return prizes;
}
private QuestDraftPrizes generateSecondPlacePrizes(final int prizePool) {
int credits = prizePool / 3; //Second place gets 1/3 the total prize pool
final List<PaperCard> cards = new ArrayList<>();
final List<BoosterPack> boosters = new ArrayList<>();
@@ -380,9 +388,11 @@ public class QuestEventDraft implements IQuestEvent {
awardSelectedRare(prizes);
return prizes;
}
private QuestDraftPrizes generateThirdPlacePrizes() {
final int credits = 0;
final List<PaperCard> cards = new ArrayList<>();
@@ -397,9 +407,11 @@ public class QuestEventDraft implements IQuestEvent {
prizes.individualCards = cards;
return prizes;
}
private QuestDraftPrizes generateFourthPlacePrizes() {
final int credits = 0;
final List<PaperCard> cards = new ArrayList<>();
@@ -428,6 +440,7 @@ public class QuestEventDraft implements IQuestEvent {
}
private void awardSelectedRare(final QuestDraftPrizes prizes) {
final List<PaperCard> possibleCards = new ArrayList<>();
final List<String> cardNames = new ArrayList<>();
@@ -453,6 +466,7 @@ public class QuestEventDraft implements IQuestEvent {
}
private PaperCard getPromoCard() {
final CardEdition randomEdition = getRandomEdition();
final List<EditionEntry> cardsInEdition = new ArrayList<>();
final List<String> cardNames = new ArrayList<>();
@@ -466,11 +480,6 @@ public class QuestEventDraft implements IQuestEvent {
}
}
// For sets such as MB1 that only have cards from PLST.
if (cardsInEdition.isEmpty()) {
return FModel.getQuest().getCards().addRandomRare();
}
EditionEntry randomCard;
PaperCard promo = null;
@@ -486,6 +495,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return promo;
}
private CardEdition getRandomEdition() {
@@ -496,6 +506,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return editions.get((int) (MyRandom.getRandom().nextDouble() * editions.size()));
}
private Set<CardEdition> getAllEditions() {
@@ -506,6 +517,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return editions;
}
private static int getBoosterPrice(final BoosterPack booster) {
@@ -516,9 +528,11 @@ public class QuestEventDraft implements IQuestEvent {
value = MAP_PRICES.getOrDefault(boosterName, 395);
return value;
}
public boolean playerHasMatchesLeft() {
if (QuestDraftUtils.TOURNAMENT_TOGGLE) {
return !bracket.isTournamentOver() && bracket.isPlayerRemaining(-1);
}
@@ -571,6 +585,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return nextMatchIndex != -1 && standings[nextMatchIndex].equals(UNDETERMINED);
}
public int getPlayerPlacement() {
@@ -607,9 +622,11 @@ public class QuestEventDraft implements IQuestEvent {
}
return -1;
}
public String getPlacementString() {
final int place = getPlayerPlacement();
String output;
@@ -633,6 +650,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return output;
}
public boolean canEnter() {
@@ -665,6 +683,7 @@ public class QuestEventDraft implements IQuestEvent {
}
public static class QuestDraftFormat implements Comparable<QuestDraftFormat> {
private CardEdition edition;
private CardBlock block;
@@ -727,9 +746,11 @@ public class QuestEventDraft implements IQuestEvent {
public int compareTo(final QuestDraftFormat other) {
return toString().compareToIgnoreCase(other.toString());
}
}
private static List<CardEdition> getAllowedSets(final QuestController quest) {
final List<CardEdition> allowedQuestSets = new ArrayList<>();
if (quest.getFormat() != null) {
@@ -750,9 +771,11 @@ public class QuestEventDraft implements IQuestEvent {
}
return allowedQuestSets;
}
private static List<CardBlock> getBlocks() {
final List<CardBlock> blocks = new ArrayList<>();
final IStorage<CardBlock> storage = FModel.getBlocks();
@@ -763,9 +786,11 @@ public class QuestEventDraft implements IQuestEvent {
}
return blocks;
}
public static List<QuestDraftFormat> getAvailableFormats(final QuestController quest) {
final List<CardEdition> allowedQuestSets = getAllowedSets(quest);
final List<QuestDraftFormat> possibleFormats = new ArrayList<>();
final List<CardBlock> blocks = getBlocks();
@@ -787,6 +812,7 @@ public class QuestEventDraft implements IQuestEvent {
if (blockAllowed) {
possibleFormats.add(new QuestDraftFormat(block));
}
}
for (CardEdition allowedQuestSet : allowedQuestSets) {
@@ -814,6 +840,7 @@ public class QuestEventDraft implements IQuestEvent {
Collections.sort(possibleFormats);
return possibleFormats;
}
/**
@@ -822,6 +849,7 @@ public class QuestEventDraft implements IQuestEvent {
* @return The created draft or null in the event no draft could be created.
*/
public static QuestEventDraft getRandomDraftOrNull(final QuestController quest) {
final List<QuestDraftFormat> possibleFormats = getAvailableFormats(quest);
if (possibleFormats.isEmpty()) {
@@ -830,6 +858,7 @@ public class QuestEventDraft implements IQuestEvent {
Collections.shuffle(possibleFormats);
return getDraftOrNull(quest, possibleFormats.get(0));
}
/**
@@ -837,6 +866,7 @@ public class QuestEventDraft implements IQuestEvent {
* @return The created draft or null in the event no draft could be created.
*/
public static QuestEventDraft getDraftOrNull(final QuestController quest, final QuestDraftFormat format) {
final QuestEventDraft event = new QuestEventDraft(format.getName());
if (format.isSet()) {
@@ -906,11 +936,13 @@ public class QuestEventDraft implements IQuestEvent {
event.aiIcons[i] = icon;
usedNames.add(event.aiNames[i]);
usedIcons.add(icon);
}
event.bracket = createBracketFromStandings(event.standings, event.aiNames, event.aiIcons);
return event;
}
private static int calculateEntryFee(final String[] boosters) {
@@ -928,6 +960,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return (int) (entryFee * 1.5);
}
private static Set<String> getSetCombos(final QuestController quest, final CardBlock block) {
@@ -1008,6 +1041,7 @@ public class QuestEventDraft implements IQuestEvent {
}
return possibleCombinations;
}
public static TournamentBracket createBracketFromStandings(String[] standings, String[] aiNames, int[] aiIcons) {