[LCI] Implement Bat Colony

This commit is contained in:
Susucre 2023-11-05 13:46:34 +01:00
parent e7a8035e92
commit 05897cba71
2 changed files with 166 additions and 0 deletions

View file

@ -0,0 +1,165 @@
package mage.cards.b;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ManaPaidEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.token.BatToken;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.Copyable;
import mage.watchers.Watcher;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author Susucr
*/
public final class BatColony extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.CAVE, "a Cave you control");
private static final Hint hint = new ValueHint("Mana spent from a Cave", BatColonyValue.instance);
public BatColony(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// When Bat Colony enters the battlefield, create a 1/1 black Bat creature token with flying for each mana from a Cave spent to cast it.
this.addAbility(
new EntersBattlefieldTriggeredAbility(
new CreateTokenEffect(new BatToken(), BatColonyValue.instance)
).addHint(hint),
new BatColonyWatcher()
);
// Whenever a Cave enters the battlefield under your control, put a +1/+1 counter on target creature you control.
Ability ability = new EntersBattlefieldControlledTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance()),
filter
);
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
}
private BatColony(final BatColony card) {
super(card);
}
@Override
public BatColony copy() {
return new BatColony(this);
}
}
enum BatColonyValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return sourceAbility == null ? 0 : BatColonyWatcher.getCaveAmount(sourceAbility.getSourceId(), game);
}
@Override
public BatColonyValue copy() {
return this;
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "";
}
}
/**
* Inspired by {@link mage.watchers.common.ManaPaidSourceWatcher}
* If more cards like Bat Colony care for mana spent by Caves in the future, best to refactor the tracking there.
* For now the assumpting is that it is a 1of, so don't want to track it in any game.
*/
class BatColonyWatcher extends Watcher {
private static final class CaveManaPaidTracker implements Serializable, Copyable<CaveManaPaidTracker> {
private int caveMana = 0;
private CaveManaPaidTracker() {
super();
}
private CaveManaPaidTracker(final CaveManaPaidTracker tracker) {
this.caveMana = tracker.caveMana;
}
@Override
public CaveManaPaidTracker copy() {
return new CaveManaPaidTracker(this);
}
private void increment(MageObject sourceObject, Game game) {
if (sourceObject != null && sourceObject.hasSubtype(SubType.CAVE, game)) {
caveMana++;
}
}
}
private static final CaveManaPaidTracker emptyTracker = new CaveManaPaidTracker();
private final Map<UUID, CaveManaPaidTracker> manaMap = new HashMap<>();
public BatColonyWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
switch (event.getType()) {
case ZONE_CHANGE:
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD
// Bug #9943 Memory Deluge cast from graveyard during the same turn
|| ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
manaMap.remove(event.getTargetId());
}
return;
case MANA_PAID:
ManaPaidEvent manaEvent = (ManaPaidEvent) event;
manaMap.computeIfAbsent(manaEvent.getTargetId(), x -> new CaveManaPaidTracker())
.increment(manaEvent.getSourceObject(), game);
manaMap.computeIfAbsent(manaEvent.getSourcePaidId(), x -> new CaveManaPaidTracker())
.increment(manaEvent.getSourceObject(), game);
}
}
@Override
public void reset() {
super.reset();
manaMap.clear();
}
public static int getCaveAmount(UUID sourceId, Game game) {
BatColonyWatcher watcher = game.getState().getWatcher(BatColonyWatcher.class);
return watcher == null ? 0 : watcher.manaMap.getOrDefault(sourceId, emptyTracker).caveMana;
}
}

View file

@ -55,6 +55,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
cards.add(new SetCardInfo("Attentive Sunscribe", 4, Rarity.COMMON, mage.cards.a.AttentiveSunscribe.class));
cards.add(new SetCardInfo("Bartolome del Presidio", 224, Rarity.UNCOMMON, mage.cards.b.BartolomeDelPresidio.class));
cards.add(new SetCardInfo("Basking Capybara", 175, Rarity.COMMON, mage.cards.b.BaskingCapybara.class));
cards.add(new SetCardInfo("Bat Colony", 5, Rarity.UNCOMMON, mage.cards.b.BatColony.class));
cards.add(new SetCardInfo("Bedrock Tortoise", 176, Rarity.RARE, mage.cards.b.BedrockTortoise.class));
cards.add(new SetCardInfo("Belligerent Yearling", 133, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class));
cards.add(new SetCardInfo("Bitter Triumph", 91, Rarity.UNCOMMON, mage.cards.b.BitterTriumph.class));