[SLD] Implemented Hawkins National Laboratory / The Upside Down

This commit is contained in:
Evan Kranzler 2021-10-23 07:47:15 -04:00
parent 05222f3bdc
commit 5995dc2f7c
3 changed files with 289 additions and 0 deletions

View file

@ -0,0 +1,110 @@
package mage.cards.h;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.keyword.InvestigateEffect;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class HawkinsNationalLaboratory extends CardImpl {
public HawkinsNationalLaboratory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.addSuperType(SuperType.LEGENDARY);
this.transformable = true;
this.secondSideCardClazz = mage.cards.t.TheUpsideDown.class;
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {4}, {T}: Investigate.
Ability ability = new SimpleActivatedAbility(new InvestigateEffect(), new GenericManaCost(4));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
// At the beginning of your end step, if you sacrificed three or more Clues this turn, transform Hawkins National Laboratory.
this.addAbility(new TransformAbility());
this.addAbility(new BeginningOfEndStepTriggeredAbility(
Zone.BATTLEFIELD, new TransformSourceEffect(true),
TargetController.YOU, HawkinsNationalLaboratoryCondition.instance, false
), new HawkinsNationalLaboratoryWatcher());
}
private HawkinsNationalLaboratory(final HawkinsNationalLaboratory card) {
super(card);
}
@Override
public HawkinsNationalLaboratory copy() {
return new HawkinsNationalLaboratory(this);
}
}
enum HawkinsNationalLaboratoryCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return HawkinsNationalLaboratoryWatcher.checkPlayer(source.getControllerId(), game);
}
@Override
public String toString() {
return "you sacrificed three or more Clues this turn";
}
}
class HawkinsNationalLaboratoryWatcher extends Watcher {
private final Map<UUID, Integer> playerMap = new HashMap<>();
HawkinsNationalLaboratoryWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SACRIFICED_PERMANENT) {
return;
}
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
if (permanent == null || !permanent.hasSubtype(SubType.CLUE, game)) {
return;
}
playerMap.compute(event.getPlayerId(), (u, i) -> i == null ? 1 : Integer.sum(i, 1));
}
@Override
public void reset() {
playerMap.clear();
super.reset();
}
static boolean checkPlayer(UUID playerId, Game game) {
return game
.getState()
.getWatcher(HawkinsNationalLaboratoryWatcher.class)
.playerMap
.getOrDefault(playerId, 0) >= 3;
}
}

View file

@ -0,0 +1,177 @@
package mage.cards.t;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.mana.BlackManaAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TheUpsideDown extends CardImpl {
public TheUpsideDown(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.addSuperType(SuperType.LEGENDARY);
this.transformable = true;
this.nightCard = true;
// When this land transforms into The Upside Down, return target creature card from your graveyard to the battlefield.
this.addAbility(new TheUpsideDownTransformAbility());
// When the creature put onto the battlefield with The Upside Down leaves the battlefield, transform The Upside Down.
this.addAbility(new TheUpsideDownLeavesAbility());
// {T}, Pay 1 life: Add {B}.
Ability ability = new BlackManaAbility();
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
}
private TheUpsideDown(final TheUpsideDown card) {
super(card);
}
@Override
public TheUpsideDown copy() {
return new TheUpsideDown(this);
}
static String makeKey(Ability source, Game game) {
return "TheUpsideDown_" + source.getSourceId() + '_' + source.getSourceObjectZoneChangeCounter();
}
}
class TheUpsideDownTransformAbility extends TriggeredAbilityImpl {
public TheUpsideDownTransformAbility() {
super(Zone.BATTLEFIELD, new TheUpsideDownEffect(), false);
this.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
}
public TheUpsideDownTransformAbility(final TheUpsideDownTransformAbility ability) {
super(ability);
}
@Override
public TheUpsideDownTransformAbility copy() {
return new TheUpsideDownTransformAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TRANSFORMED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!event.getTargetId().equals(this.getSourceId())) {
return false;
}
Permanent permanent = getSourcePermanentIfItStillExists(game);
return permanent != null && !permanent.isTransformed();
}
@Override
public String getRule() {
return "When this land transforms into {this}, " +
"return target creature card from your graveyard to the battlefield.";
}
}
class TheUpsideDownEffect extends OneShotEffect {
TheUpsideDownEffect() {
super(Outcome.Benefit);
}
private TheUpsideDownEffect(final TheUpsideDownEffect effect) {
super(effect);
}
@Override
public TheUpsideDownEffect copy() {
return new TheUpsideDownEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (player == null || card == null) {
return false;
}
player.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent == null) {
return false;
}
String key = TheUpsideDown.makeKey(source, game);
Set<MageObjectReference> morSet;
if (game.getState().getValue(key) != null) {
morSet = (Set<MageObjectReference>) game.getState().getValue(key);
} else {
morSet = new HashSet<>();
game.getState().setValue(key, morSet);
}
morSet.add(new MageObjectReference(permanent, game));
return true;
}
}
class TheUpsideDownLeavesAbility extends TriggeredAbilityImpl {
TheUpsideDownLeavesAbility() {
super(Zone.BATTLEFIELD, new TransformSourceEffect(false));
}
private TheUpsideDownLeavesAbility(final TheUpsideDownLeavesAbility ability) {
super(ability);
}
@Override
public TheUpsideDownLeavesAbility copy() {
return new TheUpsideDownLeavesAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Set<MageObjectReference> morSet = (Set<MageObjectReference>) game.getState().getValue(TheUpsideDown.makeKey(this, game));
return morSet != null
&& !morSet.isEmpty()
&& morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game));
}
@Override
public String getRule() {
return "When the creature put onto the battlefield with {this} leaves the battlefield, transform {this}.";
}
}

View file

@ -380,5 +380,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Panharmonicon", 605, Rarity.RARE, mage.cards.p.Panharmonicon.class));
cards.add(new SetCardInfo("Swiftfoot Boots", 606, Rarity.RARE, mage.cards.s.SwiftfootBoots.class));
cards.add(new SetCardInfo("Rogue's Passage", 607, Rarity.RARE, mage.cards.r.RoguesPassage.class));
cards.add(new SetCardInfo("Hawkins National Laboratory", 609, Rarity.RARE, mage.cards.h.HawkinsNationalLaboratory.class));
cards.add(new SetCardInfo("The Upside Down", 609, Rarity.RARE, mage.cards.t.TheUpsideDown.class));
}
}