[WHO] Implement 4 cards, create generic EachOpponentPermanentTargetsAdjuster (#11886)

* Implement Bigger on the Inside
* implement Reverse the Polarity
* Implement Sontaran General
* Implement Everything Comes to Dust
This commit is contained in:
ssk97 2024-03-28 14:32:38 -07:00 committed by GitHub
parent 26ac305a7f
commit d886b3e450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 479 additions and 585 deletions

View file

@ -13,6 +13,8 @@ import mage.players.Player;
import mage.util.CardUtil;
import mage.watchers.common.SpellsCastWatcher;
import java.util.UUID;
/**
* @author xenohedron
*/
@ -21,17 +23,25 @@ public class NextSpellCastHasAbilityEffect extends ContinuousEffectImpl {
private int spellsCast;
private final Ability ability;
private final FilterCard filter;
private final TargetController targetController;
public NextSpellCastHasAbilityEffect(Ability ability) {
this(ability, StaticFilters.FILTER_CARD);
}
public NextSpellCastHasAbilityEffect(Ability ability, FilterCard filter) {
this(ability, StaticFilters.FILTER_CARD, TargetController.SOURCE_CONTROLLER);
}
public NextSpellCastHasAbilityEffect(Ability ability, TargetController targetController) {
this(ability, StaticFilters.FILTER_CARD, targetController);
}
public NextSpellCastHasAbilityEffect(Ability ability, FilterCard filter, TargetController targetController) {
super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.ability = ability;
this.filter = filter;
this.targetController = targetController;
staticText = "the next " + filter.getMessage().replace("card", "spell")
+ " you cast this turn has " + CardUtil.getTextWithFirstCharLowerCase(CardUtil.stripReminderText(ability.getRule()));
+ (targetController == TargetController.SOURCE_CONTROLLER ? " you cast" : " target player casts")
+ " this turn has " + CardUtil.getTextWithFirstCharLowerCase(CardUtil.stripReminderText(ability.getRule()));
}
private NextSpellCastHasAbilityEffect(final NextSpellCastHasAbilityEffect effect) {
@ -39,6 +49,7 @@ public class NextSpellCastHasAbilityEffect extends ContinuousEffectImpl {
this.spellsCast = effect.spellsCast;
this.ability = effect.ability;
this.filter = effect.filter;
this.targetController = effect.targetController;
}
@Override
@ -57,17 +68,28 @@ public class NextSpellCastHasAbilityEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
UUID playerId;
switch (targetController){
case SOURCE_TARGETS:
playerId = source.getFirstTarget();
break;
case SOURCE_CONTROLLER:
playerId = source.getControllerId();
break;
default:
throw new UnsupportedOperationException("Value for targetController in NextSpellCastHasAbilityEffect not supported: " + targetController);
}
Player player = game.getPlayer(playerId);
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
if (player == null || watcher == null) {
return false;
}
//check if a spell was cast before
if (watcher.getCount(source.getControllerId()) > spellsCast) {
if (watcher.getCount(playerId) > spellsCast) {
discard(); // only one use
return false;
}
for (Card card : game.getExile().getAllCardsByRange(game, source.getControllerId())) {
for (Card card : game.getExile().getAllCardsByRange(game, playerId)) {
if (filter.match(card, game)) {
game.getState().addOtherAbility(card, ability);
}
@ -94,7 +116,7 @@ public class NextSpellCastHasAbilityEffect extends ContinuousEffectImpl {
.forEach(card -> game.getState().addOtherAbility(card, ability));
for (StackObject stackObject : game.getStack()) {
if (!(stackObject instanceof Spell) || !stackObject.isControlledBy(source.getControllerId())) {
if (!(stackObject instanceof Spell) || !stackObject.isControlledBy(playerId)) {
continue;
}
// TODO: Distinguish "you cast" to exclude copies

View file

@ -0,0 +1,48 @@
package mage.target.targetadjustment;
import mage.abilities.Ability;
import mage.filter.Filter;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
* @author notgreat
*/
public class EachOpponentPermanentTargetsAdjuster implements TargetAdjuster {
private final TargetPermanent blueprintTarget;
/**
* Duplicates the permanent target for each opponent.
* Filtering of permanent's controllers will be handled inside, so
* do not pass a blueprint target with a controller restriction filter/predicate.
*
* @param blueprintTarget The target to be duplicated per opponent
*/
public EachOpponentPermanentTargetsAdjuster(TargetPermanent blueprintTarget) {
this.blueprintTarget = blueprintTarget.copy(); //Defensively copy the blueprint to ensure immutability
}
@Override
public void adjustTargets(Ability ability, Game game) {
ability.getTargets().clear();
for (UUID opponentId : game.getOpponents(ability.getControllerId())) {
Player opponent = game.getPlayer(opponentId);
if (opponent == null) {
continue;
}
TargetPermanent newTarget = blueprintTarget.copy();
Filter<Permanent> filter = newTarget.getFilter();
filter.add(new ControllerIdPredicate(opponentId));
if (newTarget.canChoose(ability.getControllerId(), ability, game)) {
filter.setMessage(filter.getMessage()+" controlled by " + opponent.getLogName());
ability.addTarget(newTarget);
}
}
}
}

View file

@ -11,5 +11,6 @@ import java.io.Serializable;
@FunctionalInterface
public interface TargetAdjuster extends Serializable {
// Warning: This is not Copyable, do not use changeable data inside (only use static objects like Filter)
void adjustTargets(Ability ability, Game game);
}