From 84a7b79e3c8498942bafe60424723b06c3e6a9a5 Mon Sep 17 00:00:00 2001 From: Hythonia Date: Tue, 11 May 2021 09:12:05 +0200 Subject: [PATCH] Add Time Sidewalk and Bone Rattler --- .../src/main/java/forge/ai/SpellApiToAi.java | 1 + .../main/java/forge/game/ability/ApiType.java | 1 + .../game/ability/effects/MakeCardEffect.java | 38 +++++++++++++++++++ .../src/main/java/forge/game/card/Card.java | 13 +++++++ .../java/forge/game/card/CardPredicates.java | 4 +- .../java/forge/game/card/CardProperty.java | 4 +- .../main/java/forge/game/card/CardView.java | 3 ++ .../forge/trackable/TrackableProperty.java | 1 + forge-gui/res/cardsfolder/b/bone_rattler.txt | 10 +++++ forge-gui/res/cardsfolder/t/time_sidewalk.txt | 9 +++++ .../java/forge/gui/card/CardDetailUtil.java | 2 + 11 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java create mode 100644 forge-gui/res/cardsfolder/b/bone_rattler.txt create mode 100644 forge-gui/res/cardsfolder/t/time_sidewalk.txt diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index c95593f5c71..ae17f988dc7 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -98,6 +98,7 @@ public enum SpellApiToAi { .put(ApiType.Learn, LearnAi.class) .put(ApiType.LoseLife, LifeLoseAi.class) .put(ApiType.LosesGame, GameLossAi.class) + .put(ApiType.MakeCard, AlwaysPlayAi.class) .put(ApiType.Mana, ManaEffectAi.class) .put(ApiType.ManaReflected, CannotPlayAi.class) .put(ApiType.Manifest, ManifestAi.class) 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 e540e28f6b1..c528e15ce83 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -97,6 +97,7 @@ public enum ApiType { LookAt (LookAtEffect.class), LoseLife (LifeLoseEffect.class), LosesGame (GameLossEffect.class), + MakeCard (MakeCardEffect.class), Mana (ManaEffect.class), ManaReflected (ManaReflectedEffect.class), Manifest (ManifestEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java new file mode 100644 index 00000000000..7da3ab8f3a6 --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java @@ -0,0 +1,38 @@ +package forge.game.ability.effects; + +import forge.StaticData; +import forge.game.Game; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.card.CardCollection; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.zone.ZoneType; + +public class MakeCardEffect extends SpellAbilityEffect { + @Override + public void resolve(SpellAbility sa) { + final Player player = sa.getActivatingPlayer(); + final Game game = player.getGame(); + + final String name = sa.hasParam("Name") ? sa.getParam("Name") : sa.getHostCard().getName(); + final ZoneType zone = ZoneType.smartValueOf(sa.getParamOrDefault("Zone", "Library")); + int amount = sa.hasParam("Amount") ? Integer.parseInt(sa.getParam("Amount")) : 1; + + CardCollection cards = new CardCollection(); + + while (amount > 0) { + Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), player); + if (!sa.hasParam("NotToken")) { card.setTokenCard(true); } + cards.add(card); + amount--; + } + + for (final Card c : cards) { + game.getAction().moveTo(zone, c, sa); + } + if (zone.equals(ZoneType.Library)) { + player.shuffle(sa); + } + } +} 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 50d0f287809..81b031e1a77 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -222,6 +222,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private boolean tapped = false; private boolean sickness = true; // summoning sickness private boolean token = false; + private boolean tokenCard = false; private Card copiedPermanent = null; private boolean copiedSpell = false; @@ -2921,6 +2922,18 @@ public class Card extends GameEntity implements Comparable, IHasSVars { view.updateToken(this); } + public final boolean isTokenCard() { + if (isInZone(ZoneType.Battlefield) && hasMergedCard()) { + return getTopMergedCard().tokenCard; + } + return tokenCard; + } + public final void setTokenCard(boolean tokenC) { + if (tokenCard = tokenC) { return; } + tokenCard = tokenC; + view.updateTokenCard(this); + } + public final Card getCopiedPermanent() { return copiedPermanent; } diff --git a/forge-game/src/main/java/forge/game/card/CardPredicates.java b/forge-game/src/main/java/forge/game/card/CardPredicates.java index 56c22dd1429..2c1232f649c 100644 --- a/forge-game/src/main/java/forge/game/card/CardPredicates.java +++ b/forge-game/src/main/java/forge/game/card/CardPredicates.java @@ -598,7 +598,7 @@ public final class CardPredicates { public static final Predicate NON_TOKEN = new Predicate() { @Override public boolean apply(Card c) { - return !c.isToken(); + return !(c.isToken() || c.isTokenCard()); } }; /** @@ -607,7 +607,7 @@ public final class CardPredicates { public static final Predicate TOKEN = new Predicate() { @Override public boolean apply(Card c) { - return c.isToken(); + return c.isToken() || c.isTokenCard(); } }; /** diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index 2990fdee53b..84f8163d7a4 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1359,11 +1359,11 @@ public class CardProperty { return false; } } else if (property.startsWith("token")) { - if (!card.isToken()) { + if (!card.isToken() && !card.isTokenCard()) { return false; } } else if (property.startsWith("nonToken")) { - if (card.isToken()) { + if (card.isToken() || card.isTokenCard()) { return false; } } else if (property.startsWith("copiedSpell")) { diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index aa0a182e7bd..2562e980e9f 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -233,6 +233,9 @@ public class CardView extends GameEntityView { set(TrackableProperty.Token, c.isToken()); } + public boolean isTokenCard() { return get(TrackableProperty.TokenCard); } + void updateTokenCard(Card c) { set(TrackableProperty.TokenCard, c.isTokenCard()); } + public boolean isCommander() { return get(TrackableProperty.IsCommander); } diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 86f11dde61a..ab5db9e2836 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -47,6 +47,7 @@ public enum TrackableProperty { Sickness(TrackableTypes.BooleanType), Tapped(TrackableTypes.BooleanType), Token(TrackableTypes.BooleanType), + TokenCard(TrackableTypes.BooleanType), IsCommander(TrackableTypes.BooleanType), CommanderAltType(TrackableTypes.StringType), Damage(TrackableTypes.IntegerType), diff --git a/forge-gui/res/cardsfolder/b/bone_rattler.txt b/forge-gui/res/cardsfolder/b/bone_rattler.txt new file mode 100644 index 00000000000..034076898ac --- /dev/null +++ b/forge-gui/res/cardsfolder/b/bone_rattler.txt @@ -0,0 +1,10 @@ +Name:Bone Rattler +ManaCost:3 B B +Types:Creature Skeleton +PT:4/4 +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Graveyard | Execute$ TrigExile | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, exile it. If you do, create four Reassembling Skeleton token cards and put them into your graveyard. +SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ DBMakeCard +SVar:DBMakeCard:DB$ MakeCard | Name$ Reassembling Skeleton | Zone$ Graveyard | Amount$ 4 | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Card.Self | ConditionCompare$ GE1 +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +DeckHas:Ability$Graveyard +Oracle:When Bone Rattler is put into a graveyard from anywhere, exile it. If you do, create four Reassembling Skeleton token cards and put them into your graveyard. diff --git a/forge-gui/res/cardsfolder/t/time_sidewalk.txt b/forge-gui/res/cardsfolder/t/time_sidewalk.txt new file mode 100644 index 00000000000..1cf808dc2a0 --- /dev/null +++ b/forge-gui/res/cardsfolder/t/time_sidewalk.txt @@ -0,0 +1,9 @@ +Name:Time Sidewalk +ManaCost:4 U U U U +Types:Sorcery +K:MayEffectFromOpeningHand:ExileCard +A:SP$ AddTurn | Cost$ 4 U U U U | NumTurns$ 1 | SpellDescription$ Take an extra turn after this one. +SVar:ExileCard:DB$ ChangeZone | Defined$ Self | Origin$ Hand | Destination$ Exile | RememberChanged$ True | SubAbility$ DBMakeCard | SpellDescription$ If this card is in your opening hand, you may exile it. If you do, create four Time Walk token cards and shuffle them into your deck. +SVar:DBMakeCard:DB$ MakeCard | Name$ Time Walk | Amount$ 4 | Zone$ Library | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Card.Self | ConditionCompare$ GE1 +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +Oracle:Take an extra turn after this one.\nIf this card is in your opening hand, you may exile it. If you do, create four Time Walk token cards and shuffle them into your deck. diff --git a/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java index 2e81bd8720e..1d3df5bad43 100644 --- a/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java @@ -280,6 +280,8 @@ public class CardDetailUtil { area.append("Emblem"); else area.append("Token"); + } else if (card.isTokenCard()) { + area.append("Token card"); } // card text