Skip to content

Commit

Permalink
last cards/tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
Northmoc committed Nov 15, 2023
1 parent c654c7d commit a80bb97
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
import forge.game.cost.CostPart;
import forge.game.cost.CostReveal;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.spellability.LandAbility;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.Localizer;

import org.apache.commons.lang3.StringUtils;
Expand All @@ -33,118 +35,121 @@ public class DiscoverEffect extends SpellAbilityEffect {

@Override
protected String getStackDescription(SpellAbility sa) {
final PlayerCollection players = getDefinedPlayersOrTargeted(sa);
final String verb = players.size() == 1 ? " discovers " : " discover ";

return sa.getActivatingPlayer() + " discovers " + sa.getParamOrDefault("Num", "1") + ".";
return Lang.joinHomogenous(players) + verb + sa.getParamOrDefault("Num", "1") + ".";
}

@Override
public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard();
final Game game = host.getGame();
final Player p = sa.getActivatingPlayer();
final PlayerCollection players = getDefinedPlayersOrTargeted(sa);

// Exile cards from the top of your library until you exile a nonland card with <N> mana value or less.
final int num = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);

if (p == null || !p.isInGame()) return;
for (final Player p : players) {
if (p == null || !p.isInGame()) return;

Card found = null;
CardCollection exiled = new CardCollection();
CardCollection rest = new CardCollection();
Card found = null;
CardCollection exiled = new CardCollection();
CardCollection rest = new CardCollection();

final PlayerZone library = p.getZone(ZoneType.Library);
final PlayerZone library = p.getZone(ZoneType.Library);

for (final Card c : library) {
exiled.add(c);
if (!c.isLand() && c.getCMC() <= num) {
found = c;
if (sa.hasParam("RememberDiscovered"))
host.addRemembered(c);
break;
} else {
rest.add(c);
for (final Card c : library) {
exiled.add(c);
if (!c.isLand() && c.getCMC() <= num) {
found = c;
if (sa.hasParam("RememberDiscovered"))
host.addRemembered(c);
break;
} else {
rest.add(c);
}
}
}

if (exiled.size() > 0) {
game.getAction().reveal(exiled, p, false);
}

changeZone(exiled, ZoneType.Exile, game, sa);

// Cast it without paying its mana cost or put it into your hand.
if (found != null) {
String prompt = Localizer.getInstance().getMessage("lblDiscoverChoice",
CardTranslation.getTranslatedName(found.getName()));
final Zone origin = found.getZone();
List<String> options =
Arrays.asList(StringUtils.capitalize(Localizer.getInstance().getMessage("lblCast")),
StringUtils.capitalize(Localizer.getInstance().getMessage("lblHandZone")));
final boolean play = p.getController().confirmAction(sa, null, prompt, options, found, null);
boolean cancel = false;

if (play) {
// get basic spells (no flashback, etc.)
List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(found, p);

// filter out land abilities due to MDFC or similar
Iterables.removeIf(sas, Predicates.instanceOf(LandAbility.class));
// the spell must also have a mana value equal to or less than the discover number
sas.removeIf(sp -> sp.getPayCosts().getTotalMana().getCMC() > num);

if (sas.isEmpty()) { // shouldn't happen!
System.err.println("DiscoverEffect Error: " + host + " found " + found + " but couldn't play sa");
} else {
SpellAbility tgtSA = p.getController().getAbilityToPlay(found, sas);
if (exiled.size() > 0) {
game.getAction().reveal(exiled, p, false);
}

if (tgtSA == null) { // in case player canceled from choice dialog
cancel = true;
changeZone(exiled, ZoneType.Exile, game, sa);

// Cast it without paying its mana cost or put it into your hand.
if (found != null) {
String prompt = Localizer.getInstance().getMessage("lblDiscoverChoice",
CardTranslation.getTranslatedName(found.getName()));
final Zone origin = found.getZone();
List<String> options =
Arrays.asList(StringUtils.capitalize(Localizer.getInstance().getMessage("lblCast")),
StringUtils.capitalize(Localizer.getInstance().getMessage("lblHandZone")));
final boolean play = p.getController().confirmAction(sa, null, prompt, options, found, null);
boolean cancel = false;

if (play) {
// get basic spells (no flashback, etc.)
List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(found, p);

// filter out land abilities due to MDFC or similar
Iterables.removeIf(sas, Predicates.instanceOf(LandAbility.class));
// the spell must also have a mana value equal to or less than the discover number
sas.removeIf(sp -> sp.getPayCosts().getTotalMana().getCMC() > num);

if (sas.isEmpty()) { // shouldn't happen!
System.err.println("DiscoverEffect Error: " + host + " found " + found + " but couldn't play sa");
} else {
tgtSA = tgtSA.copyWithNoManaCost();

// 118.8c
boolean optional = false;
for (CostPart cost : tgtSA.getPayCosts().getCostParts()) {
if ((cost instanceof CostDiscard || cost instanceof CostReveal)
&& !cost.getType().equals("Card") && !cost.getType().equals("Random")) {
optional = true;
break;
SpellAbility tgtSA = p.getController().getAbilityToPlay(found, sas);

if (tgtSA == null) { // in case player canceled from choice dialog
cancel = true;
} else {
tgtSA = tgtSA.copyWithNoManaCost();

// 118.8c
boolean optional = false;
for (CostPart cost : tgtSA.getPayCosts().getCostParts()) {
if ((cost instanceof CostDiscard || cost instanceof CostReveal)
&& !cost.getType().equals("Card") && !cost.getType().equals("Random")) {
optional = true;
break;
}
}
if (!optional) {
tgtSA.getPayCosts().setMandatory(true);
}
}
if (!optional) {
tgtSA.getPayCosts().setMandatory(true);
}

if (tgtSA.usesTargeting() && !optional) {
tgtSA.getTargetRestrictions().setMandatory(true);
}

tgtSA.setSVar("IsCastFromPlayEffect", "True");
if (tgtSA.usesTargeting() && !optional) {
tgtSA.getTargetRestrictions().setMandatory(true);
}

if (p.getController().playSaFromPlayEffect(tgtSA)) {
final Card played = tgtSA.getHostCard();
// add remember successfully played here if ever needed
final Zone zone = game.getCardState(played).getZone();
if (!origin.equals(zone)) {
CardZoneTable trigList = new CardZoneTable();
trigList.put(origin.getZoneType(), zone.getZoneType(), game.getCardState(found));
trigList.triggerChangesZoneAll(game, sa);
tgtSA.setSVar("IsCastFromPlayEffect", "True");

if (p.getController().playSaFromPlayEffect(tgtSA)) {
final Card played = tgtSA.getHostCard();
// add remember successfully played here if ever needed
final Zone zone = game.getCardState(played).getZone();
if (!origin.equals(zone)) {
CardZoneTable trigList = new CardZoneTable();
trigList.put(origin.getZoneType(), zone.getZoneType(), game.getCardState(found));
trigList.triggerChangesZoneAll(game, sa);
}
}
}
}
}
if (!play || cancel) changeZone(new CardCollection(found), ZoneType.Hand, game, sa);
}
if (!play || cancel) changeZone(new CardCollection(found), ZoneType.Hand, game, sa);
}

// Put the rest on the bottom in a random order.
changeZone(rest, ZoneType.Library, game, sa);

// Run discover triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
runParams.put(AbilityKey.Amount, num);
game.getTriggerHandler().runTrigger(TriggerType.Discover, runParams, false);
// Put the rest on the bottom in a random order.
changeZone(rest, ZoneType.Library, game, sa);

// Run discover triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
runParams.put(AbilityKey.Amount, num);
game.getTriggerHandler().runTrigger(TriggerType.Discover, runParams, false);
}
}

private void changeZone(CardCollection cards, ZoneType zone, Game game, SpellAbility sa) {
Expand Down
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/b/blow_your_house_down.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Name:Blow Your House Down
ManaCost:2 R
Types:Sorcery
A:SP$ Pump | Cost$ 2 R | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 3 | RememberTargets$ True | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Up to three target creatures can't block this turn. Destroy any of them that are Walls.
SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Wall.IsRemembered | SubAbility$ DBCleanup
A:SP$ Pump | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 3 | RememberTargets$ True | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True | TgtPrompt$ Select up to three target creatures | SubAbility$ DBDestroy | StackDescription$ REP Up to three target creatures_{c:Targeted} | SpellDescription$ Up to three target creatures can't block this turn.
SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Wall.IsRemembered | SubAbility$ DBCleanup | StackDescription$ SpellDescription | SpellDescription$ Destroy any of them that are Walls.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:Up to three target creatures can't block this turn. Destroy any of them that are Walls.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ Remembered$Amount/Plus.1 | SubAb
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You.descended | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ At the beginning of your end step, if you descended this turn, put a bore counter on CARDNAME. Then if there are three or more bore counters on it, remove those counters and transform it. (You descended if a permanent card was put into your graveyard from anywhere.)
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ BORE | SubAbility$ DBBranch
SVar:DBBranch:DB$ Branch | BranchConditionSVar$ Count$Valid Count$CardCounters.BORE | BranchConditionSVarCompare$ GE3 | TrueSubAbility$ DBRemoveCounter
SVar:DBBranch:DB$ Branch | BranchConditionSVar$ Count$CardCounters.BORE | BranchConditionSVarCompare$ GE3 | TrueSubAbility$ DBRemoveCounter
SVar:DBRemoveCounter:DB$ RemoveCounter | CounterType$ BORE | CounterNum$ All | SubAbility$ DBTransform
SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform
AlternateMode:DoubleFaced
Expand All @@ -21,5 +21,4 @@ Types:Legendary Land Cave
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R}.
T:Mode$ SpellCast | ValidCard$ Permanent | ValidSA$ Spell.ManaFromCard.StrictlySelf | ValidActivatingPlayer$ You | Execute$ TrigDiscover | TriggerDescription$ Whenever you cast a permanent spell using mana produced by CARDNAME, discover X, where X is that spell's mana value.
SVar:TrigDiscover:DB$ Discover | Num$ TriggeredStackInstance$CardManaCostLKI
SVar:X:TriggeredCard$CardToughness
Oracle:(Transforms from Brass's Tunnel-Grinder.)\n{T}: Add {R}.\nWhenever you cast a permanent spell using mana produced by Tecutlan, the Searing Rift, discover X, where X is that spell's mana value.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/upcoming/caparocti_sunborn.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Name:Caparocti Sunborn
ManaCost:2 R W
Types:Legendary Creature Human Soldier
PT:4/4
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDiscover | TriggerDescription$ Whenever CARDNAME attacks, you may tap two other untapped creatures you control. If you do, discover 3. (Exile cards from the top of your library until you exile a nonland card with mana value 3 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDiscover | TriggerDescription$ Whenever CARDNAME attacks, you may tap two untapped artifacts and/or creatures you control. If you do, discover 3. (Exile cards from the top of your library until you exile a nonland card with mana value 3 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
SVar:TrigDiscover:AB$ Discover | Cost$ tapXType<2/Artifact;Creature/artifacts and/or creatures> | Num$ 3
DeckHints:Type$Artifact|Token
Oracle:Whenever Caparocti Sunborn attacks, you may tap two untapped artifacts and/or creatures you control. If you do, discover 3. (Exile cards from the top of your library until you exile a nonland card with mana value 3 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
8 changes: 8 additions & 0 deletions forge-gui/res/cardsfolder/upcoming/contest_of_claws.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Name:Contest of Claws
ManaCost:1 G
Types:Sorcery
A:SP$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SubAbility$ DBDamage | AILogic$ PowerDmg | StackDescription$ {c:ThisTargetedCard} | SpellDescription$ Target creature you control
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select another target creature | TargetUnique$ True | AILogic$ PowerDmg | NumDmg$ X | DamageSource$ ParentTarget | ExcessSVar$ Excess | SubAbility$ DBDiscover | StackDescription$ REP another target creature_{c:ThisTargetedCard} | SpellDescription$ deals damage equal to its power to another target creature.
SVar:DBDiscover:DB$ Discover | Num$ Excess | StackDescription$ SpellDescription | SpellDescription$ If excess damage was dealt this way, discover X, where X is that excess damage. (Exile cards from the top of your library until you exile a nonland card with that mana value or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
SVar:X:ParentTargeted$CardPower
Oracle:Target creature you control deals damage equal to its power to another target creature. If excess damage was dealt this way, discover X, where X is that excess damage. (Exile cards from the top of your library until you exile a nonland card with that mana value or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
6 changes: 6 additions & 0 deletions forge-gui/res/cardsfolder/upcoming/daring_discovery.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Name:Daring Discovery
ManaCost:4 R
Types:Sorcery
A:SP$ Pump | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 3 | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True | TgtPrompt$ Select up to three target creatures | SubAbility$ DBDiscover | StackDescription$ REP Up to three target creatures_{c:Targeted} | SpellDescription$ Up to three target creatures can't block this turn.
SVar:DBDiscover:DB$ Discover | Num$ 4 | SpellDescription$ Discover 4. (Exile cards from the top of your library until you exile a nonland card with mana value 4 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
Oracle:Up to three target creatures can't block this turn.\nDiscover 4. (Exile cards from the top of your library until you exile a nonland card with mana value 4 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
10 changes: 10 additions & 0 deletions forge-gui/res/cardsfolder/upcoming/dinosaur_egg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Name:Dinosaur Egg
ManaCost:1 G
Types:Creature Dinosaur Egg
PT:0/3
K:Evolve
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDiscover | OptionalDecider$ You | TriggerDescription$ When CARDNAME dies, you may discover X, where X is its toughness.
SVar:TrigDiscover:DB$ Discover | Num$ X
SVar:X:TriggeredCard$CardToughness
DeckHas:Ability$Counters
Oracle:Evolve (Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature.)\nWhen Dinosaur Egg dies, you may discover X, where X is its toughness.
9 changes: 9 additions & 0 deletions forge-gui/res/cardsfolder/upcoming/etalis_favor.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Name:Etali's Favor
ManaCost:2 R
Types:Enchantment Aura
K:Enchant creature you control
A:SP$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | AILogic$ Pump
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDiscover | TriggerDescription$ When CARDNAME enters the battlefield, discover 3. (Exile cards from the top of your library until you exile a nonland card with mana value 3 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
SVar:TrigDiscover:DB$ Discover | Num$ 3
S:Mode$ Continuous | Affected$ Card.EnchantedBy | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Trample | Description$ Enchanted creature gets +1/+1 and has trample.
Oracle:Enchant creature you control\nWhen Etali's Favor enters the battlefield, discover 3. (Exile cards from the top of your library until you exile a nonland card with mana value 3 or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)\nEnchanted creature gets +1/+1 and has trample.
Loading

0 comments on commit a80bb97

Please sign in to comment.