[LCI] Implement Subterranean Schooner

This commit is contained in:
theelk801 2023-11-05 10:15:17 -05:00
parent 0e3c31ca7b
commit e4ae0f6df5
5 changed files with 141 additions and 97 deletions

View file

@ -1,7 +1,6 @@
package mage.cards.g;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.AttacksOrBlocksTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
@ -10,29 +9,26 @@ import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.CrewedSourceThisTurnPredicate;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.TargetAdjuster;
import mage.util.CardUtil;
import mage.watchers.Watcher;
import mage.watchers.common.CrewedVehicleWatcher;
import java.util.*;
import java.util.stream.Collectors;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class GetawayCar extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("creature that crewed it this turn");
static {
filter.add(CrewedSourceThisTurnPredicate.instance);
}
public GetawayCar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
@ -44,11 +40,9 @@ public final class GetawayCar extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// Whenever Getaway Car attacks or blocks, return up to one target creature that crewed it this turn to its owner's hand.
this.addAbility(new AttacksOrBlocksTriggeredAbility(
new ReturnToHandTargetEffect()
.setText("return up to one target creature that crewed it this turn to its owner's hand"),
false
).setTargetAdjuster(GetawayCarAdjuster.instance), new GetawayCarWatcher());
Ability ability = new AttacksOrBlocksTriggeredAbility(new ReturnToHandTargetEffect(), false);
ability.addTarget(new TargetPermanent(0, 1, filter));
this.addAbility(ability, new CrewedVehicleWatcher());
// Crew 1
this.addAbility(new CrewAbility(1));
@ -63,81 +57,3 @@ public final class GetawayCar extends CardImpl {
return new GetawayCar(this);
}
}
enum GetawayCarAdjuster implements TargetAdjuster {
instance;
@Override
public void adjustTargets(Ability ability, Game game) {
ability.getTargets().clear();
ability.addTarget(new TargetPermanent(
0, 1, GetawayCarWatcher.makeFilter(ability, game)
));
}
}
class GetawayCarWatcher extends Watcher {
private final Map<MageObjectReference, Set<MageObjectReference>> crewMap = new HashMap<>();
private static final FilterPermanent invalidFilter = new FilterPermanent();
static {
invalidFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, -2));
}
GetawayCarWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
Permanent vehicle;
Permanent crewer;
switch (event.getType()) {
case VEHICLE_CREWED:
vehicle = game.getPermanent(event.getTargetId());
crewer = null;
break;
case CREWED_VEHICLE:
vehicle = game.getPermanent(event.getSourceId());
crewer = game.getPermanent(event.getTargetId());
break;
default:
return;
}
if (vehicle == null) {
return;
}
crewMap.computeIfAbsent(
new MageObjectReference(vehicle, game), x -> new HashSet<>()
).add(new MageObjectReference(crewer, game));
}
@Override
public void reset() {
super.reset();
crewMap.clear();
}
public static FilterPermanent makeFilter(Ability source, Game game) {
Set<MageObjectReferencePredicate> predicates = game
.getState()
.getWatcher(GetawayCarWatcher.class)
.crewMap
.computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>())
.stream()
.filter(mor -> {
Permanent permanent = mor.getPermanent(game);
return permanent != null && permanent.isCreature(game);
}).map(MageObjectReferencePredicate::new)
.collect(Collectors.toSet());
if (predicates.isEmpty()) {
return invalidFilter;
}
FilterPermanent filterPermanent = new FilterPermanent(
"creature that crewed " + CardUtil.getSourceName(game, source) + " this turn"
);
filterPermanent.add(Predicates.or(predicates));
return filterPermanent;
}
}

View file

@ -0,0 +1,55 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.keyword.ExploreTargetEffect;
import mage.abilities.keyword.CrewAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.CrewedSourceThisTurnPredicate;
import mage.target.TargetPermanent;
import mage.watchers.common.CrewedVehicleWatcher;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SubterraneanSchooner extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("creature that crewed it this turn");
static {
filter.add(CrewedSourceThisTurnPredicate.instance);
}
public SubterraneanSchooner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}");
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// Whenever Subterranean Schooner attacks, target creature that crewed it this turn explores.
Ability ability = new AttacksTriggeredAbility(new ExploreTargetEffect());
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability, new CrewedVehicleWatcher());
// Crew 1
this.addAbility(new CrewAbility(1));
}
private SubterraneanSchooner(final SubterraneanSchooner card) {
super(card);
}
@Override
public SubterraneanSchooner copy() {
return new SubterraneanSchooner(this);
}
}

View file

@ -284,6 +284,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
cards.add(new SetCardInfo("Starving Revenant", 123, Rarity.RARE, mage.cards.s.StarvingRevenant.class));
cards.add(new SetCardInfo("Staunch Crewmate", 79, Rarity.UNCOMMON, mage.cards.s.StaunchCrewmate.class));
cards.add(new SetCardInfo("Stinging Cave Crawler", 124, Rarity.UNCOMMON, mage.cards.s.StingingCaveCrawler.class));
cards.add(new SetCardInfo("Subterranean Schooner", 80, Rarity.RARE, mage.cards.s.SubterraneanSchooner.class));
cards.add(new SetCardInfo("Sunbird Effigy", 262, Rarity.UNCOMMON, mage.cards.s.SunbirdEffigy.class));
cards.add(new SetCardInfo("Sunbird Standard", 262, Rarity.UNCOMMON, mage.cards.s.SunbirdStandard.class));
cards.add(new SetCardInfo("Sunfire Torch", 167, Rarity.COMMON, mage.cards.s.SunfireTorch.class));

View file

@ -0,0 +1,26 @@
package mage.filter.predicate.permanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.watchers.common.CrewedVehicleWatcher;
/**
* @author TheElk801
*/
public enum CrewedSourceThisTurnPredicate implements ObjectSourcePlayerPredicate<Permanent> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
return CrewedVehicleWatcher.checkIfCrewedThisTurn(
input.getObject(), input.getSource().getSourcePermanentOrLKI(game), game
);
}
@Override
public String toString() {
return "crewed {this} this turn";
}
}

View file

@ -0,0 +1,46 @@
package mage.watchers.common;
import mage.MageObjectReference;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
import java.util.*;
/**
* @author TheElk801
*/
public class CrewedVehicleWatcher extends Watcher {
private final Map<MageObjectReference, Set<MageObjectReference>> crewMap = new HashMap<>();
public CrewedVehicleWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.CREWED_VEHICLE) {
crewMap.computeIfAbsent(new MageObjectReference(event.getSourceId(), game), x -> new HashSet<>())
.add(new MageObjectReference(event.getTargetId(), game));
}
}
@Override
public void reset() {
super.reset();
crewMap.clear();
}
public static boolean checkIfCrewedThisTurn(Permanent crewer, Permanent crewed, Game game) {
return game
.getState()
.getWatcher(CrewedVehicleWatcher.class)
.crewMap
.getOrDefault(new MageObjectReference(crewed, game), Collections.emptySet())
.stream()
.anyMatch(mor -> mor.refersTo(crewer, game));
}
}