[LTR] Implement Forge Anew (#10777)

* implements Forge Anew with unit tests

* fixes equip effect and adjusts test

* fixes effect to only apply on controller's turns

* changed test location to set

* fixes comparison, fixes wording of text to match oracle text
This commit is contained in:
Vivian Greenslade 2023-08-11 01:30:09 -02:30 committed by GitHub
parent 178e408ac5
commit 040a9779b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 0 deletions

View file

@ -0,0 +1,147 @@
package mage.cards.f;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MyTurnCondition;
import mage.abilities.decorator.ConditionalAsThoughEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.continuous.ActivateAbilitiesAnyTimeYouCouldCastInstantEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.watchers.Watcher;
/**
*
* @author xanderhall
*/
public class ForgeAnew extends CardImpl {
private static final FilterCard filter = new FilterCard("Equipment card from your graveyard");
static {
filter.add(SubType.EQUIPMENT.getPredicate());
}
public ForgeAnew(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// When Forge Anew enters the battlefield, return target Equipment card from your graveyard to the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
//As long as its your turn, you may activate equip abilities any time you could cast an instant.
this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(
new ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(EquipAbility.class, "equip abilities"), MyTurnCondition.instance
).setText("as long as it's your turn, you may activate equip abilities any time you could cast an instant."))
);
//You may pay {0} rather than pay the equip cost of the first equip ability you activate during each of your turns.
this.addAbility(new SimpleStaticAbility(new ForgeAnewCostEffect()), new ForgeAnewWatcher());
}
private ForgeAnew(final ForgeAnew card) {
super(card);
}
@Override
public ForgeAnew copy() {
return new ForgeAnew(this);
}
}
class ForgeAnewCostEffect extends CostModificationEffectImpl {
ForgeAnewCostEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.SET_COST);
this.staticText = "you may pay {0} rather than pay the equip cost of the first equip ability you activate during each of your turns.";
}
ForgeAnewCostEffect(final ForgeAnewCostEffect effect) {
super(effect);
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof EquipAbility
&& source.isControlledBy(abilityToModify.getControllerId())
&& game.getActivePlayerId().equals(source.getControllerId())
&& !ForgeAnewWatcher.checkPlayer(abilityToModify.getControllerId(), game);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
boolean applyReduce = false;
if (game.inCheckPlayableState()) {
// getPlayable use - apply all the time
applyReduce = true;
} else {
// real use - ask the player
Player controller = game.getPlayer(abilityToModify.getControllerId());
if (controller != null
&& controller.chooseUse(Outcome.PlayForFree,
String.format("Pay {0} to equip instead %s?", abilityToModify.getManaCostsToPay().getText()), source, game)) {
applyReduce = true;
}
}
if (applyReduce) {
abilityToModify.getCosts().clear();
abilityToModify.getManaCostsToPay().clear();
return true;
}
return false;
}
@Override
public ForgeAnewCostEffect copy() {
return new ForgeAnewCostEffect(this);
}
}
class ForgeAnewWatcher extends Watcher {
private final Set<UUID> equippedThisTurn = new HashSet<>();
ForgeAnewWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.ACTIVATED_ABILITY) {
return;
}
StackObject object = game.getStack().getStackObject(event.getSourceId());
if (object != null && object.getStackAbility() instanceof EquipAbility) {
equippedThisTurn.add(event.getPlayerId());
}
}
@Override
public void reset() {
super.reset();
equippedThisTurn.clear();
}
static boolean checkPlayer(UUID playerId, Game game) {
ForgeAnewWatcher watcher = game.getState().getWatcher(ForgeAnewWatcher.class);
return watcher != null && watcher.equippedThisTurn.contains(playerId);
}
}

View file

@ -99,6 +99,7 @@ public final class TheLordOfTheRingsTalesOfMiddleEarth extends ExpansionSet {
cards.add(new SetCardInfo("Flowering of the White Tree", 15, Rarity.RARE, mage.cards.f.FloweringOfTheWhiteTree.class));
cards.add(new SetCardInfo("Fog on the Barrow-Downs", 16, Rarity.COMMON, mage.cards.f.FogOnTheBarrowDowns.class));
cards.add(new SetCardInfo("Foray of Orcs", 128, Rarity.UNCOMMON, mage.cards.f.ForayOfOrcs.class));
cards.add(new SetCardInfo("Forge Anew", 17, Rarity.RARE, mage.cards.f.ForgeAnew.class));
cards.add(new SetCardInfo("Forest", 270, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Friendly Rivalry", 204, Rarity.UNCOMMON, mage.cards.f.FriendlyRivalry.class));
cards.add(new SetCardInfo("Frodo Baggins", 205, Rarity.UNCOMMON, mage.cards.f.FrodoBaggins.class));

View file

@ -0,0 +1,44 @@
package org.mage.test.cards.single.ltr;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import mage.constants.PhaseStep;
import mage.constants.Zone;
/**
* @author Xanderhall
*/
public class ForgeAnewTest extends CardTestPlayerBase {
static final String FORGE_ANEW = "Forge Anew";
static final String EQUIPMENT = "Bronze Sword";
static final String CREATURE = "Silvercoat Lion";
/**
* Test implementation of card
*/
@Test
public void testForgeAnew() {
addCard(Zone.BATTLEFIELD, playerA, CREATURE, 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.HAND, playerA, FORGE_ANEW, 1);
addCard(Zone.GRAVEYARD, playerA, EQUIPMENT, 1);
// Test return from graveyard
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, FORGE_ANEW);
addTarget(playerA, EQUIPMENT, 1);
// Test can equip at instant speed for 0 (all mana tapped)
activateAbility(1, PhaseStep.END_COMBAT, playerA, "Equip {3}", CREATURE);
setChoice(playerA, true); // Choose to equip for free
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
// Make sure it is attached
assertIsAttachedTo(playerA, EQUIPMENT, CREATURE);
}
}