From 06801023b507923ed3e97fc060c8897ea7ed3afc Mon Sep 17 00:00:00 2001 From: Sol Date: Fri, 2 Jan 2015 22:48:47 +0000 Subject: [PATCH] - Adding Manifest effect --- .gitattributes | 1 + .../main/java/forge/game/ability/ApiType.java | 1 + .../game/ability/effects/ManifestEffect.java | 50 ++++++++++++++++ .../effects/RearrangeTopOfLibraryEffect.java | 15 +---- .../src/main/java/forge/game/card/Card.java | 58 ++++++++++++++++++- .../java/forge/game/card/CardFactoryUtil.java | 41 +++++++++++++ .../main/java/forge/game/player/Player.java | 15 +++++ 7 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java diff --git a/.gitattributes b/.gitattributes index eff21f7ffd0..97955e15309 100644 --- a/.gitattributes +++ b/.gitattributes @@ -387,6 +387,7 @@ forge-game/src/main/java/forge/game/ability/effects/LifeSetEffect.java -text forge-game/src/main/java/forge/game/ability/effects/LookAtEffect.java -text forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java -text forge-game/src/main/java/forge/game/ability/effects/ManaReflectedEffect.java -text +forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java -text forge-game/src/main/java/forge/game/ability/effects/MillEffect.java -text forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java -text forge-game/src/main/java/forge/game/ability/effects/MustAttackEffect.java -text diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 3c3d00a4827..7d73237ba8d 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -77,6 +77,7 @@ public enum ApiType { LosesGame (GameLossEffect.class), Mana (ManaEffect.class), ManaReflected (ManaReflectedEffect.class), + Manifest (ManifestEffect.class), Mill (MillEffect.class), MoveCounter (CountersMoveEffect.class), MultiplePiles (MultiplePilesEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java new file mode 100644 index 00000000000..ff62e4e1a2a --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java @@ -0,0 +1,50 @@ +package forge.game.ability.effects; + +import forge.card.CardStateName; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.card.CardCollection; +import forge.game.card.CardCollectionView; +import forge.game.card.CardLists; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.spellability.TargetRestrictions; +import forge.game.zone.ZoneType; + +import java.util.List; + +public class ManifestEffect extends SpellAbilityEffect { + @Override + public void resolve(SpellAbility sa) { + final Card source = sa.getHostCard(); + // Usually a number leaving possibility for X, Sacrifice X land: Manifest X creatures. + final int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(sa.getHostCard(), + sa.getParam("Amount"), sa) : 1; + // Most commonly "defined" is Top of Library + final String defined = sa.hasParam("Defined") ? sa.getParam("Defined") : "TopOfLibrary"; + + final TargetRestrictions tgt = sa.getTargetRestrictions(); + for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) { + if ((tgt == null) || p.canBeTargetedBy(sa)) { + CardCollection tgtCards; + if ("TopOfLibrary".equals(defined)) { + tgtCards = p.getTopXCardsFromLibrary(amount); + } else { + tgtCards = getTargetCards(sa); + } + + if (sa.hasParam("Shuffle")) { + CardLists.shuffle(tgtCards); + } + + for(Card c : tgtCards) { + Card rem = c.manifest(p); + if (sa.hasParam("RememberManifested") && rem != null) { + source.addRemembered(rem); + } + } + } + } + } +} diff --git a/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java index 34edef496ff..22214a8b49c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java @@ -109,18 +109,9 @@ public class RearrangeTopOfLibraryEffect extends SpellAbilityEffect { if (activator == null) { return; } - final PlayerZone lib = player.getZone(ZoneType.Library); - int maxCards = lib.size(); - // If library is smaller than N, only show that many cards - maxCards = Math.min(maxCards, numCards); - if (maxCards == 0) { - return; - } - final CardCollection topCards = new CardCollection(); - // show top n cards: - for (int j = 0; j < maxCards; j++) { - topCards.add(lib.get(j)); - } + + CardCollection topCards = player.getTopXCardsFromLibrary(numCards); + int maxCards = topCards.size(); CardCollectionView orderedCards = activator.getController().orderMoveToZoneList(topCards, ZoneType.Library); for (int i = maxCards - 1; i >= 0; i--) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 3e24491940b..83973637937 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -162,6 +162,8 @@ public class Card extends GameEntity implements Comparable { private boolean monstrous = false; private int monstrosityNum = 0; + private boolean manifested = false; + private long bestowTimestamp = -1; private boolean suspendCast = false; private boolean suspend = false; @@ -334,6 +336,7 @@ public class Card extends GameEntity implements Comparable { } public boolean setState(final CardStateName state, boolean updateView) { if (state == CardStateName.FaceDown && isDoubleFaced()) { + // TODO I believe No longer true with Manifest, needs to be tested out return false; // Doublefaced cards can't be turned face-down. } @@ -346,6 +349,11 @@ public class Card extends GameEntity implements Comparable { return false; } + // Cleared tests, about to change states + if (currentStateName.equals(CardStateName.FaceDown) && state.equals(CardStateName.Original)) { + this.setManifested(false); + } + currentStateName = state; currentState = states.get(state); @@ -404,16 +412,52 @@ public class Card extends GameEntity implements Comparable { preFaceDownState = preCharacteristic; } + public Card manifest(Player p) { + // Turn Face Down (even if it's DFC). + ManaCost cost = this.getManaCost(); + + // Sometimes cards are manifested while already being face down + if (!turnFaceDown(true) && currentStateName != CardStateName.FaceDown) { + return null; + } + // Move to p's battlefield + Card c = p.getGame().getAction().moveToPlay(this, p); + c.setPreFaceDownState(CardStateName.Original); + // Mark this card as "manifested" + c.setManifested(true); + + // Add manifest demorph static ability for creatures? + c.addSpellAbility(CardFactoryUtil.abilityManifestFaceUp(c, cost)); + + return c; + } + public boolean turnFaceDown() { - if (!isDoubleFaced()) { + return turnFaceDown(false); + } + + public boolean turnFaceDown(boolean override) { + if (override || !isDoubleFaced()) { preFaceDownState = currentStateName; return setState(CardStateName.FaceDown, true); } return false; } - public boolean turnFaceUp() { + public boolean turnFaceUp() { + return turnFaceUp(false); + } + + public boolean turnFaceUp(boolean manifestPaid) { if (currentStateName == CardStateName.FaceDown) { + if (manifestPaid && this.isManifested() && !this.getRules().getType().isCreature()) { + // If we've manifested a non-creature and we're demanifesting disallow it + + // Unless this creature also has a Morph ability + + return false; + } + boolean result = setState(preFaceDownState, true); if (result) { getGame().getTriggerHandler().registerActiveTrigger(this, false); @@ -1544,6 +1588,9 @@ public class Card extends GameEntity implements Comparable { if (monstrous) { sb.append("Monstrous\r\n"); } + if (manifested) { + sb.append("Manifested\r\n"); + } sb.append(keywordsToText(getUnhiddenKeywords(state))); // Give spellText line breaks for easier reading @@ -5672,6 +5719,13 @@ public class Card extends GameEntity implements Comparable { monstrosityNum = num; } + public final boolean isManifested() { + return manifested; + } + public final void setManifested(final boolean manifested) { + this.manifested = manifested; + } + public final void animateBestow() { bestowTimestamp = getGame().getNextTimestamp(); addChangedCardTypes(new CardType(Arrays.asList("Aura")), diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index d1ad46dec38..551fc242af4 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -166,6 +166,47 @@ public class CardFactoryUtil { return morphUp; } + public static AbilityStatic abilityManifestFaceUp(final Card sourceCard, final ManaCost manaCost) { + final Cost cost = new Cost(manaCost, false); + + final AbilityStatic manifestUp = new AbilityStatic(sourceCard, cost, null) { + + @Override + public void resolve() { + if (sourceCard.turnFaceUp(true)) { + String sb = this.getActivatingPlayer() + " has unmanifested " + sourceCard.getName(); + sourceCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb); + sourceCard.getGame().fireEvent(new GameEventCardStatsChanged(sourceCard)); + } + } + + @Override + public boolean canPlay() { + return sourceCard.getController().equals(this.getActivatingPlayer()) && sourceCard.isFaceDown() + && sourceCard.isInPlay() && sourceCard.isManifested(); + } + + }; // morph_up + + String costDesc = cost.toString(); + // get rid of the ": " at the end + costDesc = costDesc.substring(0, costDesc.length() - 2); + final StringBuilder sb = new StringBuilder(); + sb.append("Unmanifest"); + if (!cost.isOnlyManaCost()) { + sb.append(" -"); + } + sb.append(" ").append(costDesc).append(" (Turn this face up any time for its mana cost.)"); + manifestUp.setDescription(sb.toString()); + + final StringBuilder sbStack = new StringBuilder(); + sbStack.append(sourceCard.getName()).append(" - turn this card face up."); + manifestUp.setStackDescription(sbStack.toString()); + //manifestUp.setIsMorphUp(true); + + return manifestUp; + } + public static boolean handleHiddenAgenda(Player player, Card card) { SpellAbility sa = new SpellAbility.EmptySa(card); sa.getMapParams().put("AILogic", card.getSVar("AgendaLogic")); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index d52bd9e4f23..1a0ad6961e7 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1330,6 +1330,21 @@ public class Player extends GameEntity implements Comparable { return milled; } + public final CardCollection getTopXCardsFromLibrary(int amount) { + final CardCollection topCards = new CardCollection(); + final PlayerZone lib = this.getZone(ZoneType.Library); + int maxCards = lib.size(); + // If library is smaller than N, only get that many cards + maxCards = Math.min(maxCards, amount); + + // show top n cards: + for (int j = 0; j < maxCards; j++) { + topCards.add(lib.get(j)); + } + + return topCards; + } + public final void shuffle(final SpellAbility sa) { final CardCollection list = new CardCollection(getCardsIn(ZoneType.Library));