mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
WIP: Implement Role mechanic (#10816)
* [WOE] Implement Embereth Veteran * add SBA for role tokens * [WOE] Implement Cursed Courtier * [WOE] Implement Conceited Witch * [WOE] Implement Besotted Knight * [WOE] Implement Syr Armont, the Redeemer * [WOE] Implement Living Lectern * add role test * [WOE] Implement Lord Skitter's Blessing * [WOE] Implement Faunsbane Troll * [WOE] Implement Twisted Fealty * [WOC] Implement Ellivere of the Wild Court * [WOE] Implement Monstrous Rage * [WOE] Implement Spellbook Vendor * add verify skips * extra fix
This commit is contained in:
parent
bf508aca9b
commit
b20bdcede7
28 changed files with 1230 additions and 6 deletions
41
Mage.Sets/src/mage/cards/b/BesottedKnight.java
Normal file
41
Mage.Sets/src/mage/cards/b/BesottedKnight.java
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.cards.AdventureCard;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class BesottedKnight extends AdventureCard {
|
||||
|
||||
public BesottedKnight(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{3}{W}", "Betroth the Beast", "{W}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Betroth the Beast
|
||||
// Create a Royal Role token attached to target creature you control.
|
||||
this.getSpellCard().getSpellAbility().addEffect(new CreateRoleAttachedTargetEffect(RoleType.ROYAL));
|
||||
this.getSpellCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
|
||||
}
|
||||
|
||||
private BesottedKnight(final BesottedKnight card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BesottedKnight copy() {
|
||||
return new BesottedKnight(this);
|
||||
}
|
||||
}
|
||||
45
Mage.Sets/src/mage/cards/c/ConceitedWitch.java
Normal file
45
Mage.Sets/src/mage/cards/c/ConceitedWitch.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.keyword.MenaceAbility;
|
||||
import mage.cards.AdventureCard;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class ConceitedWitch extends AdventureCard {
|
||||
|
||||
public ConceitedWitch(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{2}{B}", "Price of Beauty", "{B}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.WARLOCK);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Menace
|
||||
this.addAbility(new MenaceAbility());
|
||||
|
||||
// Price of Beauty
|
||||
// Create a Wicked Role token attached to target creature you control.
|
||||
this.getSpellCard().getSpellAbility().addEffect(new CreateRoleAttachedTargetEffect(RoleType.WICKED));
|
||||
this.getSpellCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
|
||||
}
|
||||
|
||||
private ConceitedWitch(final ConceitedWitch card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConceitedWitch copy() {
|
||||
return new ConceitedWitch(this);
|
||||
}
|
||||
}
|
||||
43
Mage.Sets/src/mage/cards/c/CursedCourtier.java
Normal file
43
Mage.Sets/src/mage/cards/c/CursedCourtier.java
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedSourceEffect;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class CursedCourtier extends CardImpl {
|
||||
|
||||
public CursedCourtier(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.NOBLE);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Lifelink
|
||||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// When Cursed Courtier enters the battlefield, create a Cursed Role token attached to it.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedSourceEffect(RoleType.CURSED)));
|
||||
}
|
||||
|
||||
private CursedCourtier(final CursedCourtier card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CursedCourtier copy() {
|
||||
return new CursedCourtier(this);
|
||||
}
|
||||
}
|
||||
61
Mage.Sets/src/mage/cards/e/EllivereOfTheWildCourt.java
Normal file
61
Mage.Sets/src/mage/cards/e/EllivereOfTheWildCourt.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.EnchantedPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class EllivereOfTheWildCourt extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter
|
||||
= new FilterControlledCreaturePermanent("an enchanted creature you control");
|
||||
|
||||
static {
|
||||
filter.add(EnchantedPredicate.instance);
|
||||
}
|
||||
|
||||
public EllivereOfTheWildCourt(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Whenever Ellivere of the Wild Court enters the battlefield or attacks, create a Virtuous Role token attached to another target creature you control.
|
||||
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateRoleAttachedTargetEffect(RoleType.VIRTUOUS));
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Whenever an enchanted creature you control deals combat damage to a player, draw a card.
|
||||
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
|
||||
new DrawCardSourceControllerEffect(1), filter,
|
||||
false, SetTargetPointer.NONE, true
|
||||
));
|
||||
}
|
||||
|
||||
private EllivereOfTheWildCourt(final EllivereOfTheWildCourt card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EllivereOfTheWildCourt copy() {
|
||||
return new EllivereOfTheWildCourt(this);
|
||||
}
|
||||
}
|
||||
49
Mage.Sets/src/mage/cards/e/EmberethVeteran.java
Normal file
49
Mage.Sets/src/mage/cards/e/EmberethVeteran.java
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class EmberethVeteran extends CardImpl {
|
||||
|
||||
public EmberethVeteran(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// {1}, Sacrifice Embereth Veteran: Create a Young Hero Role token attached to another target creature.
|
||||
Ability ability = new SimpleActivatedAbility(
|
||||
new CreateRoleAttachedTargetEffect(RoleType.YOUNG_HERO), new GenericManaCost(1)
|
||||
);
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private EmberethVeteran(final EmberethVeteran card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmberethVeteran copy() {
|
||||
return new EmberethVeteran(this);
|
||||
}
|
||||
}
|
||||
74
Mage.Sets/src/mage/cards/f/FaunsbaneTroll.java
Normal file
74
Mage.Sets/src/mage/cards/f/FaunsbaneTroll.java
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedSourceEffect;
|
||||
import mage.abilities.effects.common.ExileTargetIfDiesEffect;
|
||||
import mage.abilities.effects.common.FightTargetSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class FaunsbaneTroll extends CardImpl {
|
||||
|
||||
private static final FilterControlledPermanent filter
|
||||
= new FilterControlledPermanent(SubType.AURA, "an Aura attached to {this}");
|
||||
|
||||
static {
|
||||
filter.add(FaunsbaneTrollPredicate.instance);
|
||||
}
|
||||
|
||||
public FaunsbaneTroll(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}");
|
||||
|
||||
this.subtype.add(SubType.TROLL);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// When Faunsbane Troll enters the battlefield, create a Monster Role token attached to it.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedSourceEffect(RoleType.MONSTER)));
|
||||
|
||||
// {1}, Sacrifice an Aura attached to Faunsbane Troll: Faunsbane Troll fights target creature you don't control. If that creature would die this turn, exile it instead. Activate only as a sorcery.
|
||||
Ability ability = new ActivateAsSorceryActivatedAbility(new FightTargetSourceEffect(), new GenericManaCost(1));
|
||||
ability.addCost(new SacrificeTargetCost(filter));
|
||||
ability.addEffect(new ExileTargetIfDiesEffect());
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private FaunsbaneTroll(final FaunsbaneTroll card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaunsbaneTroll copy() {
|
||||
return new FaunsbaneTroll(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum FaunsbaneTrollPredicate implements ObjectSourcePlayerPredicate<Permanent> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
|
||||
return input.getSource().getSourceId().equals(input.getObject().getAttachedTo());
|
||||
}
|
||||
}
|
||||
52
Mage.Sets/src/mage/cards/l/LivingLectern.java
Normal file
52
Mage.Sets/src/mage/cards/l/LivingLectern.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package mage.cards.l;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class LivingLectern extends CardImpl {
|
||||
|
||||
public LivingLectern(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}");
|
||||
|
||||
this.subtype.add(SubType.CONSTRUCT);
|
||||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// {1}, Sacrifice Living Lectern: Draw a card. Create a Sorcerer Role token attached to up to one other target creature you control. Activate only as a sorcery.
|
||||
Ability ability = new ActivateAsSorceryActivatedAbility(
|
||||
new DrawCardSourceControllerEffect(1), new GenericManaCost(1)
|
||||
);
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
ability.addEffect(new CreateRoleAttachedTargetEffect(RoleType.SORCERER));
|
||||
ability.addTarget(new TargetPermanent(
|
||||
0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL
|
||||
));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private LivingLectern(final LivingLectern card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingLectern copy() {
|
||||
return new LivingLectern(this);
|
||||
}
|
||||
}
|
||||
67
Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java
Normal file
67
Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package mage.cards.l;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfDrawTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.EnchantedPredicate;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class LordSkittersBlessing extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterControlledCreaturePermanent();
|
||||
|
||||
static {
|
||||
filter.add(EnchantedPredicate.instance);
|
||||
}
|
||||
|
||||
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter);
|
||||
private static final Hint hint = new ConditionHint(condition, "You control an enchanted creaeture");
|
||||
|
||||
public LordSkittersBlessing(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
||||
|
||||
// When Lord Skitter's Blessing enters the battlefield, create a Wicked Role token attached to target creature you control.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedTargetEffect(RoleType.WICKED));
|
||||
ability.addTarget(new TargetControlledCreaturePermanent());
|
||||
this.addAbility(ability);
|
||||
|
||||
// At the beginning of your draw step, if you control an enchanted creature, you lose 1 life and you draw an additional card.
|
||||
ability = new ConditionalInterveningIfTriggeredAbility(
|
||||
new BeginningOfDrawTriggeredAbility(
|
||||
new LoseLifeSourceControllerEffect(1), TargetController.YOU, false
|
||||
), condition, "At the beginning of your draw step, if you control " +
|
||||
"an enchanted creature, you lose 1 life and you draw an additional card."
|
||||
);
|
||||
ability.addEffect(new DrawCardSourceControllerEffect(1));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private LordSkittersBlessing(final LordSkittersBlessing card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LordSkittersBlessing copy() {
|
||||
return new LordSkittersBlessing(this);
|
||||
}
|
||||
}
|
||||
35
Mage.Sets/src/mage/cards/m/MonstrousRage.java
Normal file
35
Mage.Sets/src/mage/cards/m/MonstrousRage.java
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class MonstrousRage extends CardImpl {
|
||||
|
||||
public MonstrousRage(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}");
|
||||
|
||||
// Target creature gets +2/+0 until end of turn. Create a Monster Role attached to it.
|
||||
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0));
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
this.getSpellAbility().addEffect(new CreateRoleAttachedTargetEffect(RoleType.MONSTER).setText("create a Monster Role attached to it"));
|
||||
}
|
||||
|
||||
private MonstrousRage(final MonstrousRage card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonstrousRage copy() {
|
||||
return new MonstrousRage(this);
|
||||
}
|
||||
}
|
||||
54
Mage.Sets/src/mage/cards/s/SpellbookVendor.java
Normal file
54
Mage.Sets/src/mage/cards/s/SpellbookVendor.java
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
|
||||
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.DoWhenCostPaid;
|
||||
import mage.abilities.keyword.VigilanceAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.RoleType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class SpellbookVendor extends CardImpl {
|
||||
|
||||
public SpellbookVendor(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.PEASANT);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Vigilance
|
||||
this.addAbility(VigilanceAbility.getInstance());
|
||||
|
||||
// At the beginning of combat on your turn, you may pay {1}. When you do, create a Sorcerer Role token attached to target creature you control.
|
||||
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
|
||||
new CreateRoleAttachedTargetEffect(RoleType.SORCERER), false
|
||||
);
|
||||
ability.addTarget(new TargetControlledCreaturePermanent());
|
||||
this.addAbility(new BeginningOfCombatTriggeredAbility(new DoWhenCostPaid(
|
||||
ability, new GenericManaCost(1), "Pay {1}?"
|
||||
), TargetController.YOU, false));
|
||||
}
|
||||
|
||||
private SpellbookVendor(final SpellbookVendor card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellbookVendor copy() {
|
||||
return new SpellbookVendor(this);
|
||||
}
|
||||
}
|
||||
58
Mage.Sets/src/mage/cards/s/SyrArmontTheRedeemer.java
Normal file
58
Mage.Sets/src/mage/cards/s/SyrArmontTheRedeemer.java
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.EnchantedPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class SyrArmontTheRedeemer extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("enchanted creatures");
|
||||
|
||||
static {
|
||||
filter.add(EnchantedPredicate.instance);
|
||||
}
|
||||
|
||||
public SyrArmontTheRedeemer(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// When Syr Armont, the Redeemer enters the battlefield, create a Monster Role token attached to another target creature you control.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedTargetEffect(RoleType.MONSTER));
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creatures you control get +1/+1.
|
||||
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
|
||||
1, 1, Duration.WhileOnBattlefield, filter
|
||||
)));
|
||||
}
|
||||
|
||||
private SyrArmontTheRedeemer(final SyrArmontTheRedeemer card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SyrArmontTheRedeemer copy() {
|
||||
return new SyrArmontTheRedeemer(this);
|
||||
}
|
||||
}
|
||||
48
Mage.Sets/src/mage/cards/t/TwistedFealty.java
Normal file
48
Mage.Sets/src/mage/cards/t/TwistedFealty.java
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import mage.abilities.effects.common.CreateRoleAttachedTargetEffect;
|
||||
import mage.abilities.effects.common.UntapTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.RoleType;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.targetpointer.SecondTargetPointer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class TwistedFealty extends CardImpl {
|
||||
|
||||
public TwistedFealty(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn.
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
|
||||
this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature"));
|
||||
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(
|
||||
HasteAbility.getInstance(), Duration.EndOfTurn
|
||||
).setText("It gains haste until end of turn."));
|
||||
|
||||
// Create a Wicked Role token attached to up to one target creature.
|
||||
this.getSpellAbility().addEffect(new CreateRoleAttachedTargetEffect(RoleType.WICKED)
|
||||
.setTargetPointer(new SecondTargetPointer()));
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1));
|
||||
}
|
||||
|
||||
private TwistedFealty(final TwistedFealty card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TwistedFealty copy() {
|
||||
return new TwistedFealty(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,12 +22,17 @@ public final class WildsOfEldraine extends ExpansionSet {
|
|||
|
||||
cards.add(new SetCardInfo("Ash, Party Crasher", 201, Rarity.UNCOMMON, mage.cards.a.AshPartyCrasher.class));
|
||||
cards.add(new SetCardInfo("Beanstalk Wurm", 161, Rarity.COMMON, mage.cards.b.BeanstalkWurm.class));
|
||||
cards.add(new SetCardInfo("Besotted Knight", 4, Rarity.COMMON, mage.cards.b.BesottedKnight.class));
|
||||
cards.add(new SetCardInfo("Break the Spell", 5, Rarity.COMMON, mage.cards.b.BreakTheSpell.class));
|
||||
cards.add(new SetCardInfo("Conceited Witch", 84, Rarity.COMMON, mage.cards.c.ConceitedWitch.class));
|
||||
cards.add(new SetCardInfo("Cruel Somnophage", 222, Rarity.RARE, mage.cards.c.CruelSomnophage.class));
|
||||
cards.add(new SetCardInfo("Cursed Courtier", 9, Rarity.UNCOMMON, mage.cards.c.CursedCourtier.class));
|
||||
cards.add(new SetCardInfo("Elvish Archivist", 168, Rarity.RARE, mage.cards.e.ElvishArchivist.class));
|
||||
cards.add(new SetCardInfo("Embereth Veteran", 127, Rarity.UNCOMMON, mage.cards.e.EmberethVeteran.class));
|
||||
cards.add(new SetCardInfo("Evolving Wilds", 256, Rarity.COMMON, mage.cards.e.EvolvingWilds.class));
|
||||
cards.add(new SetCardInfo("Faerie Dreamthief", 89, Rarity.UNCOMMON, mage.cards.f.FaerieDreamthief.class));
|
||||
cards.add(new SetCardInfo("Farsight Ritual", 49, Rarity.RARE, mage.cards.f.FarsightRitual.class));
|
||||
cards.add(new SetCardInfo("Faunsbane Troll", 203, Rarity.RARE, mage.cards.f.FaunsbaneTroll.class));
|
||||
cards.add(new SetCardInfo("Forest", 266, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Frolicking Familiar", 226, Rarity.UNCOMMON, mage.cards.f.FrolickingFamiliar.class));
|
||||
cards.add(new SetCardInfo("Gallant Pie-Wielder", 15, Rarity.UNCOMMON, mage.cards.g.GallantPieWielder.class));
|
||||
|
|
@ -35,7 +40,10 @@ public final class WildsOfEldraine extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Greta, Sweettooth Scourge", 205, Rarity.UNCOMMON, mage.cards.g.GretaSweettoothScourge.class));
|
||||
cards.add(new SetCardInfo("Island", 263, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Knight of Doves", 19, Rarity.UNCOMMON, mage.cards.k.KnightOfDoves.class));
|
||||
cards.add(new SetCardInfo("Living Lectern", 59, Rarity.COMMON, mage.cards.l.LivingLectern.class));
|
||||
cards.add(new SetCardInfo("Lord Skitter's Blessing", 98, Rarity.RARE, mage.cards.l.LordSkittersBlessing.class));
|
||||
cards.add(new SetCardInfo("Lord Skitter's Butcher", 99, Rarity.UNCOMMON, mage.cards.l.LordSkittersButcher.class));
|
||||
cards.add(new SetCardInfo("Monstrous Rage", 142, Rarity.UNCOMMON, mage.cards.m.MonstrousRage.class));
|
||||
cards.add(new SetCardInfo("Moonshaker Cavalry", 21, Rarity.MYTHIC, mage.cards.m.MoonshakerCavalry.class));
|
||||
cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Neva, Stalked by Nightmares", 209, Rarity.UNCOMMON, mage.cards.n.NevaStalkedByNightmares.class));
|
||||
|
|
@ -43,8 +51,8 @@ public final class WildsOfEldraine extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Plains", 262, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Rat Out", 103, Rarity.COMMON, mage.cards.r.RatOut.class));
|
||||
cards.add(new SetCardInfo("Ratcatcher Trainee", 144, Rarity.COMMON, mage.cards.r.RatcatcherTrainee.class));
|
||||
cards.add(new SetCardInfo("Restless Cottage", 258, Rarity.RARE, mage.cards.r.RestlessCottage.class));
|
||||
cards.add(new SetCardInfo("Realm-Scorcher Hellkite", 145, Rarity.MYTHIC, mage.cards.r.RealmScorcherHellkite.class));
|
||||
cards.add(new SetCardInfo("Restless Cottage", 258, Rarity.RARE, mage.cards.r.RestlessCottage.class));
|
||||
cards.add(new SetCardInfo("Restless Fortress", 259, Rarity.RARE, mage.cards.r.RestlessFortress.class));
|
||||
cards.add(new SetCardInfo("Return from the Wilds", 181, Rarity.COMMON, mage.cards.r.ReturnFromTheWilds.class));
|
||||
cards.add(new SetCardInfo("Rootrider Faun", 182, Rarity.COMMON, mage.cards.r.RootriderFaun.class));
|
||||
|
|
@ -53,8 +61,10 @@ public final class WildsOfEldraine extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Sharae of Numbing Depths", 213, Rarity.UNCOMMON, mage.cards.s.SharaeOfNumbingDepths.class));
|
||||
cards.add(new SetCardInfo("Skybeast Tracker", 185, Rarity.COMMON, mage.cards.s.SkybeastTracker.class));
|
||||
cards.add(new SetCardInfo("Sleight of Hand", 67, Rarity.COMMON, mage.cards.s.SleightOfHand.class));
|
||||
cards.add(new SetCardInfo("Spellbook Vendor", 31, Rarity.RARE, mage.cards.s.SpellbookVendor.class));
|
||||
cards.add(new SetCardInfo("Swamp", 264, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Sweettooth Witch", 111, Rarity.COMMON, mage.cards.s.SweettoothWitch.class));
|
||||
cards.add(new SetCardInfo("Syr Armont, the Redeemer", 214, Rarity.UNCOMMON, mage.cards.s.SyrArmontTheRedeemer.class));
|
||||
cards.add(new SetCardInfo("Syr Ginger, the Meal Ender", 252, Rarity.RARE, mage.cards.s.SyrGingerTheMealEnder.class));
|
||||
cards.add(new SetCardInfo("Talion, the Kindly Lord", 215, Rarity.MYTHIC, mage.cards.t.TalionTheKindlyLord.class));
|
||||
cards.add(new SetCardInfo("Tanglespan Lookout", 188, Rarity.UNCOMMON, mage.cards.t.TanglespanLookout.class));
|
||||
|
|
@ -66,6 +76,7 @@ public final class WildsOfEldraine extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Tough Cookie", 193, Rarity.UNCOMMON, mage.cards.t.ToughCookie.class));
|
||||
cards.add(new SetCardInfo("Troublemaker Ouphe", 194, Rarity.COMMON, mage.cards.t.TroublemakerOuphe.class));
|
||||
cards.add(new SetCardInfo("Troyan, Gutsy Explorer", 217, Rarity.UNCOMMON, mage.cards.t.TroyanGutsyExplorer.class));
|
||||
cards.add(new SetCardInfo("Twisted Fealty", 154, Rarity.UNCOMMON, mage.cards.t.TwistedFealty.class));
|
||||
cards.add(new SetCardInfo("Warehouse Tabby", 117, Rarity.COMMON, mage.cards.w.WarehouseTabby.class));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,5 +18,7 @@ public final class WildsOfEldraineCommander extends ExpansionSet {
|
|||
private WildsOfEldraineCommander() {
|
||||
super("Wilds of Eldraine Commander", "WOC", ExpansionSet.buildDate(2023, 9, 8), SetType.SUPPLEMENTAL);
|
||||
this.hasBasicLands = false;
|
||||
|
||||
cards.add(new SetCardInfo("Ellivere of the Wild Court", 2, Rarity.MYTHIC, mage.cards.e.EllivereOfTheWildCourt.class));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package org.mage.test.cards.enchantments;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class RoleTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String courtier = "Cursed Courtier";
|
||||
private static final String veteran = "Embereth Veteran";
|
||||
|
||||
@Test
|
||||
public void testRegular() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.HAND, playerA, courtier);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, courtier);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, courtier, 1);
|
||||
assertPermanentCount(playerA, "Cursed", 1);
|
||||
assertPowerToughness(playerA, courtier, 1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplace() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, veteran);
|
||||
addCard(Zone.HAND, playerA, courtier);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, courtier);
|
||||
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}, Sacrifice", courtier);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, courtier, 1);
|
||||
assertPermanentCount(playerA, veteran, 0);
|
||||
assertGraveyardCount(playerA, veteran, 1);
|
||||
assertPermanentCount(playerA, "Cursed", 0);
|
||||
assertPermanentCount(playerA, "Young Hero", 1);
|
||||
assertPowerToughness(playerA, courtier, 3, 3);
|
||||
}
|
||||
}
|
||||
|
|
@ -124,6 +124,7 @@ public class VerifyCardDataTest {
|
|||
|
||||
// cost
|
||||
skipListCreate(SKIP_LIST_COST);
|
||||
skipListAddName(SKIP_LIST_COST, "WOE", "Price of Beauty"); // temporary
|
||||
|
||||
// supertype
|
||||
skipListCreate(SKIP_LIST_SUPERTYPE);
|
||||
|
|
@ -134,6 +135,7 @@ public class VerifyCardDataTest {
|
|||
skipListAddName(SKIP_LIST_TYPE, "UND", "Old Fogey");
|
||||
skipListAddName(SKIP_LIST_TYPE, "UST", "capital offense"); // uses "instant" instead "Instant" as a joke card
|
||||
skipListAddName(SKIP_LIST_TYPE, "WOE", "Knight of Doves"); // temporary
|
||||
skipListAddName(SKIP_LIST_TYPE, "WOE", "Faunsbane Troll"); // temporary
|
||||
|
||||
// subtype
|
||||
skipListCreate(SKIP_LIST_SUBTYPE);
|
||||
|
|
@ -141,6 +143,7 @@ public class VerifyCardDataTest {
|
|||
skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Elvish Impersonators"); // subtype is "Elves" pun
|
||||
skipListAddName(SKIP_LIST_SUBTYPE, "UND", "Elvish Impersonators");
|
||||
skipListAddName(SKIP_LIST_SUBTYPE, "WOE", "Knight of Doves"); // temporary
|
||||
skipListAddName(SKIP_LIST_SUBTYPE, "WOE", "Faunsbane Troll"); // temporary
|
||||
|
||||
// number
|
||||
skipListCreate(SKIP_LIST_NUMBER);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.RoleType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CreateRoleAttachedSourceEffect extends OneShotEffect {
|
||||
|
||||
private final RoleType roleType;
|
||||
|
||||
public CreateRoleAttachedSourceEffect(RoleType roleType) {
|
||||
super(Outcome.Benefit);
|
||||
this.roleType = roleType;
|
||||
}
|
||||
|
||||
private CreateRoleAttachedSourceEffect(final CreateRoleAttachedSourceEffect effect) {
|
||||
super(effect);
|
||||
this.roleType = effect.roleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateRoleAttachedSourceEffect copy() {
|
||||
return new CreateRoleAttachedSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
roleType.createToken(permanent, game, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
return "create a " + roleType.getName() + " Role token attached to it";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.RoleType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CreateRoleAttachedTargetEffect extends OneShotEffect {
|
||||
|
||||
private final RoleType roleType;
|
||||
|
||||
public CreateRoleAttachedTargetEffect(RoleType roleType) {
|
||||
super(Outcome.Benefit);
|
||||
this.roleType = roleType;
|
||||
}
|
||||
|
||||
private CreateRoleAttachedTargetEffect(final CreateRoleAttachedTargetEffect effect) {
|
||||
super(effect);
|
||||
this.roleType = effect.roleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateRoleAttachedTargetEffect copy() {
|
||||
return new CreateRoleAttachedTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
roleType.createToken(permanent, game, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
return "create a " + roleType.getName() + " Role token attached to " +
|
||||
getTargetPointer().describeTargets(mode.getTargets(), "it");
|
||||
}
|
||||
}
|
||||
53
Mage/src/main/java/mage/constants/RoleType.java
Normal file
53
Mage/src/main/java/mage/constants/RoleType.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package mage.constants;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.*;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum RoleType {
|
||||
CURSED("Cursed", CursedRoleToken::new),
|
||||
MONSTER("Monster", MonsterRoleToken::new),
|
||||
ROYAL("Royal", RoyalRoleToken::new),
|
||||
SORCERER("Sorcerer", SorcererRoleToken::new),
|
||||
VIRTUOUS("Virtuous", VirtuousRoleToken::new),
|
||||
WICKED("Wicked", WickedRoleToken::new),
|
||||
YOUNG_HERO("Young Hero", YoungHeroRoleToken::new);
|
||||
|
||||
private final String name;
|
||||
private final Supplier<Token> supplier;
|
||||
|
||||
RoleType(String name, Supplier<Token> supplier) {
|
||||
this.name = name;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Token createToken(Permanent permanent, Game game, Ability source) {
|
||||
Token token = supplier.get();
|
||||
token.putOntoBattlefield(1, game, source);
|
||||
for (UUID tokenId : token.getLastAddedTokenIds()) {
|
||||
Permanent aura = game.getPermanent(tokenId);
|
||||
if (aura == null || !aura.hasSubtype(SubType.AURA, game)) {
|
||||
continue;
|
||||
}
|
||||
aura.getAbilities().get(0).getTargets().get(0).add(permanent.getId(), game);
|
||||
aura.getAbilities().get(0).getEffects().get(0).apply(game, aura.getAbilities().get(0));
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ public enum SubType {
|
|||
CARTOUCHE("Cartouche", SubTypeSet.EnchantmentType),
|
||||
CLASS("Class", SubTypeSet.EnchantmentType),
|
||||
CURSE("Curse", SubTypeSet.EnchantmentType),
|
||||
ROLE("Role", SubTypeSet.EnchantmentType),
|
||||
RUNE("Rune", SubTypeSet.EnchantmentType),
|
||||
SAGA("Saga", SubTypeSet.EnchantmentType),
|
||||
SHARD("Shard", SubTypeSet.EnchantmentType),
|
||||
|
|
|
|||
|
|
@ -63,11 +63,7 @@ import mage.target.Target;
|
|||
import mage.target.TargetCard;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.MessageToClient;
|
||||
import mage.util.MultiAmountMessage;
|
||||
import mage.util.RandomUtil;
|
||||
import mage.util.*;
|
||||
import mage.util.functions.CopyApplier;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.watchers.common.*;
|
||||
|
|
@ -2331,6 +2327,7 @@ public abstract class GameImpl implements Game {
|
|||
|
||||
List<Permanent> legendary = new ArrayList<>();
|
||||
List<Permanent> worldEnchantment = new ArrayList<>();
|
||||
Map<UUID, Map<UUID, Set<Permanent>>> roleMap = new HashMap<>();
|
||||
List<FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = getState().getActivePowerInsteadOfToughnessForDamageLethalityFilters();
|
||||
for (Permanent perm : getBattlefield().getAllActivePermanents()) {
|
||||
if (perm.isCreature(this)) {
|
||||
|
|
@ -2510,6 +2507,11 @@ public abstract class GameImpl implements Game {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (perm.hasSubtype(SubType.ROLE, this) && state.getZone(perm.getId()) == Zone.BATTLEFIELD) {
|
||||
roleMap.computeIfAbsent(perm.getControllerId(), x -> new HashMap<>())
|
||||
.computeIfAbsent(perm.getAttachedTo(), x -> new HashSet<>())
|
||||
.add(perm);
|
||||
}
|
||||
}
|
||||
// 704.5s If the number of lore counters on a Saga permanent is greater than or equal to its final chapter number
|
||||
// and it isn't the source of a chapter ability that has triggered but not yet left the stack, that Saga's controller sacrifices it.
|
||||
|
|
@ -2733,6 +2735,29 @@ public abstract class GameImpl implements Game {
|
|||
}
|
||||
}
|
||||
|
||||
if (!roleMap.isEmpty()) {
|
||||
List<Set<Permanent>> rolesToHandle = roleMap.values()
|
||||
.stream()
|
||||
.map(Map::values)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(s -> s.size() > 1)
|
||||
.collect(Collectors.toList());
|
||||
if (!rolesToHandle.isEmpty()) {
|
||||
for (Set<Permanent> roleSet : rolesToHandle) {
|
||||
int newest = roleSet
|
||||
.stream()
|
||||
.mapToInt(Permanent::getCreateOrder)
|
||||
.max()
|
||||
.orElse(-1);
|
||||
roleSet.removeIf(permanent -> permanent.getCreateOrder() == newest);
|
||||
for (Permanent permanent : roleSet) {
|
||||
movePermanentToGraveyardWithInfo(permanent);
|
||||
somethingHappened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Daybound/Nightbound permanents should be transformed according to day/night
|
||||
// This is not a state-based action but it's unclear where else to put it
|
||||
if (hasDayNight()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.SetBasePowerToughnessEnchantedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class CursedRoleToken extends TokenImpl {
|
||||
|
||||
public CursedRoleToken() {
|
||||
super("Cursed", "Cursed Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature is 1/1.
|
||||
this.addAbility(new SimpleStaticAbility(new SetBasePowerToughnessEnchantedEffect(1, 1)));
|
||||
}
|
||||
|
||||
private CursedRoleToken(final CursedRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public CursedRoleToken copy() {
|
||||
return new CursedRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class MonsterRoleToken extends TokenImpl {
|
||||
|
||||
public MonsterRoleToken() {
|
||||
super("Monster", "Monster Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature gets +1/+1 and has trample
|
||||
ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
|
||||
ability.addEffect(new GainAbilityAttachedEffect(
|
||||
TrampleAbility.getInstance(), AttachmentType.AURA
|
||||
).setText("and has trample"));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private MonsterRoleToken(final MonsterRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public MonsterRoleToken copy() {
|
||||
return new MonsterRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.abilities.keyword.WardAbility;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class RoyalRoleToken extends TokenImpl {
|
||||
|
||||
public RoyalRoleToken() {
|
||||
super("Royal", "Royal Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature gets +1/+1 and has ward {1}
|
||||
ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
|
||||
ability.addEffect(new GainAbilityAttachedEffect(
|
||||
new WardAbility(new GenericManaCost(1), false), AttachmentType.AURA
|
||||
).setText("and has ward {1}"));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private RoyalRoleToken(final RoyalRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public RoyalRoleToken copy() {
|
||||
return new RoyalRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.effects.keyword.ScryEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class SorcererRoleToken extends TokenImpl {
|
||||
|
||||
public SorcererRoleToken() {
|
||||
super("Sorcerer", "Sorcerer Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature gets +1/+1 and has "Whenever this creature attacks, scry 1."
|
||||
ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
|
||||
ability.addEffect(new GainAbilityAttachedEffect(
|
||||
new AttacksTriggeredAbility(new ScryEffect(1, false))
|
||||
.setTriggerPhrase("Whenever this creature attacks, "),
|
||||
AttachmentType.AURA
|
||||
).setText("and has \"Whenever this creature attacks, scry 1.\""));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private SorcererRoleToken(final SorcererRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public SorcererRoleToken copy() {
|
||||
return new SorcererRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class VirtuousRoleToken extends TokenImpl {
|
||||
|
||||
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ENCHANTMENT);
|
||||
|
||||
public VirtuousRoleToken() {
|
||||
super("Virtuous", "Virtuous Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature gets +1/+1 for each enchantment you control.
|
||||
this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue)));
|
||||
}
|
||||
|
||||
private VirtuousRoleToken(final VirtuousRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public VirtuousRoleToken copy() {
|
||||
return new VirtuousRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class WickedRoleToken extends TokenImpl {
|
||||
|
||||
public WickedRoleToken() {
|
||||
super("Wicked", "Wicked Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature gets +1/+1
|
||||
this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)));
|
||||
|
||||
// When this Aura is put into a graveyard from the battlefield, each opponent loses 1 life."
|
||||
this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new LoseLifeOpponentsEffect(1))
|
||||
.setTriggerPhrase("When this Aura is put into a graveyard from the battlefield, "));
|
||||
}
|
||||
|
||||
private WickedRoleToken(final WickedRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public WickedRoleToken copy() {
|
||||
return new WickedRoleToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.common.SourceMatchesFilterCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.ToughnessPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class YoungHeroRoleToken extends TokenImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterCreaturePermanent();
|
||||
|
||||
static {
|
||||
filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 4));
|
||||
}
|
||||
|
||||
private static final Condition condition = new SourceMatchesFilterCondition(filter);
|
||||
|
||||
public YoungHeroRoleToken() {
|
||||
super("Young Hero", "Young Hero Role token");
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
subtype.add(SubType.AURA);
|
||||
subtype.add(SubType.ROLE);
|
||||
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget);
|
||||
ability.addTarget(auraTarget);
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature has "Whenever this creature attacks, if its toughness is 3 or less, put a +1/+1 counter on it."
|
||||
this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(
|
||||
new ConditionalInterveningIfTriggeredAbility(
|
||||
new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())),
|
||||
condition, "Whenever this creature attacks, if its toughness is 3 or less, put a +1/+1 counter on it."
|
||||
), AttachmentType.AURA
|
||||
)));
|
||||
}
|
||||
|
||||
private YoungHeroRoleToken(final YoungHeroRoleToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public YoungHeroRoleToken copy() {
|
||||
return new YoungHeroRoleToken(this);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue