[VOC] Implemented Mirage Phalanx (#8654)

* Implemented Mirage Phalanx

* Changed based on first set of comments

* Reordered variables in alphabetical order

* Added support for removing abilities from a token before creating it.

* Fixed typo in CreateTokenCopyTargetEffect, should have been getAddedPermanents not getAddedPermanent (with the s).

* Updated how soulbond is removed from MiragePhalanx tokens

* Fixed missing fields in the copy constructor

* - Refactoring the exileTokensCreated function to exile all tokens as a single trigger.
- Changed Mirage Phalanx to use the new exileTokensCreated function
- changed ’ to '
This commit is contained in:
Alex Vasile 2022-02-05 20:38:12 -05:00 committed by GitHub
parent c68c7699c0
commit 5611f41949
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 250 additions and 74 deletions

View file

@ -3,10 +3,14 @@ package mage.abilities.effects.common;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.Mode;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.EffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
@ -16,43 +20,44 @@ import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.EmptyToken;
import mage.game.turn.Step;
import mage.target.targetpointer.FixedTarget;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import mage.util.functions.CopyApplier;
import mage.util.functions.EmptyCopyApplier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.*;
/**
* @author LevelX2
*/
public class CreateTokenCopyTargetEffect extends OneShotEffect {
private final UUID playerId;
private final CardType additionalCardType;
private boolean hasHaste;
private int number;
private final Set<Class<? extends Ability>> abilityClazzesToRemove;
private final List<Permanent> addedTokenPermanents;
private final List<Ability> additionalAbilities;
private final CardType additionalCardType;
private SubType additionalSubType;
private SubType onlySubType;
private final boolean tapped;
private final boolean attacking;
private final UUID attackedPlayer;
private final int tokenPower;
private final int tokenToughness;
private final boolean gainsFlying;
private final boolean attacking;
private boolean becomesArtifact;
private ObjectColor color;
private boolean useLKI = false;
private boolean isntLegendary = false;
private int startingLoyalty = -1;
private final List<Ability> additionalAbilities = new ArrayList();
private Permanent savedPermanent = null;
private CounterType counter;
private final boolean gainsFlying;
private boolean hasHaste;
private boolean isntLegendary = false;
private int number;
private int numberOfCounters;
private SubType onlySubType;
private final UUID playerId;
private final boolean tapped;
private Permanent savedPermanent = null;
private int startingLoyalty = -1;
private final int tokenPower;
private final int tokenToughness;
private boolean useLKI = false;
public CreateTokenCopyTargetEffect(boolean useLKI) {
this();
@ -111,27 +116,37 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
this.tokenPower = power;
this.tokenToughness = toughness;
this.gainsFlying = gainsFlying;
this.abilityClazzesToRemove = new HashSet<>();
this.additionalAbilities = new ArrayList<>();
}
public CreateTokenCopyTargetEffect(final CreateTokenCopyTargetEffect effect) {
super(effect);
this.playerId = effect.playerId;
this.additionalCardType = effect.additionalCardType;
this.hasHaste = effect.hasHaste;
this.abilityClazzesToRemove = new HashSet<>(effect.abilityClazzesToRemove);
this.addedTokenPermanents = new ArrayList<>(effect.addedTokenPermanents);
this.number = effect.number;
this.additionalAbilities = new ArrayList<>(effect.additionalAbilities);
this.additionalCardType = effect.additionalCardType;
this.additionalSubType = effect.additionalSubType;
this.onlySubType = effect.onlySubType;
this.tapped = effect.tapped;
this.attacking = effect.attacking;
this.attackedPlayer = effect.attackedPlayer;
this.tokenPower = effect.tokenPower;
this.tokenToughness = effect.tokenToughness;
this.gainsFlying = effect.gainsFlying;
this.attacking = effect.attacking;
this.becomesArtifact = effect.becomesArtifact;
this.color = effect.color;
this.useLKI = effect.useLKI;
this.counter = effect.counter;
this.gainsFlying = effect.gainsFlying;
this.hasHaste = effect.hasHaste;
this.isntLegendary = effect.isntLegendary;
this.number = effect.number;
this.numberOfCounters = effect.numberOfCounters;
this.onlySubType = effect.onlySubType;
this.playerId = effect.playerId;
this.savedPermanent = effect.savedPermanent;
this.startingLoyalty = effect.startingLoyalty;
this.tapped = effect.tapped;
this.tokenPower = effect.tokenPower;
this.tokenToughness = effect.tokenToughness;
this.useLKI = effect.useLKI;
}
@Override
@ -224,6 +239,25 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
}
additionalAbilities.stream().forEach(token::addAbility);
if (!this.abilityClazzesToRemove.isEmpty()) {
List<Ability> abilitiesToRemoveTmp = new ArrayList<>();
// Find the ones to remove
for (Ability ability : token.getAbilities()) {
if (this.abilityClazzesToRemove.contains(ability.getClass())) {
abilitiesToRemoveTmp.add(ability);
}
}
// Remove them
for (Ability ability : abilitiesToRemoveTmp) {
// Remove subabilities
token.removeAbilities(ability.getSubAbilities());
// Remove the ability
token.removeAbility(ability);
}
}
token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer);
for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield
Permanent tokenPermanent = game.getPermanent(tokenId);
@ -280,7 +314,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
return sb.toString();
}
public List<Permanent> getAddedPermanent() {
public List<Permanent> getAddedPermanents() {
return addedTokenPermanents;
}
@ -321,26 +355,43 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
}
public void exileTokensCreatedAtNextEndStep(Game game, Ability source) {
for (Permanent tokenPermanent : addedTokenPermanents) {
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source);
}
this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_TURN);
}
public void exileTokensCreatedAtEndOfCombat(Game game, Ability source) {
for (Permanent tokenPermanent : addedTokenPermanents) {
this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_COMBAT);
}
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game));
game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source);
private void exileTokensCreatedAtEndOf(Game game, Ability source, PhaseStep phaseStepToExileCards) {
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
exileEffect.setText("exile the token copies");
exileEffect.setTargetPointer(new FixedTargets(addedTokenPermanents, game));
DelayedTriggeredAbility exileAbility;
switch (phaseStepToExileCards) {
case END_TURN:
exileAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
break;
case END_COMBAT:
exileAbility = new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect);
break;
default:
return;
}
game.addDelayedTriggeredAbility(exileAbility, source);
}
public void addAbilityClassesToRemoveFromTokens(Class<? extends Ability> clazz) {
this.abilityClazzesToRemove.add(clazz);
}
public void addAdditionalAbilities(Ability... abilities) {
Arrays.stream(abilities).forEach(this.additionalAbilities::add);
this.additionalAbilities.addAll(Arrays.asList(abilities));
}
public CreateTokenCopyTargetEffect setSavedPermanent(Permanent savedPermanent) {
this.savedPermanent = savedPermanent;
return this;

View file

@ -79,7 +79,7 @@ class MyriadEffect extends OneShotEffect {
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(controller.getId(), null, false, 1, true, true, playerId);
effect.setTargetPointer(new FixedTarget(sourceObject, game));
effect.apply(game, source);
tokens.addAll(effect.getAddedPermanent());
tokens.addAll(effect.getAddedPermanents());
}
}
}

View file

@ -27,6 +27,10 @@ public interface Token extends MageObject {
void addAbility(Ability ability);
void removeAbility(Ability abilityToRemove);
void removeAbilities(List<Ability> abilitiesToRemove);
boolean putOntoBattlefield(int amount, Game game, Ability source);
boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId);

View file

@ -130,6 +130,35 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
abilities.addAll(ability.getSubAbilities());
}
// Directly from PermanentImpl
@Override
public void removeAbility(Ability abilityToRemove) {
if (abilityToRemove == null) {
return;
}
// 112.10b Effects that remove an ability remove all instances of it.
List<Ability> toRemove = new ArrayList<>();
abilities.forEach(a -> {
if (a.isSameInstance(abilityToRemove)) {
toRemove.add(a);
}
});
// TODO: what about triggered abilities? See addAbility above -- triggers adds to GameState
toRemove.forEach(r -> abilities.remove(r));
}
// Directly from PermanentImpl
@Override
public void removeAbilities(List<Ability> abilitiesToRemove) {
if (abilitiesToRemove == null) {
return;
}
abilitiesToRemove.forEach(a -> removeAbility(a));
}
@Override
public boolean putOntoBattlefield(int amount, Game game, Ability source) {
return this.putOntoBattlefield(amount, game, source, source.getControllerId());