mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 13:02:06 -08:00
fix harmonize implementation (fixes #13531)
This commit is contained in:
parent
9261c1362e
commit
5876040be7
5 changed files with 37 additions and 109 deletions
|
|
@ -549,6 +549,8 @@ public interface Ability extends Controllable, Serializable {
|
|||
*/
|
||||
Ability setCostAdjuster(CostAdjuster costAdjuster);
|
||||
|
||||
CostAdjuster getCostAdjuster();
|
||||
|
||||
/**
|
||||
* Prepare {X} settings for announce
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1761,6 +1761,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CostAdjuster getCostAdjuster() {
|
||||
return costAdjuster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustX(Game game) {
|
||||
if (costAdjuster != null) {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ public abstract class CastFromGraveyardAbility extends SpellAbility {
|
|||
spellAbilityCopy.addCost(this.getCosts().copy());
|
||||
spellAbilityCopy.addCost(this.getManaCosts().copy());
|
||||
spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode());
|
||||
spellAbilityCopy.setCostAdjuster(this.getCostAdjuster());
|
||||
spellAbilityToResolve = spellAbilityCopy;
|
||||
ContinuousEffect effect = new CastFromGraveyardReplacementEffect();
|
||||
effect.setTargetPointer(new FixedTarget(getSourceId(), game.getState().getZoneChangeCounter(getSourceId())));
|
||||
|
|
|
|||
|
|
@ -4,15 +4,12 @@ import mage.MageInt;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.VariableCostImpl;
|
||||
import mage.abilities.costs.VariableCostType;
|
||||
import mage.abilities.costs.CostAdjuster;
|
||||
import mage.abilities.costs.common.TapTargetCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityCastMode;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.permanent.PermanentIdPredicate;
|
||||
|
|
@ -23,9 +20,6 @@ import mage.target.TargetPermanent;
|
|||
import mage.target.common.TargetControlledPermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
|
|
@ -36,8 +30,7 @@ public class HarmonizeAbility extends CastFromGraveyardAbility {
|
|||
|
||||
public HarmonizeAbility(Card card, String manaString) {
|
||||
super(card, new ManaCostsImpl<>(manaString), SpellAbilityCastMode.HARMONIZE);
|
||||
this.addCost(new HarmonizeCost());
|
||||
this.addSubAbility(new SimpleStaticAbility(Zone.ALL, new HarmonizeCostReductionEffect()).setRuleVisible(false));
|
||||
this.setCostAdjuster(HarmonizeAbilityAdjuster.instance);
|
||||
}
|
||||
|
||||
private HarmonizeAbility(final HarmonizeAbility ability) {
|
||||
|
|
@ -57,123 +50,45 @@ public class HarmonizeAbility extends CastFromGraveyardAbility {
|
|||
}
|
||||
}
|
||||
|
||||
class HarmonizeCostReductionEffect extends CostModificationEffectImpl {
|
||||
|
||||
HarmonizeCostReductionEffect() {
|
||||
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
|
||||
}
|
||||
|
||||
private HarmonizeCostReductionEffect(final HarmonizeCostReductionEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
enum HarmonizeAbilityAdjuster implements CostAdjuster {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
SpellAbility spellAbility = (SpellAbility) abilityToModify;
|
||||
int power;
|
||||
public void reduceCost(Ability ability, Game game) {
|
||||
if (game.inCheckPlayableState()) {
|
||||
power = game
|
||||
int amount = game
|
||||
.getBattlefield()
|
||||
.getActivePermanents(
|
||||
StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE,
|
||||
source.getControllerId(), source, game
|
||||
).stream()
|
||||
ability.getControllerId(), ability, game
|
||||
)
|
||||
.stream()
|
||||
.map(MageObject::getPower)
|
||||
.mapToInt(MageInt::getValue)
|
||||
.max()
|
||||
.orElse(0);
|
||||
} else {
|
||||
power = CardUtil
|
||||
.castStream(spellAbility.getCosts().stream(), HarmonizeCost.class)
|
||||
.map(HarmonizeCost::getChosenCreature)
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.map(MageObject::getPower)
|
||||
.mapToInt(MageInt::getValue)
|
||||
.map(x -> Math.max(x, 0))
|
||||
.sum();
|
||||
CardUtil.reduceCost(ability, amount);
|
||||
return;
|
||||
}
|
||||
if (power > 0) {
|
||||
CardUtil.adjustCost(spellAbility, power);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
return abilityToModify instanceof SpellAbility
|
||||
&& abilityToModify.getSourceId().equals(source.getSourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarmonizeCostReductionEffect copy() {
|
||||
return new HarmonizeCostReductionEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
class HarmonizeCost extends VariableCostImpl {
|
||||
|
||||
private UUID chosenCreature = null;
|
||||
|
||||
HarmonizeCost() {
|
||||
super(VariableCostType.ADDITIONAL, "", "");
|
||||
}
|
||||
|
||||
private HarmonizeCost(final HarmonizeCost cost) {
|
||||
super(cost);
|
||||
this.chosenCreature = cost.chosenCreature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarmonizeCost copy() {
|
||||
return new HarmonizeCost(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPaid() {
|
||||
super.clearPaid();
|
||||
chosenCreature = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxValue(Ability source, Game game) {
|
||||
return game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE, source, game, 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int announceXValue(Ability source, Game game) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
if (player == null || !game.getBattlefield().contains(
|
||||
StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE, source, game, 1
|
||||
StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE, ability, game, 1
|
||||
) || !player.chooseUse(
|
||||
Outcome.Benefit, "Tap an untapped creature you control for harmonize?", source, game
|
||||
Outcome.Tap, "Tap a creature to reduce the cost of this spell?", ability, game
|
||||
)) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE);
|
||||
target.withNotTarget(true);
|
||||
target.withChooseHint("for harmonize");
|
||||
player.choose(Outcome.PlayForFree, target, source, game);
|
||||
target.withChooseHint("to pay for harmonize");
|
||||
player.choose(Outcome.Tap, target, ability, game);
|
||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
||||
if (permanent == null) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
chosenCreature = permanent.getId();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private FilterControlledPermanent makeFilter() {
|
||||
FilterControlledPermanent filter = new FilterControlledPermanent("tap the chosen creature");
|
||||
filter.add(new PermanentIdPredicate(chosenCreature));
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
|
||||
return new TapTargetCost(new TargetControlledPermanent(xValue, xValue, makeFilter(), true));
|
||||
}
|
||||
|
||||
public UUID getChosenCreature() {
|
||||
return chosenCreature;
|
||||
CardUtil.reduceCost(ability, permanent.getPower().getValue());
|
||||
FilterControlledPermanent filter = new FilterControlledPermanent("creature chosen to tap for harmonize");
|
||||
filter.add(new PermanentIdPredicate(permanent.getId()));
|
||||
ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -787,6 +787,11 @@ public class StackAbility extends StackObjectImpl implements Ability {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CostAdjuster getCostAdjuster() {
|
||||
return costAdjuster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustX(Game game) {
|
||||
if (costAdjuster != null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue