mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 17:58:01 +00:00
Merge branch '1495-morph-x-costs-x-is-not-being-remembered' into 'master'
Resolve "Morph X costs - X is not being remembered" Closes #1496 and #1495 See merge request core-developers/forge!2969
This commit is contained in:
@@ -174,7 +174,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
if (!card.isFaceDown()) {
|
||||
transformed.turnFaceDown(true);
|
||||
} else {
|
||||
transformed.turnFaceUp(false, false);
|
||||
transformed.forceTurnFaceUp();
|
||||
}
|
||||
transformed.updateStateForView();
|
||||
return compareCards(card, transformed, ai, ph);
|
||||
|
||||
@@ -202,7 +202,7 @@ public class GameAction {
|
||||
// all sort of funky shenanigans may happen later (e.g. their ETB replacement effects are set
|
||||
// up on the wrong card state etc.).
|
||||
if (wasFacedown && (fromBattlefield || (toHand && zoneFrom.is(ZoneType.Exile)))) {
|
||||
c.turnFaceUp(false, false);
|
||||
c.forceTurnFaceUp();
|
||||
}
|
||||
|
||||
if (!c.isToken()) {
|
||||
@@ -264,7 +264,7 @@ public class GameAction {
|
||||
if (repres != ReplacementResult.NotReplaced) {
|
||||
// reset failed manifested Cards back to original
|
||||
if (c.isManifested() && !c.isInZone(ZoneType.Battlefield)) {
|
||||
c.turnFaceUp(false, false);
|
||||
c.forceTurnFaceUp();
|
||||
}
|
||||
|
||||
copied.getOwner().removeInboundToken(copied);
|
||||
@@ -431,7 +431,7 @@ public class GameAction {
|
||||
// rule 504.6: reveal a face-down card leaving the stack
|
||||
if (zoneFrom != null && zoneTo != null && zoneFrom.is(ZoneType.Stack) && !zoneTo.is(ZoneType.Battlefield) && wasFacedown) {
|
||||
Card revealLKI = CardUtil.getLKICopy(c);
|
||||
revealLKI.turnFaceUp(true, false);
|
||||
revealLKI.forceTurnFaceUp();
|
||||
reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card moves from the stack: ");
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ public class GameAction {
|
||||
// Reveal if face-down
|
||||
if (wasFacedown) {
|
||||
Card revealLKI = CardUtil.getLKICopy(c);
|
||||
revealLKI.turnFaceUp(true, false);
|
||||
revealLKI.forceTurnFaceUp();
|
||||
|
||||
reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card leaves the battlefield: ");
|
||||
|
||||
|
||||
@@ -1650,6 +1650,12 @@ public class AbilityUtils {
|
||||
return CardFactoryUtil.doXMath(0, expr, c);
|
||||
}
|
||||
return CardFactoryUtil.doXMath(cycleSA.getXManaCostPaid(), expr, c);
|
||||
} else if (TriggerType.TurnFaceUp.equals(t.getMode())) {
|
||||
SpellAbility turnupSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause);
|
||||
if (turnupSA == null || turnupSA.getXManaCostPaid() == null) {
|
||||
return CardFactoryUtil.doXMath(0, expr, c);
|
||||
}
|
||||
return CardFactoryUtil.doXMath(turnupSA.getXManaCostPaid(), expr, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +483,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
if (sa.hasParam("Transformed")) {
|
||||
if (tgtC.isDoubleFaced()) {
|
||||
tgtC.changeCardState("Transform", null);
|
||||
tgtC.changeCardState("Transform", null, sa);
|
||||
} else {
|
||||
// If it can't Transform, don't change zones.
|
||||
continue;
|
||||
@@ -1031,7 +1031,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
if (sa.hasParam("Transformed")) {
|
||||
if (c.isDoubleFaced()) {
|
||||
c.changeCardState("Transform", null);
|
||||
c.changeCardState("Transform", null, sa);
|
||||
} else {
|
||||
// If it can't Transform, don't change zones.
|
||||
continue;
|
||||
|
||||
@@ -19,8 +19,6 @@ import forge.util.Aggregates;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@@ -294,8 +292,7 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
continue; // for loop over players
|
||||
|
||||
if (sa.hasParam("RevealNumber")) {
|
||||
String amountString = sa.getParam("RevealNumber");
|
||||
int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
int amount = AbilityUtils.calculateAmount(source, sa.getParam("RevealNumber"), sa);
|
||||
dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
|
||||
final boolean wasFaceDown;
|
||||
if (tgtCard.isFaceDown()) {
|
||||
tgtCard.turnFaceUp(false, false);
|
||||
tgtCard.forceTurnFaceUp();
|
||||
wasFaceDown = true;
|
||||
} else {
|
||||
wasFaceDown = false;
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
if ("TurnFace".equals(mode) && tgt.isFaceDown() && tgt.isInZone(ZoneType.Battlefield)
|
||||
&& !tgt.getState(CardStateName.Original).getType().isPermanent()) {
|
||||
Card lki = CardUtil.getLKICopy(tgt);
|
||||
lki.turnFaceUp(true, false);
|
||||
lki.forceTurnFaceUp();
|
||||
game.getAction().reveal(new CardCollection(lki), lki.getOwner(), true, Localizer.getInstance().getMessage("lblFaceDownCardCantTurnFaceUp"));
|
||||
|
||||
continue;
|
||||
@@ -106,11 +106,11 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
|
||||
boolean hasTransformed = false;
|
||||
if (morphUp) {
|
||||
hasTransformed = tgt.turnFaceUp();
|
||||
hasTransformed = tgt.turnFaceUp(sa);
|
||||
} else if (manifestUp) {
|
||||
hasTransformed = tgt.turnFaceUp(true, true);
|
||||
hasTransformed = tgt.turnFaceUp(true, true, sa);
|
||||
} else {
|
||||
hasTransformed = tgt.changeCardState(mode, sa.getParam("NewState"));
|
||||
hasTransformed = tgt.changeCardState(mode, sa.getParam("NewState"), sa);
|
||||
}
|
||||
if ( hasTransformed ) {
|
||||
if (morphUp) {
|
||||
|
||||
@@ -549,7 +549,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
currentState.getView().updateType(currentState);
|
||||
}
|
||||
|
||||
public boolean changeCardState(final String mode, final String customState) {
|
||||
public boolean changeCardState(final String mode, final String customState, final SpellAbility cause) {
|
||||
if (mode == null)
|
||||
return changeToState(CardStateName.smartValueOf(customState));
|
||||
|
||||
@@ -597,7 +597,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (oldState == CardStateName.Original || oldState == CardStateName.Flipped) {
|
||||
return turnFaceDown();
|
||||
} else if (isFaceDown()) {
|
||||
return turnFaceUp();
|
||||
return turnFaceUp(cause);
|
||||
}
|
||||
} else if (mode.equals("Meld") && isMeldable()) {
|
||||
return changeToState(CardStateName.Meld);
|
||||
@@ -656,11 +656,11 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return setState(CardStateName.FaceDown, false);
|
||||
}
|
||||
|
||||
public boolean turnFaceUp() {
|
||||
return turnFaceUp(false, true);
|
||||
public boolean turnFaceUp(SpellAbility cause) {
|
||||
return turnFaceUp(false, true, cause);
|
||||
}
|
||||
|
||||
public boolean turnFaceUp(boolean manifestPaid, boolean runTriggers) {
|
||||
public boolean turnFaceUp(boolean manifestPaid, boolean runTriggers, SpellAbility cause) {
|
||||
if (isFaceDown()) {
|
||||
if (manifestPaid && isManifested() && !getRules().getType().isCreature()) {
|
||||
// If we've manifested a non-creature and we're demanifesting disallow it
|
||||
@@ -688,8 +688,11 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, AbilityKey.mapFromAffected(this));
|
||||
|
||||
// Run triggers
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
|
||||
runParams.put(AbilityKey.Cause, cause);
|
||||
|
||||
getGame().getTriggerHandler().registerActiveTrigger(this, false);
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, AbilityKey.mapFromCard(this), false);
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, runParams, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -6102,7 +6105,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (isFaceDown()) {
|
||||
lkicheck = true;
|
||||
source = CardUtil.getLKICopy(source);
|
||||
source.turnFaceUp(false, false);
|
||||
source.forceTurnFaceUp();
|
||||
}
|
||||
|
||||
if (lkicheck) {
|
||||
@@ -6315,7 +6318,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
|
||||
public void forceTurnFaceUp() {
|
||||
getGame().getTriggerHandler().suppressMode(TriggerType.TurnFaceUp);
|
||||
turnFaceUp(false, false);
|
||||
turnFaceUp(false, false, null);
|
||||
getGame().getTriggerHandler().clearSuppression(TriggerType.TurnFaceUp);
|
||||
}
|
||||
|
||||
|
||||
@@ -1772,7 +1772,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void playLandNoCheck(final Card land) {
|
||||
land.setController(this, 0);
|
||||
if (land.isFaceDown()) {
|
||||
land.turnFaceUp();
|
||||
land.turnFaceUp(null);
|
||||
}
|
||||
final Card c = game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null);
|
||||
game.updateLastStateForCard(c);
|
||||
|
||||
@@ -209,7 +209,7 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
|
||||
source = CardUtil.getLKICopy(source);
|
||||
}
|
||||
|
||||
source.turnFaceUp(false, false);
|
||||
source.forceTurnFaceUp();
|
||||
lkicheck = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class TriggerTurnFaceUp extends Trigger {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card);
|
||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -242,7 +242,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
if (spell.isCastFaceDown()) {
|
||||
source.turnFaceDown();
|
||||
} else if (source.isFaceDown()) {
|
||||
source.turnFaceUp();
|
||||
source.turnFaceUp(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
forge-gui/res/quest/precons/Basri, Devoted Paladin.dck
Normal file
29
forge-gui/res/quest/precons/Basri, Devoted Paladin.dck
Normal file
@@ -0,0 +1,29 @@
|
||||
[shop]
|
||||
WinsToUnlock=0
|
||||
Credits=1200
|
||||
MinDifficulty=0
|
||||
MaxDifficulty=5
|
||||
[metadata]
|
||||
Name=Basri, Devoted Paladin
|
||||
Description=Basri is a new planeswalker from the Egyptian themed plane Amonkhet. His deck plays a bunch of small creatures and buffs them with +1/+1 counters.
|
||||
Deck Type=constructed
|
||||
Set=M21
|
||||
Image=basri_devoted_paladin.jpg
|
||||
[Main]
|
||||
4 Adherent of Hope|M21
|
||||
3 Anointed Chorister|M21
|
||||
2 Aven Gagglemaster|M21
|
||||
2 Banishing Light|THB
|
||||
3 Basri's Acolyte|M21
|
||||
2 Basri's Aegis|M21
|
||||
1 Basri's Lieutenant|M21
|
||||
1 Basri, Devoted Paladin+|M21
|
||||
3 Fight as One|IKO
|
||||
4 Makeshift Battalion|WAR
|
||||
1 Perimeter Sergeant|IKO
|
||||
25 Plains|M21
|
||||
3 Sigiled Contender|M21
|
||||
1 Speaker of the Heavens|M21
|
||||
2 Swift Response|M21
|
||||
3 Tempered Veteran|M21
|
||||
[Sideboard]
|
||||
30
forge-gui/res/quest/precons/Chandra, Flames Catalyst.dck
Normal file
30
forge-gui/res/quest/precons/Chandra, Flames Catalyst.dck
Normal file
@@ -0,0 +1,30 @@
|
||||
[shop]
|
||||
WinsToUnlock=0
|
||||
Credits=1200
|
||||
MinDifficulty=0
|
||||
MaxDifficulty=5
|
||||
[metadata]
|
||||
Name=Chandra, Flame's Catalyst
|
||||
Description=As you can expect from Chandra, there’s a lot of burning going on in this deck. Burn your opponents, burn their creatures, and make you aggressive creatures grow while you’re at it.
|
||||
Deck Type=constructed
|
||||
Set=M21
|
||||
Image=chandra_flames_catalyst.jpg
|
||||
[Main]
|
||||
2 Blisterspit Gremlin|IKO
|
||||
2 Chandra's Firemaw|M21
|
||||
1 Chandra's Incinerator|M21
|
||||
3 Chandra's Pyreling|M21
|
||||
1 Chandra, Flame's Catalyst+|M21
|
||||
1 Double Vision|M21
|
||||
3 Heartfire Immolator|M21
|
||||
2 Infuriate|THB
|
||||
3 Keral Keep Disciples|M21
|
||||
25 Mountain|M21
|
||||
2 Pyroceratops|IKO
|
||||
3 Shock|M21
|
||||
2 Slaying Fire|ELD
|
||||
2 Spellgorger Weird|M21
|
||||
4 Storm Caller|M21
|
||||
2 Sure Strike|M21
|
||||
2 Unleash Fury|M21
|
||||
[Sideboard]
|
||||
29
forge-gui/res/quest/precons/Garruk, Savage Herald.dck
Normal file
29
forge-gui/res/quest/precons/Garruk, Savage Herald.dck
Normal file
@@ -0,0 +1,29 @@
|
||||
[shop]
|
||||
WinsToUnlock=0
|
||||
Credits=1200
|
||||
MinDifficulty=0
|
||||
MaxDifficulty=5
|
||||
[metadata]
|
||||
Name=Garruk, Savage Herald
|
||||
Description=Be Garruk. Play big creatures. Then play bigger creatures. Great deck for everyone who likes… you guessed it – big creatures.
|
||||
Deck Type=constructed
|
||||
Set=M21
|
||||
Image=garruk_savage_herald.jpg
|
||||
[Main]
|
||||
3 Almighty Brushwagg|IKO
|
||||
3 Drowsing Tyrannodon|M21
|
||||
25 Forest|M21
|
||||
1 Garruk's Harbinger|M21
|
||||
2 Garruk's Uprising|M21
|
||||
2 Garruk's Warsteed|M21
|
||||
1 Garruk, Savage Herald+|M21
|
||||
2 Ilysian Caryatid|THB
|
||||
3 Nessian Hornbeetle|THB
|
||||
2 Ornery Dilophosaur|M21
|
||||
3 Predatory Wurm|M21
|
||||
3 Pridemalkin|M21
|
||||
1 Primal Might|M21
|
||||
2 Ram Through|IKO
|
||||
3 Titanic Growth|M20
|
||||
4 Wildwood Patrol|M21
|
||||
[Sideboard]
|
||||
29
forge-gui/res/quest/precons/Liliana, Death Mage.dck
Normal file
29
forge-gui/res/quest/precons/Liliana, Death Mage.dck
Normal file
@@ -0,0 +1,29 @@
|
||||
[shop]
|
||||
WinsToUnlock=0
|
||||
Credits=1200
|
||||
MinDifficulty=0
|
||||
MaxDifficulty=5
|
||||
[metadata]
|
||||
Name=Liliana, Death Mage
|
||||
Description=The black deck cares about the graveyard. When your creatures die, you get all sorts of benefits. Then you can get them back from the grave with Liliana or with some other cards.
|
||||
Deck Type=constructed
|
||||
Set=M21
|
||||
Image=liliana_death_mage.jpg
|
||||
[Main]
|
||||
2 Alchemist's Gift|M21
|
||||
2 Bushmeat Poacher|IKO
|
||||
1 Demonic Embrace|M21
|
||||
3 Durable Coilbug|IKO
|
||||
2 Goremand|M21
|
||||
3 Grasp of Darkness|OGW
|
||||
3 Grim Physician|THB
|
||||
2 Liliana's Scorn|M21
|
||||
3 Liliana's Scrounger|M21
|
||||
1 Liliana's Standard Bearer|M21
|
||||
1 Liliana, Death Mage+|M21
|
||||
2 Lurking Deadeye|IKO
|
||||
4 Masked Blackguard|M21
|
||||
4 Spirit of Malevolence|M21
|
||||
25 Swamp|M21
|
||||
2 Unlikely Aid|IKO
|
||||
[Sideboard]
|
||||
30
forge-gui/res/quest/precons/Teferi, Timeless Voyager.dck
Normal file
30
forge-gui/res/quest/precons/Teferi, Timeless Voyager.dck
Normal file
@@ -0,0 +1,30 @@
|
||||
[shop]
|
||||
WinsToUnlock=0
|
||||
Credits=1200
|
||||
MinDifficulty=0
|
||||
MaxDifficulty=5
|
||||
[metadata]
|
||||
Name=Teferi, Timeless Voyager
|
||||
Description=Teferi’s deck does what blue decks do best – it draws tons of cards! Deck also contains a bunch of cards that synergize with card draw.
|
||||
Deck Type=constructed
|
||||
Set=M21
|
||||
Image=teferi_timeless_voyager.jpg
|
||||
[Main]
|
||||
2 Charmed Sleep|ELD
|
||||
3 Faerie Vandal|ELD
|
||||
4 Frantic Inventory|M21
|
||||
2 Gust of Wind|IKO
|
||||
3 Historian of Zhalfir|M21
|
||||
25 Island|M21
|
||||
2 Jeskai Elder|KTK
|
||||
2 Mantle of Tides|ELD
|
||||
4 Mystic Skyfish|M21
|
||||
3 Opt|ELD
|
||||
2 Shipwreck Dowser|M21
|
||||
1 Stern Dismissal|THB
|
||||
1 Stormwing Entity|M21
|
||||
1 Teferi's Ageless Insight|M21
|
||||
2 Teferi's Wavecaster|M21
|
||||
1 Teferi, Timeless Voyager|M21
|
||||
2 Tome Anima|M21
|
||||
[Sideboard]
|
||||
@@ -82,7 +82,7 @@ public class HumanPlay {
|
||||
}
|
||||
|
||||
if (flippedToCast && !castFaceDown) {
|
||||
source.turnFaceUp(false, false);
|
||||
source.forceTurnFaceUp();
|
||||
}
|
||||
|
||||
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
|
||||
|
||||
@@ -103,7 +103,7 @@ public class HumanPlaySpellAbility {
|
||||
// This is should happen earlier, before the Modal spell is chosen
|
||||
// Turn face-down card face up (except case of morph spell)
|
||||
if (ability.isSpell() && !ability.isCastFaceDown() && fromState == CardStateName.FaceDown) {
|
||||
c.turnFaceUp();
|
||||
c.turnFaceUp(null);
|
||||
}
|
||||
ability.setHostCard(game.getAction().moveToStack(c, ability));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user