[FIN] Implement Ancient Adamantoise (#13670)

* [FIN] Implement Ancient Adamantoise

* change effect type

* add test
This commit is contained in:
Evan Kranzler 2025-05-27 21:56:07 -04:00 committed by GitHub
parent 3d85682535
commit e1f4e9db59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 188 additions and 2 deletions

View file

@ -0,0 +1,148 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.ExileSourceEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TreasureToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AncientAdamantoise extends CardImpl {
public AncientAdamantoise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}{G}");
this.subtype.add(SubType.TURTLE);
this.power = new MageInt(8);
this.toughness = new MageInt(20);
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// Ward {3}
this.addAbility(new WardAbility(new ManaCostsImpl<>("{3}")));
// Damage isn't removed from this creature during cleanup steps.
this.addAbility(new SimpleStaticAbility(new AncientAdamantoiseDamageEffect()));
// All damage that would be dealt to you and other permanents you control is dealt to this creature instead.
this.addAbility(new SimpleStaticAbility(new AncientAdamantoiseRedirectEffect()));
// When this creature dies, exile it and create ten tapped Treasure tokens.
Ability ability = new DiesSourceTriggeredAbility(new ExileSourceEffect().setText("exile it"));
ability.addEffect(new CreateTokenEffect(new TreasureToken(), 10, true).concatBy("and"));
this.addAbility(ability);
}
private AncientAdamantoise(final AncientAdamantoise card) {
super(card);
}
@Override
public AncientAdamantoise copy() {
return new AncientAdamantoise(this);
}
}
class AncientAdamantoiseDamageEffect extends ContinuousRuleModifyingEffectImpl {
AncientAdamantoiseDamageEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "damage isn't removed from {this} during cleanup steps";
}
private AncientAdamantoiseDamageEffect(final AncientAdamantoiseDamageEffect effect) {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.REMOVE_DAMAGE_EOT;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getTargetId().equals(source.getSourceId());
}
@Override
public AncientAdamantoiseDamageEffect copy() {
return new AncientAdamantoiseDamageEffect(this);
}
}
class AncientAdamantoiseRedirectEffect extends ReplacementEffectImpl {
AncientAdamantoiseRedirectEffect() {
super(Duration.WhileOnBattlefield, Outcome.RedirectDamage);
staticText = "all damage that would be dealt to you and other " +
"permanents you control is dealt to this creature instead";
}
private AncientAdamantoiseRedirectEffect(final AncientAdamantoiseRedirectEffect effect) {
super(effect);
}
@Override
public AncientAdamantoiseRedirectEffect copy() {
return new AncientAdamantoiseRedirectEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
DamageEvent damageEvent = (DamageEvent) event;
Permanent permanent = source.getSourcePermanentOrLKI(game);
if (permanent != null) {
permanent.damage(
damageEvent.getAmount(), event.getSourceId(), source, game,
damageEvent.isCombatDamage(), damageEvent.isPreventable()
);
}
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
switch (event.getType()) {
case DAMAGE_PLAYER:
case DAMAGE_PERMANENT:
return true;
default:
return false;
}
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
switch (event.getType()) {
case DAMAGE_PLAYER:
return source.isControlledBy(event.getTargetId());
case DAMAGE_PERMANENT:
return !event.getTargetId().equals(source.getSourceId())
&& source.isControlledBy(game.getControllerId(event.getTargetId()));
default:
return false;
}
}
}

View file

@ -44,6 +44,7 @@ public final class FinalFantasy extends ExpansionSet {
cards.add(new SetCardInfo("Ambrosia Whiteheart", 325, Rarity.UNCOMMON, mage.cards.a.AmbrosiaWhiteheart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ambrosia Whiteheart", 424, Rarity.UNCOMMON, mage.cards.a.AmbrosiaWhiteheart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ambrosia Whiteheart", 6, Rarity.UNCOMMON, mage.cards.a.AmbrosiaWhiteheart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ancient Adamantoise", 172, Rarity.MYTHIC, mage.cards.a.AncientAdamantoise.class));
cards.add(new SetCardInfo("Ardyn, the Usurper", 315, Rarity.RARE, mage.cards.a.ArdynTheUsurper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ardyn, the Usurper", 379, Rarity.RARE, mage.cards.a.ArdynTheUsurper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ardyn, the Usurper", 444, Rarity.RARE, mage.cards.a.ArdynTheUsurper.class, NON_FULL_USE_VARIOUS));

View file

@ -0,0 +1,32 @@
package org.mage.test.cards.single.fin;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class AncientAdamantoiseTest extends CardTestPlayerBase {
private static final String adamantoise = "Ancient Adamantoise";
private static final String bolt = "Lightning Bolt";
@Test
public void testDamageStays() {
addCard(Zone.HAND, playerA, bolt);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, adamantoise);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, adamantoise);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
execute();
Permanent permanent = getPermanent(adamantoise);
Assert.assertEquals(adamantoise + " should have 3 damage on it on the next turn", 3, permanent.getDamage());
}
}

View file

@ -173,7 +173,7 @@ public class GameEvent implements Serializable {
amount amount of life loss
flag true = from combat damage - other from non combat damage
*/
LOSE_LIFE, LOST_LIFE,
/* LOST_LIFE_BATCH_FOR_ONE_PLAYER
combines all life lost events for a player to a single batch (event)
@ -509,6 +509,7 @@ public class GameEvent implements Serializable {
combines all permanent damage events to a single batch (event) and split it per damaged permanent
*/
DAMAGED_BATCH_FOR_ONE_PERMANENT(true),
REMOVE_DAMAGE_EOT,
DESTROY_PERMANENT,
/* DESTROYED_PERMANENT

View file

@ -524,7 +524,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
@Override
public void endOfTurn(Game game) {
this.damage = 0;
if (!game.replaceEvent(GameEvent.getEvent(
EventType.REMOVE_DAMAGE_EOT, this.getId(), null, this.getControllerId()
))) {
this.damage = 0;
}
this.timesLoyaltyUsed = 0;
this.turnsOnBattlefield++;
this.deathtouched = false;