From 7481cc96317c84b16f809ebb87eb7be036a51ff5 Mon Sep 17 00:00:00 2001 From: Sean Walsh <40175938+stwalsh4118@users.noreply.github.com> Date: Thu, 2 Mar 2023 20:15:18 -0600 Subject: [PATCH] [40K] Implement Bloodthirster (#10056) --- Mage.Sets/src/mage/cards/b/Bloodthirster.java | 117 ++++++++++++++++++ Mage.Sets/src/mage/sets/Warhammer40000.java | 1 + 2 files changed, 118 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/Bloodthirster.java diff --git a/Mage.Sets/src/mage/cards/b/Bloodthirster.java b/Mage.Sets/src/mage/cards/b/Bloodthirster.java new file mode 100644 index 0000000000..e857da60d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Bloodthirster.java @@ -0,0 +1,117 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.AdditionalCombatPhaseEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +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 @stwalsh4118 + */ +public final class Bloodthirster extends CardImpl { + + public Bloodthirster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Bloodthirster deals combat damage to a player, untap it. After this combat phase, there is an additional combat phase. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new UntapSourceEffect().setText("untap it"), false, true); + ability.addEffect(new AdditionalCombatPhaseEffect("After this combat phase, there is an additional combat phase")); + this.addAbility(ability); + + // Bloodthirster can't attack a player it has already attacked this turn. + this.addAbility(new SimpleStaticAbility(new BloodthirsterEffect()), new BloodthirsterWatcher()); + + } + + private Bloodthirster(final Bloodthirster card) { + super(card); + } + + @Override + public Bloodthirster copy() { + return new Bloodthirster(this); + } +} + +class BloodthirsterEffect extends RestrictionEffect { + + BloodthirsterEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack a player it has already attacked this turn"; + } + + private BloodthirsterEffect(final BloodthirsterEffect effect) { + super(effect); + } + + @Override + public BloodthirsterEffect copy() { + return new BloodthirsterEffect(this); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + BloodthirsterWatcher watcher = game.getState().getWatcher(BloodthirsterWatcher.class); + return watcher != null && watcher.checkAttacker(attacker, defenderId); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } +} + +class BloodthirsterWatcher extends Watcher { + + private final Map> attackMap = new HashMap<>(); + + BloodthirsterWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ATTACKER_DECLARED + || game.getPlayer(event.getTargetId()) == null) { + return; + } + attackMap.computeIfAbsent(event.getSourceId(), x -> new HashSet<>()).add(event.getTargetId()); + } + + @Override + public void reset() { + attackMap.clear(); + super.reset(); + } + + boolean checkAttacker(Permanent permanent, UUID defenderId) { + return !attackMap.computeIfAbsent(permanent.getId(), x -> new HashSet<>()).contains(defenderId); + } +} diff --git a/Mage.Sets/src/mage/sets/Warhammer40000.java b/Mage.Sets/src/mage/sets/Warhammer40000.java index 5bfc4a06cc..628464afef 100644 --- a/Mage.Sets/src/mage/sets/Warhammer40000.java +++ b/Mage.Sets/src/mage/sets/Warhammer40000.java @@ -52,6 +52,7 @@ public final class Warhammer40000 extends ExpansionSet { cards.add(new SetCardInfo("Blight Grenade", 31, Rarity.RARE, mage.cards.b.BlightGrenade.class)); cards.add(new SetCardInfo("Blood for the Blood God!", 108, Rarity.RARE, mage.cards.b.BloodForTheBloodGod.class)); cards.add(new SetCardInfo("Bloodcrusher of Khorne", 72, Rarity.UNCOMMON, mage.cards.b.BloodcrusherOfKhorne.class)); + cards.add(new SetCardInfo("Bloodthirster", 73, Rarity.RARE, mage.cards.b.Bloodthirster.class)); cards.add(new SetCardInfo("Bone Sabres", 88, Rarity.RARE, mage.cards.b.BoneSabres.class)); cards.add(new SetCardInfo("Brainstorm", 192, Rarity.COMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Bred for the Hunt", 222, Rarity.UNCOMMON, mage.cards.b.BredForTheHunt.class));