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 f3323a8b814..7f8ef748e2f 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1388,6 +1388,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final boolean hasDoubleStrike() { return hasKeyword(Keyword.DOUBLE_STRIKE); } + + public final boolean hasDoubleTeam() { + return hasKeyword(Keyword.DOUBLE_TEAM); + } public final boolean hasSecondStrike() { return hasDoubleStrike() || !hasFirstStrike(); 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 cb3ef24e228..25bcd2abb76 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1063,6 +1063,22 @@ public class CardFactoryUtil { dethroneTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card)); inst.addTrigger(dethroneTrigger); + } else if (keyword.equals("Double Team")) { + final String doubleteamScript = "Mode$ Attacks | ValidCard$ Card.Self+nonToken | TriggerZones$ Battlefield | TriggerDescription$ (" + inst.getReminderText() + ")"; + final String makeString = "DB$ MakeCard | DefinedName$ Self | Zone$ Hand | RememberMade$ True"; + final String forgetString = "DB$ Effect | Duration$ Permanent | RememberObjects$ Remembered | ImprintCards$ TriggeredAttacker | StaticAbilities$ RemoveDoubleTeamMade"; + final String madeforgetmadeString = "Mode$ Continuous | EffectZone$ Command | Affected$ Card.IsRemembered,Card.IsImprinted | RemoveKeyword$ Double Team | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ Both cards perpetually lose double team."; + final String CleanupString = "DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True"; + final Trigger trigger = TriggerHandler.parseTrigger(doubleteamScript, card, intrinsic); + final SpellAbility youMake = AbilityFactory.getAbility(makeString, card); + final AbilitySub forget = (AbilitySub) AbilityFactory.getAbility(forgetString, card); + final AbilitySub Cleanup = (AbilitySub) AbilityFactory.getAbility(CleanupString, card); + forget.setSVar("RemoveDoubleTeamMade",madeforgetmadeString); + youMake.setSubAbility(forget); + forget.setSubAbility(Cleanup); + trigger.setOverridingAbility(youMake); + + inst.addTrigger(trigger); } else if (keyword.startsWith("Echo")) { final String[] k = keyword.split(":"); final String cost = k[1]; 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 352ced47d8c..a176696afcd 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -1364,6 +1364,7 @@ public class CardView extends GameEntityView { public boolean hasDefender() { return get(TrackableProperty.HasDefender); } public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); } public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); } + public boolean hasDoubleTeam() { return get(TrackableProperty.HasDoubleTeam); } public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); } public boolean hasFlying() { return get(TrackableProperty.HasFlying); } public boolean hasFear() { return get(TrackableProperty.HasFear); } diff --git a/forge-game/src/main/java/forge/game/keyword/Keyword.java b/forge-game/src/main/java/forge/game/keyword/Keyword.java index e293c449d2d..fc31d2c3a8e 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -60,6 +60,7 @@ public enum Keyword { DEVOID("Devoid", SimpleKeyword.class, true, "This card has no color."), DISTURB("Disturb", KeywordWithCost.class, false, "You may cast this card from your graveyard transformed for its disturb cost."), DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."), + DOUBLE_TEAM("Double Team", SimpleKeyword.class, true, "When this creature attacks, if it's not a token, conjure a duplicate of it into your hand. Then both cards perpetually lose double team."), DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."), ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."), EMBALM("Embalm", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Create a token that's a copy of this card, except it's white, it has no mana cost, and it's a Zombie in addition to its other types. Embalm only as a sorcery."), diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 62dbe8e9b96..c97649b0c1e 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -138,6 +138,7 @@ public enum TrackableProperty { HasDefender(TrackableTypes.BooleanType), HasDivideDamage(TrackableTypes.BooleanType), HasDoubleStrike(TrackableTypes.BooleanType), + HasDoubleTeam(TrackableTypes.BooleanType), HasFirstStrike(TrackableTypes.BooleanType), HasFlying(TrackableTypes.BooleanType), HasFear(TrackableTypes.BooleanType), diff --git a/forge-gui/res/cardsfolder/upcoming/genasi_rabble_rouser.txt b/forge-gui/res/cardsfolder/upcoming/genasi_rabble_rouser.txt new file mode 100644 index 00000000000..48cc67b15e2 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/genasi_rabble_rouser.txt @@ -0,0 +1,7 @@ +Name:Genasi Rabble-Rouser +ManaCost:1 R +Types:Creature Elemental Shaman +K:Double Team +A:AB$ PumpAll | Cost$ 1 R | ValidCards$ Creature.YouCtrl+namedGenasi Rabble-Rouser | NumAtt$ +1 | SpellDescription$ Creatures you control named Genasi Rabble-Rouser get +1/+0 until end of turn. +DeckHints:Name$Genasi Rabble-Rouser +Oracle:Double team\n{1}{R}: Creatures you control named Genasi Rabble-Rouser gets +1/+0 until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/giant_fire_beetles.txt b/forge-gui/res/cardsfolder/upcoming/giant_fire_beetles.txt new file mode 100644 index 00000000000..360556ffa46 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/giant_fire_beetles.txt @@ -0,0 +1,7 @@ +Name:Giant Fire Beetles +ManaCost:2 R +Types:Creature Insect +PT:2/2 +K:Double Team +K:Menace +Oracle:Menace\nDouble team diff --git a/forge-gui/res/cardsfolder/upcoming/gnoll_hunting_party.txt b/forge-gui/res/cardsfolder/upcoming/gnoll_hunting_party.txt new file mode 100644 index 00000000000..d194a5492a3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/gnoll_hunting_party.txt @@ -0,0 +1,10 @@ +Name:Gnoll Hunting Party +ManaCost:5 R +Types:Creature Gnoll +PT:5/5 +S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each creature you attacked with this turn. +S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has first strike. +SVar:X:Count$AttackersDeclared +K:Double Team +SVar:PlayMain2:TRUE +Oracle:This spell costs {1} less to cast for each creature you attacked with this turn.\nDouble team\nAs long as it's your turn, Gnoll Hunting Party has first strike. diff --git a/forge-gui/res/cardsfolder/upcoming/lizardfolk_librarians.txt b/forge-gui/res/cardsfolder/upcoming/lizardfolk_librarians.txt new file mode 100644 index 00000000000..9b4f7f01c87 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/lizardfolk_librarians.txt @@ -0,0 +1,8 @@ +Name:Lizardfolk Librarians +ManaCost:3 U +Types:Creature Lizard +PT:2/1 +K:Double Team +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigScry | TriggerDescription$ When CARDNAME enters the battlefield, scry 2. +SVar:TrigScry:DB$ Scry | ScryNum$ 2 +Oracle:Double team\When Lizardfolk Librarians enters the battlefield, scry 2. diff --git a/forge-gui/res/cardsfolder/upcoming/moradins_disciples.txt b/forge-gui/res/cardsfolder/upcoming/moradins_disciples.txt new file mode 100644 index 00000000000..afe342d5d8a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/moradins_disciples.txt @@ -0,0 +1,8 @@ +Name:Moradin's Disciples +ManaCost:3 W +Types:Creature Dwarf Cleric +PT:2/3 +K:Double Team +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBTap | TriggerDescription$ Whenever CARDNAME attacks, tap target creature defending player controls. +SVar:DBTap:DB$ Tap | ValidTgts$ Creature | TargetsWithDefinedController$ TriggeredDefendingPlayer | TargetMax$ 1 | TgtPrompt$ Select target creature defending player controls +Oracle:Double team\nWhenever Moradin's Disciples attacks, tap target creature defending player controls. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/ranger_squadron.txt b/forge-gui/res/cardsfolder/upcoming/ranger_squadron.txt new file mode 100644 index 00000000000..108e500babb --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/ranger_squadron.txt @@ -0,0 +1,7 @@ +Name:Ranger Squadron +ManaCost:4 W W +Types:Creature Cat Ranger +PT:3/4 +K:Flying +K:Double Team +Oracle:Flying\nDouble Team \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/seatower_imprisonment.txt b/forge-gui/res/cardsfolder/upcoming/seatower_imprisonment.txt new file mode 100644 index 00000000000..c49cb221f5a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/seatower_imprisonment.txt @@ -0,0 +1,9 @@ +Name:Seatower Imprisonment +ManaCost:2 W W +Types:Enchantment Aura +K:Enchant creature or planeswalker you don't control +A:SP$ Attach | ValidTgts$ Creature.YouDontCtrl,Planeswalker.YouDontCtrl | AILogic$ Curse +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigConjure | TriggerDescription$ When CARDNAME enters the battlefield, conjure a card named Soldiers of the Watch onto the battlefield. +SVar:TrigConjure:DB$ MakeCard | Name$ Soldiers of the Watch | Zone$ Battlefield +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddHiddenKeyword$ CARDNAME can't attack or block. & CARDNAME's activated abilities can't be activated. | Description$ Enchanted permanent can't attack or block and its activated abilities can't be activated. +Oracle:Enchant creature or planeswalker you don't control\nWhen Seatower Imprisonment enters the battlefield, conjure a card named Soldiers of the Watch onto the battlefield.\nEnchanted permanent can't attack or block and its activated abilities can't be activated. diff --git a/forge-gui/res/cardsfolder/upcoming/soldiers_of_the_watch.txt b/forge-gui/res/cardsfolder/upcoming/soldiers_of_the_watch.txt new file mode 100644 index 00000000000..7ffb9277231 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/soldiers_of_the_watch.txt @@ -0,0 +1,6 @@ +Name:Soldiers of the Watch +ManaCost:1 W +Types:Creature Human Soldier +PT:2/1 +K:Double Team +Oracle:Double Team \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/sworn_to_the_legion.txt b/forge-gui/res/cardsfolder/upcoming/sworn_to_the_legion.txt new file mode 100644 index 00000000000..a7cd72cd301 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/sworn_to_the_legion.txt @@ -0,0 +1,11 @@ +Name:Sworn to the Legion +ManaCost:4 W W +Types:Enchantment +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ DBEffect | TriggerDescription$ When CARDNAME enters the battlefield, nontoken creatures you control perpetually gain double team. +SVar:DBEffect:DB$ Effect | RememberObjects$ Valid Creature.YouCtrl+nonToken | StaticAbilities$ PerpetualDoubleTeam | Name$ Sworn to the Legion's Perpetual Effect | Duration$ Permanent +SVar:PerpetualDoubleTeam:Mode$ Continuous | Affected$ Card.IsRemembered | AddKeyword$ Double Team | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ Nontoken creatures you control perpetually gain double team. +T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ DBEffectCast | TriggerDescription$ Whenever you cast a creature spell, it perpetually gains double team. +SVar:DBEffectCast:DB$ Effect | RememberObjects$ TriggeredCard | StaticAbilities$ PerpetualDoubleTeamCast | Name$ Sworn to the Legion's Perpetual Effect | Duration$ Permanent +SVar:PerpetualDoubleTeamCast:Mode$ Continuous | Affected$ Card.IsRemembered | AddKeyword$ Double Team | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This creature perpetually gains double team. +SVar:BuffedBy:Creature +Oracle:When Sworn to the Legion enters the battlefield, nontoken creatures you control perpetually gain double team.\nWhenever you cast a creature spell, it perpetually gains double team. diff --git a/forge-gui/res/cardsfolder/upcoming/tiefling_outcasts.txt b/forge-gui/res/cardsfolder/upcoming/tiefling_outcasts.txt new file mode 100644 index 00000000000..3c0df1ec579 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tiefling_outcasts.txt @@ -0,0 +1,8 @@ +Name:Tiefling Outcasts +ManaCost:R +Types:Creature Tiefling Peasant +PT:1/1 +K:Double Team +S:Mode$ Continuous | Affected$ Demon.Other+YouCtrl,Devil.Other+YouCtrl,Imp.Other+YouCtrl,Tiefling.Other+YouCtrl | AddPower$ 1 | Description$ Other Demons, Devils, Imps, and Tieflings you control get +1/+0. +DeckHints:Type$Demon|Devil|Imp|Tiefling +Oracle:Double Team\nOther Demons, Devils, Imps, and Tieflings you control get +1/+0. diff --git a/forge-gui/res/cardsfolder/upcoming/ulder_ravengard_marshal.txt b/forge-gui/res/cardsfolder/upcoming/ulder_ravengard_marshal.txt new file mode 100644 index 00000000000..04128aee82d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/ulder_ravengard_marshal.txt @@ -0,0 +1,10 @@ +Name:Ulder Ravengard, Marshal +ManaCost:1 R W +Types:Legendary Creature Human Noble Soldier +PT:3/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPumpEOT | TriggerDescription$ When CARDNAME enters the battlefield, another target nontoken creature you control gains double team until end of turn. +SVar:TrigPumpEOT:DB$ Pump | ValidTgts$ Creature.YouCtrl+nonToken+Other | TgtPrompt$ Select another target nontoken creature you control | KW$ Double Team +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigConjure | TriggerDescription$ Whenever NICKNAME attacks, conjure a duplicate of another target nontoken attacking creature into your hand. +SVar:TrigConjure:DB$ MakeCard | ValidTgts$ Creature.attacking+Other+nonToken | TgtPrompt$ Select another target nontoken creature that is attacking | DefinedName$ Targeted | Zone$ Hand +SVar:HasAttackEffect:TRUE +Oracle:When Ulder Ravengard, Marshal enters the battlefield, another target nontoken creature you control gains double team until end of turn.\nWhenever Ulder Ravengard attacks, conjure a duplicate of another target nontoken attacking creature into your hand. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/warriors_of_tiamat.txt b/forge-gui/res/cardsfolder/upcoming/warriors_of_tiamat.txt new file mode 100644 index 00000000000..b3c0f03651f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/warriors_of_tiamat.txt @@ -0,0 +1,7 @@ +Name:Warriors of Tiamat +ManaCost:4 R +Types:Creature Dragon Warrior +PT:4/2 +K:Haste +K:Double Team +Oracle:Haste\nDouble Team \ No newline at end of file