mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
[C21] Implemented Fractal Harness
This commit is contained in:
parent
2e5619e268
commit
1fad23b9fb
7 changed files with 152 additions and 131 deletions
116
Mage.Sets/src/mage/cards/f/FractalHarness.java
Normal file
116
Mage.Sets/src/mage/cards/f/FractalHarness.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.QuandrixToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.watchers.common.ManaSpentToCastWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class FractalHarness extends CardImpl {
|
||||
|
||||
public FractalHarness(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{X}{2}{G}");
|
||||
|
||||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
// When Fractal Harness enters the battlefield, create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it and attach Fractal Harness to it.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new FractalHarnessTokenEffect()), new ManaSpentToCastWatcher());
|
||||
|
||||
// Whenever equipped creature attacks, double the number of +1/+1 counters on it.
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||
new FractalHarnessDoubleEffect(), AttachmentType.EQUIPMENT, false
|
||||
));
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(2));
|
||||
}
|
||||
|
||||
private FractalHarness(final FractalHarness card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FractalHarness copy() {
|
||||
return new FractalHarness(this);
|
||||
}
|
||||
}
|
||||
|
||||
class FractalHarnessTokenEffect extends OneShotEffect {
|
||||
|
||||
FractalHarnessTokenEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "create a 0/0 green and blue Fractal creature token. " +
|
||||
"Put X +1/+1 counters on it and attach {this} to it";
|
||||
}
|
||||
|
||||
private FractalHarnessTokenEffect(final FractalHarnessTokenEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FractalHarnessTokenEffect copy() {
|
||||
return new FractalHarnessTokenEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Token token = new QuandrixToken();
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
int xValue = ManacostVariableValue.instance.calculate(game, source, this);
|
||||
boolean flag = true;
|
||||
for (UUID tokenId : token.getLastAddedTokenIds()) {
|
||||
Permanent permanent = game.getPermanent(tokenId);
|
||||
if (permanent == null) {
|
||||
continue;
|
||||
}
|
||||
if (flag && permanent.addAttachment(tokenId, source, game)) {
|
||||
flag = false;
|
||||
}
|
||||
permanent.addCounters(CounterType.P1P1.createInstance(xValue), source.getControllerId(), source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class FractalHarnessDoubleEffect extends OneShotEffect {
|
||||
|
||||
FractalHarnessDoubleEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "double the number of +1/+1 counters on it";
|
||||
}
|
||||
|
||||
private FractalHarnessDoubleEffect(final FractalHarnessDoubleEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FractalHarnessDoubleEffect copy() {
|
||||
return new FractalHarnessDoubleEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = (Permanent) getValue("attachedPermanent");
|
||||
return permanent != null && permanent.addCounters(CounterType.P1P1.createInstance(
|
||||
permanent.getCounters(game).getCount(CounterType.P1P1)
|
||||
), source.getControllerId(), source, game);
|
||||
}
|
||||
}
|
|
@ -5,22 +5,21 @@ import mage.ObjectColor;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.TapTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.common.FilterNonlandPermanent;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.watchers.common.ManaSpentToCastWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -50,8 +49,8 @@ public final class GadwickTheWizened extends CardImpl {
|
|||
|
||||
// When Gadwick, the Wizened enters the battlefield, draw X cards.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(
|
||||
new DrawCardSourceControllerEffect(GadwickTheWizenedValue.instance)
|
||||
), new GadwickTheWizenedWatcher());
|
||||
new DrawCardSourceControllerEffect(ManacostVariableValue.instance)
|
||||
), new ManaSpentToCastWatcher());
|
||||
|
||||
// Whenever you cast a blue spell, tap target nonland permanent an opponent controls.
|
||||
Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), filter, false);
|
||||
|
@ -68,60 +67,3 @@ public final class GadwickTheWizened extends CardImpl {
|
|||
return new GadwickTheWizened(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum GadwickTheWizenedValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
// watcher in card's scope
|
||||
GadwickTheWizenedWatcher watcher = game.getState().getWatcher(GadwickTheWizenedWatcher.class, sourceAbility.getSourceId());
|
||||
if (watcher == null) {
|
||||
return 0;
|
||||
}
|
||||
if (game.getState().getValue(sourceAbility.getSourceId().toString()
|
||||
+ "cardsToDraw") == null) {
|
||||
return 0;
|
||||
}
|
||||
return (Integer) game.getState().getValue(sourceAbility.getSourceId().toString()
|
||||
+ "cardsToDraw");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class GadwickTheWizenedWatcher extends Watcher {
|
||||
|
||||
GadwickTheWizenedWatcher() {
|
||||
super(WatcherScope.CARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.SPELL_CAST) {
|
||||
return;
|
||||
}
|
||||
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
|
||||
if (spell == null) {
|
||||
return;
|
||||
}
|
||||
if (spell.getSourceId() != super.getSourceId()) {
|
||||
return; // the spell is not Gadwick, the Wizened
|
||||
}
|
||||
game.getState().setValue(spell.getSourceId().toString()
|
||||
+ "cardsToDraw", spell.getSpellAbility().getManaCostsToPay().getX());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
|
|||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.MultipliedValue;
|
||||
import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
|
@ -16,18 +17,20 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
|||
import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.TappedPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.token.ShardToken;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.watchers.common.CardsDrawnThisTurnWatcher;
|
||||
import mage.watchers.common.ManaSpentToCastWatcher;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
@ -54,8 +57,8 @@ public final class NikoAris extends CardImpl {
|
|||
|
||||
// When Niko Aris enters the battlefield, create X Shard tokens.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(
|
||||
new CreateTokenEffect(new ShardToken(), NikoArisValue.instance)
|
||||
), new NikoArisWatcher());
|
||||
new CreateTokenEffect(new ShardToken(), ManacostVariableValue.instance)
|
||||
), new ManaSpentToCastWatcher());
|
||||
|
||||
// +1: Up to one target creature you control can't be blocked this turn. Whenever that creature deals damage this turn, return it to its owner's hand.
|
||||
Ability ability = new LoyaltyAbility(new CantBeBlockedTargetEffect(Duration.EndOfTurn), 1);
|
||||
|
@ -84,59 +87,6 @@ public final class NikoAris extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
enum NikoArisValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
NikoArisWatcher watcher = game.getState().getWatcher(NikoArisWatcher.class, sourceAbility.getSourceId());
|
||||
if (watcher == null) {
|
||||
return 0;
|
||||
}
|
||||
if (game.getState().getValue(sourceAbility.getSourceId().toString() + "xValue") == null) {
|
||||
return 0;
|
||||
}
|
||||
return (Integer) game.getState().getValue(sourceAbility.getSourceId().toString() + "xValue");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class NikoArisWatcher extends Watcher {
|
||||
|
||||
NikoArisWatcher() {
|
||||
super(WatcherScope.CARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.SPELL_CAST) {
|
||||
return;
|
||||
}
|
||||
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
|
||||
if (spell == null || spell.getSourceId() != super.getSourceId()) {
|
||||
return;
|
||||
}
|
||||
game.getState().setValue(
|
||||
spell.getSourceId().toString() + "xValue",
|
||||
spell.getSpellAbility().getManaCostsToPay().getX()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NikoArisDamageTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
NikoArisDamageTriggeredAbility() {
|
||||
|
@ -176,4 +126,4 @@ class NikoArisDamageTriggeredAbility extends DelayedTriggeredAbility {
|
|||
public String getRule() {
|
||||
return "Whenever that creature deals damage this turn, return it to its owner's hand.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ public final class Commander2021Edition extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Fiery Fall", 170, Rarity.COMMON, mage.cards.f.FieryFall.class));
|
||||
cards.add(new SetCardInfo("Forgotten Ancient", 189, Rarity.RARE, mage.cards.f.ForgottenAncient.class));
|
||||
cards.add(new SetCardInfo("Forgotten Cave", 289, Rarity.COMMON, mage.cards.f.ForgottenCave.class));
|
||||
cards.add(new SetCardInfo("Fractal Harness", 61, Rarity.RARE, mage.cards.f.FractalHarness.class));
|
||||
cards.add(new SetCardInfo("Garruk, Primal Hunter", 190, Rarity.MYTHIC, mage.cards.g.GarrukPrimalHunter.class));
|
||||
cards.add(new SetCardInfo("Gaze of Granite", 217, Rarity.RARE, mage.cards.g.GazeOfGranite.class));
|
||||
cards.add(new SetCardInfo("Geometric Nexus", 77, Rarity.RARE, mage.cards.g.GeometricNexus.class));
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.Locale;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AttachmentType;
|
||||
|
@ -10,6 +9,8 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* "When enchanted/equipped creature attacks " triggered ability
|
||||
*
|
||||
|
@ -52,9 +53,8 @@ public class AttacksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
Permanent equipment = game.getPermanent(this.sourceId);
|
||||
if (equipment != null && equipment.getAttachedTo() != null
|
||||
&& event.getSourceId().equals(equipment.getAttachedTo())) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("sourceId", event.getSourceId());
|
||||
}
|
||||
getEffects().setValue("sourceId", event.getSourceId());
|
||||
getEffects().setValue("attachedPermanent", game.getPermanent(event.getSourceId()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -3,14 +3,20 @@ package mage.abilities.dynamicvalue.common;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.ManaSpentToCastWatcher;
|
||||
|
||||
public enum ManacostVariableValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
return sourceAbility.getManaCostsToPay().getX();
|
||||
if (sourceAbility.getAbilityType() == AbilityType.SPELL) {
|
||||
return sourceAbility.getManaCostsToPay().getX();
|
||||
}
|
||||
ManaSpentToCastWatcher watcher = game.getState().getWatcher(ManaSpentToCastWatcher.class, sourceAbility.getSourceId());
|
||||
return watcher != null ? watcher.getAndResetLastXValue() : sourceAbility.getManaCostsToPay().getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@ import mage.watchers.Watcher;
|
|||
public class ManaSpentToCastWatcher extends Watcher {
|
||||
|
||||
private Mana payment = null;
|
||||
private Integer xValue = 0;
|
||||
|
||||
public ManaSpentToCastWatcher() {
|
||||
super(WatcherScope.CARD);
|
||||
|
@ -29,12 +30,14 @@ public class ManaSpentToCastWatcher extends Watcher {
|
|||
Spell spell = (Spell) game.getObject(event.getTargetId());
|
||||
if (spell != null && this.getSourceId().equals(spell.getSourceId())) {
|
||||
payment = spell.getSpellAbility().getManaCostsToPay().getUsedManaToPay();
|
||||
xValue = spell.getSpellAbility().getManaCostsToPay().getX();
|
||||
}
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
|
||||
&& this.getSourceId().equals(event.getSourceId())) {
|
||||
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
|
||||
payment = null;
|
||||
xValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,13 +48,16 @@ public class ManaSpentToCastWatcher extends Watcher {
|
|||
returnPayment = payment.copy();
|
||||
}
|
||||
return returnPayment;
|
||||
}
|
||||
|
||||
public int getAndResetLastXValue() {
|
||||
return xValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
payment = null;
|
||||
xValue = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue