mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
[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:
parent
c68c7699c0
commit
5611f41949
36 changed files with 250 additions and 74 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue