mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Added Tarrian's Journal // The Tomb of Aclazotz
This commit is contained in:
parent
5c677b8cce
commit
7adbf45258
4 changed files with 349 additions and 1 deletions
69
Mage.Sets/src/mage/cards/t/TarriansJournal.java
Normal file
69
Mage.Sets/src/mage/cards/t/TarriansJournal.java
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.TransformSourceEffect;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class TarriansJournal extends CardImpl {
|
||||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("another artifact or creature");
|
||||
|
||||
static {
|
||||
filter.add(AnotherPredicate.instance);
|
||||
filter.add(Predicates.or(
|
||||
CardType.ARTIFACT.getPredicate(),
|
||||
CardType.CREATURE.getPredicate()
|
||||
));
|
||||
}
|
||||
|
||||
public TarriansJournal(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}");
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
|
||||
this.secondSideCardClazz = mage.cards.t.TheTombOfAclazotz.class;
|
||||
this.color.setBlack(true);
|
||||
|
||||
// T: Sacrifice another artifact or creature: Draw a card. Activate only as a sorcery.
|
||||
Ability ability = new ActivateAsSorceryActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost());
|
||||
ability.addCost(new SacrificeTargetCost(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
this.addAbility(new TransformAbility());
|
||||
Ability transformAbility = new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl("{2}"));
|
||||
transformAbility.addCost(new TapSourceCost());
|
||||
this.addAbility(transformAbility);
|
||||
|
||||
}
|
||||
|
||||
private TarriansJournal(final TarriansJournal card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TarriansJournal copy() {
|
||||
return new TarriansJournal(this);
|
||||
}
|
||||
|
||||
}
|
||||
276
Mage.Sets/src/mage/cards/t/TheTombOfAclazotz.java
Normal file
276
Mage.Sets/src/mage/cards/t/TheTombOfAclazotz.java
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.counter.AddCounterEnteringCreatureEffect;
|
||||
import mage.abilities.mana.BlackManaAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class TheTombOfAclazotz extends CardImpl {
|
||||
|
||||
public TheTombOfAclazotz(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, null);
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.CAVE);
|
||||
|
||||
// this is the second face of Tarrian's Journal
|
||||
this.nightCard = true;
|
||||
|
||||
// {T}: Add {B}.
|
||||
this.addAbility(new BlackManaAbility());
|
||||
|
||||
// You may cast a creature spell from your graveyard this turn. If you do, it enters the battlefield with a finality counter on it and is a Vampire in addition to its other types.
|
||||
Ability castSpellAbility = new SimpleActivatedAbility(new TheTombOfAclazotzEffect(), new TapSourceCost());
|
||||
castSpellAbility.setIdentifier(MageIdentifier.TheTombOfAclazotzWatcher);
|
||||
castSpellAbility.addWatcher(new TheTombOfAclazotzWatcher());
|
||||
this.addAbility(castSpellAbility);
|
||||
|
||||
}
|
||||
|
||||
private TheTombOfAclazotz(final TheTombOfAclazotz card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TheTombOfAclazotz copy() {
|
||||
return new TheTombOfAclazotz(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TheTombOfAclazotzEffect extends AsThoughEffectImpl {
|
||||
|
||||
TheTombOfAclazotzEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
|
||||
staticText = "You may cast a creature spell from your graveyard this turn. If you do, it enters the battlefield with a finality counter on it and is a Vampire in addition to its other types. (If a creature with a finality counter on it would die, exile it instead.)";
|
||||
}
|
||||
|
||||
private TheTombOfAclazotzEffect(final TheTombOfAclazotzEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TheTombOfAclazotzEffect copy() {
|
||||
return new TheTombOfAclazotzEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class);
|
||||
if (watcher != null) {
|
||||
watcher.addPlayable(source, game);
|
||||
watcher.addPlayFromAnywhereEffect(this.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class);
|
||||
if (watcher == null
|
||||
|| !watcher.checkPermission(playerId, source, game)
|
||||
|| game.getState().getZone(objectId) != Zone.GRAVEYARD) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(objectId);
|
||||
if (card != null
|
||||
&& affectedAbility instanceof SpellAbility
|
||||
&& card.getOwnerId().equals(playerId)
|
||||
&& card.isCreature(game)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class TheTombOfAclazotzWatcher extends Watcher {
|
||||
|
||||
private final Map<MageObjectReference, Map<UUID, Integer>> morMap = new HashMap<>();
|
||||
private MageObjectReference mor;
|
||||
private UUID playFromAnywhereEffectId;
|
||||
|
||||
TheTombOfAclazotzWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (GameEvent.EventType.SPELL_CAST.equals(event.getType())
|
||||
&& event.hasApprovingIdentifier(MageIdentifier.TheTombOfAclazotzWatcher)) {
|
||||
Spell target = game.getSpell(event.getTargetId());
|
||||
Card card = target.getCard();
|
||||
if (card != null) {
|
||||
mor = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game), game);
|
||||
if (mor != null) {
|
||||
game.getState().addEffect(new AddCounterEnteringCreatureEffect(new MageObjectReference(target.getCard(), game),
|
||||
CounterType.FINALITY.createInstance(), Outcome.Neutral),
|
||||
target.getSpellAbility());
|
||||
game.getState().addEffect(new AddSubtypeEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), SubType.VAMPIRE, Outcome.Benefit), target.getSpellAbility());
|
||||
// Rule 728.2 we must insure the effect is used (creature is cast successfully) before discarding the play effect
|
||||
UUID playEffectId = this.getPlayFromAnywhereEffect();
|
||||
if (playEffectId != null
|
||||
&& game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().getId().equals(playEffectId)) {
|
||||
// discard the play effect
|
||||
game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean checkPermission(UUID playerId, Ability source, Game game) {
|
||||
if (!playerId.equals(source.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
MageObjectReference mor = new MageObjectReference(
|
||||
source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game
|
||||
);
|
||||
return morMap.computeIfAbsent(mor, m -> new HashMap<>()).getOrDefault(playerId, 0) > 0;
|
||||
}
|
||||
|
||||
void addPlayable(Ability source, Game game) {
|
||||
MageObjectReference mor = new MageObjectReference(
|
||||
source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game
|
||||
);
|
||||
morMap.computeIfAbsent(mor, m -> new HashMap<>())
|
||||
.compute(source.getControllerId(), CardUtil::setOrIncrementValue);
|
||||
}
|
||||
|
||||
void addPlayFromAnywhereEffect(UUID uuid) {
|
||||
playFromAnywhereEffectId = uuid;
|
||||
}
|
||||
|
||||
UUID getPlayFromAnywhereEffect() {
|
||||
return playFromAnywhereEffectId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
morMap.clear();
|
||||
super.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final MageObjectReference mor;
|
||||
private final SubType subType;
|
||||
|
||||
public AddSubtypeEnteringCreatureEffect(MageObjectReference mor, SubType subType, Outcome outcome) {
|
||||
super(Duration.WhileOnBattlefield, outcome);
|
||||
this.mor = mor;
|
||||
this.subType = subType;
|
||||
}
|
||||
|
||||
private AddSubtypeEnteringCreatureEffect(final AddSubtypeEnteringCreatureEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
this.subType = effect.subType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
return permanent != null
|
||||
&& mor.refersTo(permanent, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent target = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
if (target != null) {
|
||||
AddCardSubTypeEnteringTargetEffect effect = new AddCardSubTypeEnteringTargetEffect(subType, Duration.WhileOnBattlefield);
|
||||
effect.setTargetPointer(new FixedTarget(target, game));
|
||||
game.addEffect(effect, source);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddSubtypeEnteringCreatureEffect copy() {
|
||||
return new AddSubtypeEnteringCreatureEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final SubType addedSubType;
|
||||
|
||||
public AddCardSubTypeEnteringTargetEffect(SubType addedSubType, Duration duration) {
|
||||
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
this.addedSubType = addedSubType;
|
||||
}
|
||||
|
||||
protected AddCardSubTypeEnteringTargetEffect(final AddCardSubTypeEnteringTargetEffect effect) {
|
||||
super(effect);
|
||||
this.addedSubType = effect.addedSubType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent target = game.getPermanent(game.getObject(targetPointer.getFixedTarget(game, source).getTarget()).getId());
|
||||
if (target != null) {
|
||||
target.addSubType(game, addedSubType);
|
||||
}
|
||||
if (target == null) {
|
||||
discard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddCardSubTypeEnteringTargetEffect copy() {
|
||||
return new AddCardSubTypeEnteringTargetEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -313,6 +313,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Swamp", 397, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Swashbuckler's Whip", 263, Rarity.UNCOMMON, mage.cards.s.SwashbucklersWhip.class));
|
||||
cards.add(new SetCardInfo("Synapse Necromage", 125, Rarity.UNCOMMON, mage.cards.s.SynapseNecromage.class));
|
||||
cards.add(new SetCardInfo("Tarrian's Journal", 126, Rarity.RARE, mage.cards.t.TarriansJournal.class));
|
||||
cards.add(new SetCardInfo("Tarrian's Soulcleaver", 264, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class));
|
||||
cards.add(new SetCardInfo("Tectonic Hazard", 169, Rarity.COMMON, mage.cards.t.TectonicHazard.class));
|
||||
cards.add(new SetCardInfo("Tecutlan, the Searing Rift", 135, Rarity.RARE, mage.cards.t.TecutlanTheSearingRift.class));
|
||||
|
|
@ -333,6 +334,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("The Mycotyrant", 235, Rarity.MYTHIC, mage.cards.t.TheMycotyrant.class));
|
||||
cards.add(new SetCardInfo("The Myriad Pools", 363, Rarity.RARE, mage.cards.t.TheMyriadPools.class));
|
||||
cards.add(new SetCardInfo("The Skullspore Nexus", 212, Rarity.MYTHIC, mage.cards.t.TheSkullsporeNexus.class));
|
||||
cards.add(new SetCardInfo("The Tomb of Aclazotz", 126, Rarity.RARE, mage.cards.t.TheTombOfAclazotz.class));
|
||||
cards.add(new SetCardInfo("Thousand Moons Crackshot", 37, Rarity.COMMON, mage.cards.t.ThousandMoonsCrackshot.class));
|
||||
cards.add(new SetCardInfo("Thousand Moons Infantry", 38, Rarity.COMMON, mage.cards.t.ThousandMoonsInfantry.class));
|
||||
cards.add(new SetCardInfo("Thousand Moons Smithy", 39, Rarity.RARE, mage.cards.t.ThousandMoonsSmithy.class));
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ public enum MageIdentifier {
|
|||
ScourgeOfNelTothAlternateCast,
|
||||
SqueeDubiousMonarchAlternateCast,
|
||||
WorldheartPhoenixAlternateCast,
|
||||
XandersPactAlternateCast;
|
||||
XandersPactAlternateCast,
|
||||
TheTombOfAclazotzWatcher;
|
||||
|
||||
/**
|
||||
* Additional text if there is need to differentiate two very similar effects
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue