diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfMight.java b/Mage.Sets/src/mage/cards/a/AvatarOfMight.java
index c35a03c79b..d051a3174d 100644
--- a/Mage.Sets/src/mage/cards/a/AvatarOfMight.java
+++ b/Mage.Sets/src/mage/cards/a/AvatarOfMight.java
@@ -1,27 +1,30 @@
-
 package mage.cards.a;
 
-import java.util.UUID;
 import mage.MageInt;
-import mage.Mana;
 import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.condition.Condition;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
+import mage.abilities.hint.ConditionHint;
 import mage.abilities.keyword.TrampleAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
 import mage.filter.StaticFilters;
 import mage.game.Game;
 import mage.players.Player;
 
+import java.util.UUID;
+
 /**
- *
  * @author LevelX2
  */
 public final class AvatarOfMight extends CardImpl {
 
+    private static final Condition condition = new AvatarOfMightCondition();
+
     public AvatarOfMight(UUID ownerId, CardSetInfo setInfo) {
         super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}{G}");
         this.subtype.add(SubType.AVATAR);
@@ -29,7 +32,10 @@ public final class AvatarOfMight extends CardImpl {
         this.toughness = new MageInt(8);
 
         // If an opponent controls at least four more creatures than you, Avatar of Might costs {6} less to cast.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfMightCostReductionEffect()));
+        this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(6, condition)
+                .setText("If an opponent controls at least four more creatures than you, {this} costs {6} less to cast"))
+                .addHint(new ConditionHint(condition, "Opponent controls at least four more creatures than you"))
+        );
 
         // Trample
         this.addAbility(TrampleAbility.getInstance());
@@ -45,49 +51,17 @@ public final class AvatarOfMight extends CardImpl {
     }
 }
 
-class AvatarOfMightCostReductionEffect extends CostModificationEffectImpl {
-
-    AvatarOfMightCostReductionEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "If an opponent controls at least four more creatures than you, {this} costs {6} less to cast";
-    }
-
-    AvatarOfMightCostReductionEffect(final AvatarOfMightCostReductionEffect effect) {
-        super(effect);
-    }
+class AvatarOfMightCondition implements Condition {
 
     @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            int newCount = mana.getGeneric() - 6;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        if (abilityToModify.getSourceId().equals(source.getSourceId()) && (abilityToModify instanceof SpellAbility)) {
-            int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game);
-            for (UUID playerId : game.getOpponents(source.getControllerId())) {
-                Player opponent = game.getPlayer(playerId);
-                if (opponent != null && game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) >= creatures + 4) {
-                    return true;
-                }
+    public boolean apply(Game game, Ability source) {
+        int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game);
+        for (UUID playerId : game.getOpponents(source.getControllerId())) {
+            Player opponent = game.getPlayer(playerId);
+            if (opponent != null && game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) >= creatures + 4) {
+                return true;
             }
         }
         return false;
     }
-
-    @Override
-    public AvatarOfMightCostReductionEffect copy() {
-        return new AvatarOfMightCostReductionEffect(this);
-    }
 }
diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfWill.java b/Mage.Sets/src/mage/cards/a/AvatarOfWill.java
index c57877756a..d67fb66059 100644
--- a/Mage.Sets/src/mage/cards/a/AvatarOfWill.java
+++ b/Mage.Sets/src/mage/cards/a/AvatarOfWill.java
@@ -1,22 +1,20 @@
-
 package mage.cards.a;
 
-import java.util.UUID;
 import mage.MageInt;
-import mage.Mana;
-import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.condition.common.OpponentHasNoCardsInHandCondition;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
+import mage.abilities.hint.ConditionHint;
 import mage.abilities.keyword.FlyingAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
-import mage.game.Game;
-import mage.players.Player;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
+
+import java.util.UUID;
 
 /**
- *
  * @author LevelX2
  */
 public final class AvatarOfWill extends CardImpl {
@@ -28,7 +26,10 @@ public final class AvatarOfWill extends CardImpl {
         this.toughness = new MageInt(6);
 
         // If an opponent has no cards in hand, Avatar of Will costs {6} less to cast.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfWillCostReductionEffect()));
+        this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(6, OpponentHasNoCardsInHandCondition.instance)
+                        .setText("If an opponent has no cards in hand, Avatar of Will costs {6} less to cast")
+                ).addHint(new ConditionHint(OpponentHasNoCardsInHandCondition.instance, "Opponent has no cards in hand"))
+        );
 
         // Flying
         this.addAbility(FlyingAbility.getInstance());
@@ -43,49 +44,3 @@ public final class AvatarOfWill extends CardImpl {
         return new AvatarOfWill(this);
     }
 }
-
-class AvatarOfWillCostReductionEffect extends CostModificationEffectImpl {
-
-    AvatarOfWillCostReductionEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "If an opponent has no cards in hand, {this} costs {6} less to cast";
-    }
-
-    AvatarOfWillCostReductionEffect(final AvatarOfWillCostReductionEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            int newCount = mana.getGeneric() - 6;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        if (abilityToModify.getSourceId().equals(source.getSourceId())) {
-            for (UUID playerId : game.getOpponents(source.getControllerId())) {
-                Player opponent = game.getPlayer(playerId);
-                if (opponent != null && opponent.getHand().isEmpty()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public AvatarOfWillCostReductionEffect copy() {
-        return new AvatarOfWillCostReductionEffect(this);
-    }
-}
diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java
index 02115afba8..70911593e4 100644
--- a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java
+++ b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java
@@ -1,30 +1,36 @@
 package mage.cards.a;
 
-import java.util.UUID;
 import mage.MageInt;
-import mage.Mana;
 import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleActivatedAbility;
 import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
 import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.dynamicvalue.DynamicValue;
 import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
 import mage.abilities.effects.common.DestroyTargetEffect;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
+import mage.abilities.hint.ValueHint;
 import mage.abilities.keyword.FearAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
 import mage.filter.StaticFilters;
 import mage.game.Game;
 import mage.target.common.TargetCreaturePermanent;
 
+import java.util.UUID;
+
 /**
- *
  * @author emerald000
  */
 public final class AvatarOfWoe extends CardImpl {
 
+    protected static final DynamicValue graveyardCount = new CardsInAllGraveyardsCount(StaticFilters.FILTER_CARD_CREATURE);
+    private static final Condition condition = new AvatarOfWoeCondition();
+
     public AvatarOfWoe(UUID ownerId, CardSetInfo setInfo) {
         super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}{B}");
         this.subtype.add(SubType.AVATAR);
@@ -32,12 +38,15 @@ public final class AvatarOfWoe extends CardImpl {
         this.toughness = new MageInt(5);
 
         // If there are ten or more creature cards total in all graveyards, Avatar of Woe costs {6} less to cast.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfWoeCostReductionEffect()));
+        this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(6, condition)
+                .setText("If there are ten or more creature cards total in all graveyards, {this} costs {6} less to cast"))
+                .addHint(new ValueHint("Creature cards in all graveyards", graveyardCount))
+        );
 
         // Fear
         this.addAbility(FearAbility.getInstance());
 
-        // {tap}: Destroy target creature. It can't be regenerated.
+        // {T}: Destroy target creature. It can't be regenerated.
         Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(true), new TapSourceCost());
         ability.addTarget(new TargetCreaturePermanent());
         this.addAbility(ability);
@@ -53,42 +62,13 @@ public final class AvatarOfWoe extends CardImpl {
     }
 }
 
-class AvatarOfWoeCostReductionEffect extends CostModificationEffectImpl {
-
-    AvatarOfWoeCostReductionEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "If there are ten or more creature cards total in all graveyards, {this} costs {6} less to cast";
-    }
-
-    AvatarOfWoeCostReductionEffect(final AvatarOfWoeCostReductionEffect effect) {
-        super(effect);
-    }
+class AvatarOfWoeCondition implements Condition {
 
     @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            int newCount = mana.getGeneric() - 6;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
+    public boolean apply(Game game, Ability source) {
+        if (AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10) {
             return true;
         }
         return false;
     }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        return abilityToModify.getSourceId().equals(source.getSourceId())
-                && (abilityToModify instanceof SpellAbility)
-                && new CardsInAllGraveyardsCount(StaticFilters.FILTER_CARD_CREATURE).calculate(game, source, this) >= 10;
-    }
-
-    @Override
-    public AvatarOfWoeCostReductionEffect copy() {
-        return new AvatarOfWoeCostReductionEffect(this);
-    }
 }
diff --git a/Mage.Sets/src/mage/cards/d/DaybreakChimera.java b/Mage.Sets/src/mage/cards/d/DaybreakChimera.java
index 7b6d0c1bb0..b8035bf7db 100644
--- a/Mage.Sets/src/mage/cards/d/DaybreakChimera.java
+++ b/Mage.Sets/src/mage/cards/d/DaybreakChimera.java
@@ -1,17 +1,15 @@
 package mage.cards.d;
 
 import mage.MageInt;
-import mage.Mana;
-import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
 import mage.abilities.dynamicvalue.common.DevotionCount;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
 import mage.abilities.keyword.FlyingAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
-import mage.game.Game;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
 
 import java.util.UUID;
 
@@ -28,7 +26,9 @@ public final class DaybreakChimera extends CardImpl {
         this.toughness = new MageInt(3);
 
         // This spell costs {X} less to cast, where X is your devotion to white.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new DaybreakChimeraEffect()).addHint(DevotionCount.W.getHint()));
+        this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(DevotionCount.W))
+                .addHint(DevotionCount.W.getHint())
+        );
 
         // Flying
         this.addAbility(FlyingAbility.getInstance());
@@ -43,40 +43,3 @@ public final class DaybreakChimera extends CardImpl {
         return new DaybreakChimera(this);
     }
 }
-
-class DaybreakChimeraEffect extends CostModificationEffectImpl {
-
-    DaybreakChimeraEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "This spell costs {X} less to cast, where X is your devotion to white. " +
-                "<i>(Each {W} in the mana costs of permanents you control counts toward your devotion to white.)</i>";
-    }
-
-    private DaybreakChimeraEffect(final DaybreakChimeraEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() == 0) {
-            return false;
-        }
-        int count = DevotionCount.W.calculate(game, source, this);
-        mana.setGeneric(Math.max(mana.getGeneric() - count, 0));
-        spellAbility.getManaCostsToPay().load(mana.toString());
-        return true;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        return abilityToModify instanceof SpellAbility
-                && abilityToModify.getSourceId().equals(source.getSourceId());
-    }
-
-    @Override
-    public DaybreakChimeraEffect copy() {
-        return new DaybreakChimeraEffect(this);
-    }
-}
diff --git a/Mage.Sets/src/mage/cards/d/DragToTheUnderworld.java b/Mage.Sets/src/mage/cards/d/DragToTheUnderworld.java
index a569e15e87..bc91ad64c3 100644
--- a/Mage.Sets/src/mage/cards/d/DragToTheUnderworld.java
+++ b/Mage.Sets/src/mage/cards/d/DragToTheUnderworld.java
@@ -1,16 +1,13 @@
 package mage.cards.d;
 
-import mage.Mana;
-import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
 import mage.abilities.dynamicvalue.common.DevotionCount;
 import mage.abilities.effects.common.DestroyTargetEffect;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
-import mage.game.Game;
+import mage.constants.CardType;
+import mage.constants.Zone;
 import mage.target.common.TargetCreaturePermanent;
 
 import java.util.UUID;
@@ -24,7 +21,7 @@ public final class DragToTheUnderworld extends CardImpl {
         super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}{B}");
 
         // This spell costs {X} less to cast, where X is your devotion to black.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new DragToTheUnderworldEffect())
+        this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(DevotionCount.B))
                 .addHint(DevotionCount.B.getHint())
                 .setRuleAtTheTop(true));
 
@@ -41,41 +38,4 @@ public final class DragToTheUnderworld extends CardImpl {
     public DragToTheUnderworld copy() {
         return new DragToTheUnderworld(this);
     }
-}
-
-class DragToTheUnderworldEffect extends CostModificationEffectImpl {
-
-    DragToTheUnderworldEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "This spell costs {X} less to cast, where X is your devotion to black. " +
-                "<i>(Each {B} in the mana costs of permanents you control counts toward your devotion to black.)</i> ";
-    }
-
-    private DragToTheUnderworldEffect(final DragToTheUnderworldEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() == 0) {
-            return false;
-        }
-        int count = DevotionCount.B.calculate(game, source, this);
-        mana.setGeneric(Math.max(mana.getGeneric() - count, 0));
-        spellAbility.getManaCostsToPay().load(mana.toString());
-        return true;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        return abilityToModify instanceof SpellAbility
-                && abilityToModify.getSourceId().equals(source.getSourceId());
-    }
-
-    @Override
-    public DragToTheUnderworldEffect copy() {
-        return new DragToTheUnderworldEffect(this);
-    }
-}
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/d/DuskFeaster.java b/Mage.Sets/src/mage/cards/d/DuskFeaster.java
index 8d586d0640..4075027397 100644
--- a/Mage.Sets/src/mage/cards/d/DuskFeaster.java
+++ b/Mage.Sets/src/mage/cards/d/DuskFeaster.java
@@ -1,36 +1,38 @@
-
 package mage.cards.d;
 
-import java.util.EnumSet;
-import java.util.UUID;
 import mage.MageInt;
-import mage.Mana;
 import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.condition.common.DeliriumCondition;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
+import mage.abilities.hint.common.DeliriumHint;
 import mage.abilities.keyword.FlyingAbility;
-import mage.cards.Card;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
-import mage.game.Game;
-import mage.players.Player;
+import mage.constants.AbilityWord;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
+
+import java.util.UUID;
 
 /**
- *
  * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
  */
 public final class DuskFeaster extends CardImpl {
 
     public DuskFeaster(UUID ownerId, CardSetInfo setInfo) {
-        super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{B}");
+        super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
         this.subtype.add(SubType.VAMPIRE);
         this.power = new MageInt(4);
         this.toughness = new MageInt(5);
 
-        // Delirium - Dusk Feaster costs {2} less to cast if there are four or more card types among cards in your graveyard.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new DuskFeasterCostReductionEffect()));
+        // <i>Delirium</i> &mdash; This spell costs {2} less to cast if there are four or more card types among cards in your graveyard.
+        Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(2, DeliriumCondition.instance));
+        ability.setRuleAtTheTop(true);
+        ability.setAbilityWord(AbilityWord.DELIRIUM);
+        ability.addHint(DeliriumHint.instance);
+        this.addAbility(ability);
 
         // Flying
         this.addAbility(FlyingAbility.getInstance());
@@ -44,56 +46,4 @@ public final class DuskFeaster extends CardImpl {
     public DuskFeaster copy() {
         return new DuskFeaster(this);
     }
-}
-
-class DuskFeasterCostReductionEffect extends CostModificationEffectImpl {
-
-    DuskFeasterCostReductionEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "<i>Delirium</i> &mdash; {this} costs {2} less to cast if there are four or more card types among cards in your graveyard";
-    }
-
-    DuskFeasterCostReductionEffect(final DuskFeasterCostReductionEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            int newCount = mana.getGeneric() - 2;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-
-        boolean hasDelirium = false;
-        Player controller = game.getPlayer(source.getControllerId());
-        if (controller != null) {
-            EnumSet<CardType> foundCardTypes = EnumSet.noneOf(CardType.class);
-            for (Card card : controller.getGraveyard().getCards(game)) {
-                foundCardTypes.addAll(card.getCardType());
-            }
-            int number = foundCardTypes.size();
-            hasDelirium = number > 3;
-        }
-
-        return abilityToModify.getSourceId().equals(source.getSourceId())
-                && (abilityToModify instanceof SpellAbility)
-                && hasDelirium;
-    }
-
-    @Override
-    public DuskFeasterCostReductionEffect copy() {
-        return new DuskFeasterCostReductionEffect(this);
-    }
 }
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java
index b350bc7107..30468d663c 100644
--- a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java
+++ b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java
@@ -1,7 +1,5 @@
-
 package mage.cards.g;
 
-import java.util.UUID;
 import mage.MageInt;
 import mage.abilities.Ability;
 import mage.abilities.common.SimpleActivatedAbility;
@@ -16,14 +14,15 @@ import mage.filter.common.FilterControlledPermanent;
 import mage.game.Game;
 import mage.util.CardUtil;
 
+import java.util.UUID;
+
 /**
- *
  * @author LevelX2
  */
 public final class GearseekerSerpent extends CardImpl {
 
     public GearseekerSerpent(UUID ownerId, CardSetInfo setInfo) {
-        super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}{U}");
+        super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
         this.subtype.add(SubType.SERPENT);
         this.power = new MageInt(5);
         this.toughness = new MageInt(6);
@@ -70,7 +69,6 @@ class GearseekerSerpentCostReductionEffect extends CostModificationEffectImpl {
         if (count > 0) {
             CardUtil.reduceCost(abilityToModify, count);
         }
-
         return true;
     }
 
diff --git a/Mage.Sets/src/mage/cards/m/MarshmistTitan.java b/Mage.Sets/src/mage/cards/m/MarshmistTitan.java
index a3c86710c0..8c380f606e 100644
--- a/Mage.Sets/src/mage/cards/m/MarshmistTitan.java
+++ b/Mage.Sets/src/mage/cards/m/MarshmistTitan.java
@@ -1,16 +1,15 @@
 package mage.cards.m;
 
 import mage.MageInt;
-import mage.Mana;
 import mage.abilities.Ability;
-import mage.abilities.SpellAbility;
 import mage.abilities.common.SimpleStaticAbility;
 import mage.abilities.dynamicvalue.common.DevotionCount;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
-import mage.constants.*;
-import mage.game.Game;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
 
 import java.util.UUID;
 
@@ -26,9 +25,11 @@ public final class MarshmistTitan extends CardImpl {
         this.power = new MageInt(4);
         this.toughness = new MageInt(5);
 
-        // Marshmist Titan costs {X} less to cast, where X is your devotion to black.
-        this.addAbility(new SimpleStaticAbility(Zone.ALL, new MarshmistTitanCostReductionEffect())
-                .addHint(DevotionCount.B.getHint()));
+        // This spell costs {X} less to cast, where X is your devotion to black.
+        Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(DevotionCount.B));
+        ability.addHint(DevotionCount.B.getHint());
+        this.addAbility(ability);
+
     }
 
     private MarshmistTitan(final MarshmistTitan card) {
@@ -40,40 +41,3 @@ public final class MarshmistTitan extends CardImpl {
         return new MarshmistTitan(this);
     }
 }
-
-class MarshmistTitanCostReductionEffect extends CostModificationEffectImpl {
-
-    MarshmistTitanCostReductionEffect() {
-        super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        staticText = "This spell costs {X} less to cast, where X is your devotion to black. " +
-                "<i>(Each {B} in the mana costs of permanents you control counts toward your devotion to black.)</i> ";
-    }
-
-    private MarshmistTitanCostReductionEffect(final MarshmistTitanCostReductionEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() == 0) {
-            return false;
-        }
-        int count = DevotionCount.B.calculate(game, source, this);
-        mana.setGeneric(Math.max(mana.getGeneric() - count, 0));
-        spellAbility.getManaCostsToPay().load(mana.toString());
-        return true;
-    }
-
-    @Override
-    public boolean applies(Ability abilityToModify, Ability source, Game game) {
-        return abilityToModify instanceof SpellAbility
-                && abilityToModify.getSourceId().equals(source.getSourceId());
-    }
-
-    @Override
-    public MarshmistTitanCostReductionEffect copy() {
-        return new MarshmistTitanCostReductionEffect(this);
-    }
-}
diff --git a/Mage.Sets/src/mage/cards/r/RekindledFlame.java b/Mage.Sets/src/mage/cards/r/RekindledFlame.java
index b294ef6821..a5592bde47 100644
--- a/Mage.Sets/src/mage/cards/r/RekindledFlame.java
+++ b/Mage.Sets/src/mage/cards/r/RekindledFlame.java
@@ -1,30 +1,26 @@
-
 package mage.cards.r;
 
-import java.util.UUID;
 import mage.abilities.Ability;
 import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
-import mage.abilities.condition.Condition;
+import mage.abilities.condition.common.OpponentHasNoCardsInHandCondition;
 import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
 import mage.abilities.effects.common.DamageTargetEffect;
 import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect;
+import mage.abilities.hint.ConditionHint;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
 import mage.constants.CardType;
 import mage.constants.TargetController;
 import mage.constants.Zone;
-import mage.game.Game;
-import mage.players.Player;
 import mage.target.common.TargetAnyTarget;
 
+import java.util.UUID;
+
 /**
- *
  * @author jeffwadsworth
  */
 public final class RekindledFlame extends CardImpl {
 
-    static final String rule = "if an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand";
-
     public RekindledFlame(UUID ownerId, CardSetInfo setInfo) {
         super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{R}");
 
@@ -34,10 +30,10 @@ public final class RekindledFlame extends CardImpl {
 
         // At the beginning of your upkeep, if an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand.
         Ability ability = new ConditionalInterveningIfTriggeredAbility(
-                new BeginningOfUpkeepTriggeredAbility(
-                        Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), TargetController.YOU, true
-                ),
-                new OpponentHasNoCardsInHandCondition(), rule);
+                new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), TargetController.YOU, true),
+                OpponentHasNoCardsInHandCondition.instance,
+                "If an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand.");
+        ability.addHint(new ConditionHint(OpponentHasNoCardsInHandCondition.instance, "Opponent has no cards in hand"));
         ability.setRuleVisible(true);
         this.addAbility(ability);
 
@@ -51,21 +47,4 @@ public final class RekindledFlame extends CardImpl {
     public RekindledFlame copy() {
         return new RekindledFlame(this);
     }
-}
-
-class OpponentHasNoCardsInHandCondition implements Condition {
-
-    @Override
-    public boolean apply(Game game, Ability source) {
-        Player player = game.getPlayer(source.getControllerId());
-        if (player != null) {
-            for (UUID playerId : game.getOpponents(source.getControllerId())) {
-                Player opponent = game.getPlayer(playerId);
-                if (opponent != null && opponent.getHand().isEmpty()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-}
+}
\ No newline at end of file
diff --git a/Mage/src/main/java/mage/abilities/condition/common/OpponentHasNoCardsInHandCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OpponentHasNoCardsInHandCondition.java
new file mode 100644
index 0000000000..3eaed97bd9
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/condition/common/OpponentHasNoCardsInHandCondition.java
@@ -0,0 +1,36 @@
+package mage.abilities.condition.common;
+
+import mage.abilities.Ability;
+import mage.abilities.condition.Condition;
+import mage.game.Game;
+import mage.players.Player;
+
+import java.util.UUID;
+
+/**
+ * @author JayDi85
+ */
+
+public enum OpponentHasNoCardsInHandCondition implements Condition {
+
+    instance;
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        Player player = game.getPlayer(source.getControllerId());
+        if (player != null) {
+            for (UUID playerId : game.getOpponents(source.getControllerId())) {
+                Player opponent = game.getPlayer(playerId);
+                if (opponent != null && opponent.getHand().isEmpty()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "an opponent has no cards in hand";
+    }
+}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java
index f3d6e14290..617a18934e 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java
@@ -1,6 +1,5 @@
 package mage.abilities.effects.common;
 
-import mage.Mana;
 import mage.abilities.Ability;
 import mage.abilities.SpellAbility;
 import mage.abilities.effects.common.cost.CostModificationEffectImpl;
@@ -9,9 +8,10 @@ import mage.constants.Duration;
 import mage.constants.Outcome;
 import mage.filter.common.FilterControlledPermanent;
 import mage.game.Game;
+import mage.util.CardUtil;
 
 public class AffinityEffect extends CostModificationEffectImpl {
-    
+
     private final FilterControlledPermanent filter;
 
     public AffinityEffect(FilterControlledPermanent affinityFilter) {
@@ -27,20 +27,12 @@ public class AffinityEffect extends CostModificationEffectImpl {
 
     @Override
     public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility)abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            // the following works with Sen Triplets and in multiplayer games
-            int count = game.getBattlefield().getActivePermanents(filter, abilityToModify.getControllerId(), source.getId(), game).size();
-            int newCount = mana.getGeneric() - count;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
-            return true;
+        // abilityToModify.getControllerId() works with Sen Triplets and in multiplayer games, see https://github.com/magefree/mage/issues/5931
+        int count = game.getBattlefield().getActivePermanents(filter, abilityToModify.getControllerId(), source.getId(), game).size();
+        if (count > 0) {
+            CardUtil.reduceCost(abilityToModify, count);
         }
-        return false;
+        return true;
     }
 
     @Override
diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java
index e280df5a06..0f535c1a7f 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java
@@ -5,6 +5,8 @@ import mage.abilities.SpellAbility;
 import mage.abilities.condition.Condition;
 import mage.abilities.costs.mana.ManaCost;
 import mage.abilities.costs.mana.ManaCosts;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.dynamicvalue.common.StaticValue;
 import mage.constants.CostModificationType;
 import mage.constants.Duration;
 import mage.constants.Outcome;
@@ -16,7 +18,7 @@ import mage.util.CardUtil;
  */
 public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
 
-    private final int amount;
+    private final DynamicValue amount;
     private ManaCosts<ManaCost> manaCostsToReduce = null;
     private Condition condition;
 
@@ -26,7 +28,7 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
 
     public SpellCostReductionSourceEffect(ManaCosts<ManaCost> manaCostsToReduce, Condition condition) {
         super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
-        this.amount = 0;
+        this.amount = StaticValue.get(0);
         this.manaCostsToReduce = manaCostsToReduce;
         this.condition = condition;
 
@@ -44,19 +46,30 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
     }
 
     public SpellCostReductionSourceEffect(int amount) {
+        this(StaticValue.get(amount), null);
+    }
+
+    public SpellCostReductionSourceEffect(DynamicValue amount) {
         this(amount, null);
     }
 
     public SpellCostReductionSourceEffect(int amount, Condition condition) {
+        this(StaticValue.get(amount), condition);
+    }
+
+    public SpellCostReductionSourceEffect(DynamicValue amount, Condition condition) {
         super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
         this.amount = amount;
         this.condition = condition;
         StringBuilder sb = new StringBuilder();
-        sb.append("this spell costs {").append(amount).append("} less to cast");
+        sb.append("this spell costs {").append(this.amount).append("} less to cast");
         if (this.condition != null) {
             sb.append(" ").append(this.condition.toString().startsWith("if ") ? "" : "if ");
             sb.append(this.condition.toString());
         }
+        if (this.amount.toString().equals("X")) {
+            sb.append(", where {X} is ").append(this.amount.getMessage());
+        }
         this.staticText = sb.toString();
     }
 
@@ -72,7 +85,7 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
         if (manaCostsToReduce != null) {
             CardUtil.adjustCost((SpellAbility) abilityToModify, manaCostsToReduce, false);
         } else {
-            CardUtil.reduceCost(abilityToModify, this.amount);
+            CardUtil.reduceCost(abilityToModify, this.amount.calculate(game, source, this));
         }
         return true;
     }
diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java
index 4391755fa3..25b3ce931f 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java
@@ -1,12 +1,12 @@
 package mage.abilities.effects.common.cost;
 
-import mage.Mana;
 import mage.abilities.Ability;
 import mage.abilities.SpellAbility;
 import mage.constants.CostModificationType;
 import mage.constants.Duration;
 import mage.constants.Outcome;
 import mage.game.Game;
+import mage.util.CardUtil;
 
 public class SpellCostReductionSourceForOpponentsEffect extends CostModificationEffectImpl {
 
@@ -25,19 +25,11 @@ public class SpellCostReductionSourceForOpponentsEffect extends CostModification
 
     @Override
     public boolean apply(Game game, Ability source, Ability abilityToModify) {
-        SpellAbility spellAbility = (SpellAbility) abilityToModify;
-        Mana mana = spellAbility.getManaCostsToPay().getMana();
-        if (mana.getGeneric() > 0) {
-            int count = game.getOpponents(source.getControllerId()).size();
-            int newCount = mana.getGeneric() - count;
-            if (newCount < 0) {
-                newCount = 0;
-            }
-            mana.setGeneric(newCount);
-            spellAbility.getManaCostsToPay().load(mana.toString());
-            return true;
+        int count = game.getOpponents(source.getControllerId()).size();
+        if (count > 0) {
+            CardUtil.reduceCost(abilityToModify, count);
         }
-        return false;
+        return true;
     }
 
     @Override