diff --git a/Mage.Sets/src/mage/cards/b/BroodcallerScourge.java b/Mage.Sets/src/mage/cards/b/BroodcallerScourge.java index 4a8145bbece..953fe67658f 100644 --- a/Mage.Sets/src/mage/cards/b/BroodcallerScourge.java +++ b/Mage.Sets/src/mage/cards/b/BroodcallerScourge.java @@ -69,8 +69,7 @@ enum BroodcallerScourgePredicate implements ObjectSourcePlayerPredicate { .getManaValue() <= CardUtil .getEffectValueFromAbility( - input.getSource(), "damage", - Integer.class, 0 - ); + input.getSource(), "damage", Integer.class + ).orElse(0); } } diff --git a/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java b/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java new file mode 100644 index 00000000000..e79e460bb93 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java @@ -0,0 +1,103 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterHistoricCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HaviTheAllFather extends CardImpl { + + private static final Condition condition = new CardsInControllerGraveyardCondition( + 4, new FilterHistoricCard("historic cards") + ); + private static final Hint hint = new ValueHint( + "Historic cards in your graveyard", new CardsInControllerGraveyardCount(new FilterHistoricCard()) + ); + private static final FilterCard filter = new FilterCreatureCard("legendary creature card with lesser mana value from your graveyard"); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + filter.add(HaviTheAllFatherPredicate.instance); + } + + public HaviTheAllFather(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.GOD); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Havi, the All-Father has indestructible as long as there are four or more historic cards in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), condition, + "{this} has indestructible as long as there are four or more historic cards in your graveyard" + )).addHint(hint)); + + // Sage Project -- Whenever Havi or another legendary creature you control dies, return target legendary creature card with lesser mana value from your graveyard to the battlefield tapped. + Ability ability = new DiesThisOrAnotherTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(true), + false, StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability.withFlavorWord("Sage Project")); + } + + private HaviTheAllFather(final HaviTheAllFather card) { + super(card); + } + + @Override + public HaviTheAllFather copy() { + return new HaviTheAllFather(this); + } +} + +enum HaviTheAllFatherPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input + .getObject() + .getManaValue() + < CardUtil + .getEffectValueFromAbility( + input.getSource(), "creatureDied", Permanent.class + ) + .map(MageObject::getManaValue) + .orElse(0); + } +} diff --git a/Mage.Sets/src/mage/sets/AssassinsCreed.java b/Mage.Sets/src/mage/sets/AssassinsCreed.java index 233facd2f17..76ce1d51546 100644 --- a/Mage.Sets/src/mage/sets/AssassinsCreed.java +++ b/Mage.Sets/src/mage/sets/AssassinsCreed.java @@ -152,9 +152,9 @@ public final class AssassinsCreed extends ExpansionSet { cards.add(new SetCardInfo("Forest", 110, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Go for the Throat", 205, Rarity.UNCOMMON, mage.cards.g.GoForTheThroat.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Go for the Throat", 91, Rarity.UNCOMMON, mage.cards.g.GoForTheThroat.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Havi, the All-Father", 146, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Havi, the All-Father", 237, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Havi, the All-Father", 56, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Havi, the All-Father", 146, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Havi, the All-Father", 237, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Havi, the All-Father", 56, Rarity.RARE, mage.cards.h.HaviTheAllFather.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Haystack", 175, Rarity.UNCOMMON, mage.cards.h.Haystack.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Haystack", 5, Rarity.UNCOMMON, mage.cards.h.Haystack.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Haytham Kenway", 57, Rarity.RARE, mage.cards.h.HaythamKenway.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java index e55160ee720..c540d95db44 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java @@ -61,8 +61,12 @@ public class DiesThisOrAnotherTriggeredAbility extends TriggeredAbilityImpl { return false; } // TODO: remove applyFilterOnSource workaround for Basri's Lieutenant - return ((!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) - || filter.match(zEvent.getTarget(), getControllerId(), this, game)); + if ((applyFilterOnSource || !zEvent.getTarget().getId().equals(this.getSourceId())) + && !filter.match(zEvent.getTarget(), getControllerId(), this, game)) { + return false; + } + this.getEffects().setValue("creatureDied", zEvent.getTarget()); + return true; } @Override diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index e7bb1732f4d..5bc55367adc 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1131,10 +1131,10 @@ public final class CardUtil { * Also ensures that spells/abilities that target the same object twice only trigger each "becomes the target" ability once. * If this is the first attempt at triggering for a given ability targeting a given object, * this method records that in the game state for later checks by this same method, to not return the same object again. - * + * * @param checkingReference must be unique for each usage (this.getId().toString() of the TriggeredAbility, or this.getKey() of the watcher) - * @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch() - * @param game the Game from checkTrigger() or watch() + * @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch() + * @param game the Game from checkTrigger() or watch() * @return the StackObject which targeted the source, or null if already used or not found */ public static StackObject findTargetingStackObject(String checkingReference, GameEvent event, Game game) { @@ -2213,17 +2213,13 @@ public final class CardUtil { return sb.toString(); } - public static T getEffectValueFromAbility(Ability ability, String key, Class clazz) { - return getEffectValueFromAbility(ability, key, clazz, null); - } - - public static T getEffectValueFromAbility(Ability ability, String key, Class clazz, T defaultValue) { + public static Optional getEffectValueFromAbility(Ability ability, String key, Class clazz) { return castStream( ability.getAllEffects() .stream() .map(effect -> effect.getValue(key)), clazz - ).findFirst().orElse(defaultValue); + ).findFirst(); } public static Stream castStream(Collection collection, Class clazz) {