mirror of
https://github.com/correl/mage.git
synced 2024-12-26 11:09:27 +00:00
Implemented Mairsil properly
This commit is contained in:
parent
f33d9006c6
commit
8d85189262
2 changed files with 195 additions and 103 deletions
|
@ -27,14 +27,21 @@
|
||||||
*/
|
*/
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.ActivatedAbility;
|
import mage.abilities.ActivatedAbility;
|
||||||
import mage.abilities.ActivatedAbilityImpl;
|
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -46,6 +53,7 @@ import mage.constants.Outcome;
|
||||||
import mage.constants.SubLayer;
|
import mage.constants.SubLayer;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.constants.TargetController;
|
import mage.constants.TargetController;
|
||||||
|
import mage.constants.WatcherScope;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
|
@ -54,11 +62,15 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||||
import mage.filter.predicate.other.CounterCardPredicate;
|
import mage.filter.predicate.other.CounterCardPredicate;
|
||||||
import mage.filter.predicate.other.OwnerPredicate;
|
import mage.filter.predicate.other.OwnerPredicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.stack.StackAbility;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.common.TargetCardInHand;
|
import mage.target.common.TargetCardInHand;
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -79,7 +91,9 @@ public class MairsilThePretender extends CardImpl {
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new MairsilThePretenderExileEffect(), true));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new MairsilThePretenderExileEffect(), true));
|
||||||
|
|
||||||
// Mairsil, the Pretender has all activated abilities of all cards you own in exile with cage counters on them. You may activate each of those abilities only once each turn.
|
// Mairsil, the Pretender has all activated abilities of all cards you own in exile with cage counters on them. You may activate each of those abilities only once each turn.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MairsilThePretenderGainAbilitiesEffect()));
|
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new MairsilThePretenderGainAbilitiesEffect());
|
||||||
|
ability.addEffect(new MairsilThePretenderRuleModifyingEffect());
|
||||||
|
this.addAbility(ability, new MairsilThePretenderWatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
public MairsilThePretender(final MairsilThePretender card) {
|
public MairsilThePretender(final MairsilThePretender card) {
|
||||||
|
@ -167,8 +181,11 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
|
||||||
if (filter.match(card, game)) {
|
if (filter.match(card, game)) {
|
||||||
for (Ability ability : card.getAbilities()) {
|
for (Ability ability : card.getAbilities()) {
|
||||||
if (ability instanceof ActivatedAbility) {
|
if (ability instanceof ActivatedAbility) {
|
||||||
ActivatedAbilityImpl copyAbility = (ActivatedAbilityImpl) ability;
|
UUID originaId = ability.getId();
|
||||||
copyAbility.setMaxActivationsPerTurn(1);
|
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();
|
||||||
|
Effect effect = new DoNothingEffect();
|
||||||
|
effect.setValue("key", originaId);
|
||||||
|
copyAbility.addEffect(effect);
|
||||||
perm.addAbility(copyAbility, card.getId(), game);
|
perm.addAbility(copyAbility, card.getId(), game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,3 +201,135 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
|
||||||
return new MairsilThePretenderGainAbilitiesEffect(this);
|
return new MairsilThePretenderGainAbilitiesEffect(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MairsilThePretenderWatcher extends Watcher {
|
||||||
|
|
||||||
|
public final Map<UUID, Set<UUID>> activatedThisTurnAbilities = new HashMap<>();
|
||||||
|
|
||||||
|
public MairsilThePretenderWatcher() {
|
||||||
|
super(MairsilThePretenderWatcher.class.getSimpleName(), WatcherScope.GAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MairsilThePretenderWatcher(final MairsilThePretenderWatcher watcher) {
|
||||||
|
super(watcher);
|
||||||
|
for (Entry<UUID, Set<UUID>> entry : watcher.activatedThisTurnAbilities.entrySet()) {
|
||||||
|
activatedThisTurnAbilities.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void watch(GameEvent event, Game game) {
|
||||||
|
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event instanceof ZoneChangeEvent) {
|
||||||
|
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||||
|
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||||
|
Permanent permanent = zEvent.getTarget();
|
||||||
|
if (permanent != null) {
|
||||||
|
this.activatedThisTurnAbilities.remove(permanent.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) {
|
||||||
|
Set<UUID> permAbilities;
|
||||||
|
if (activatedThisTurnAbilities.keySet().contains(event.getSourceId())) {
|
||||||
|
permAbilities = activatedThisTurnAbilities.get(event.getSourceId());
|
||||||
|
} else {
|
||||||
|
permAbilities = new HashSet<>();
|
||||||
|
}
|
||||||
|
StackAbility ability = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||||
|
if (ability != null && ability.getStackAbility().isActivated()) {
|
||||||
|
for (Effect effect : ability.getAllEffects()) {
|
||||||
|
if (effect instanceof DoNothingEffect) {
|
||||||
|
permAbilities.add((UUID) effect.getValue("key"));
|
||||||
|
this.activatedThisTurnAbilities.put(event.getSourceId(), permAbilities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
activatedThisTurnAbilities.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UUID, Set<UUID>> getActivatedThisTurnAbilities() {
|
||||||
|
return this.activatedThisTurnAbilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MairsilThePretenderWatcher copy() {
|
||||||
|
return new MairsilThePretenderWatcher(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MairsilThePretenderRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
public MairsilThePretenderRuleModifyingEffect() {
|
||||||
|
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MairsilThePretenderRuleModifyingEffect(final MairsilThePretenderRuleModifyingEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MairsilThePretenderRuleModifyingEffect copy() {
|
||||||
|
return new MairsilThePretenderRuleModifyingEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
||||||
|
MairsilThePretenderWatcher watcher = (MairsilThePretenderWatcher) game.getState().getWatchers().get(MairsilThePretenderWatcher.class.getSimpleName());
|
||||||
|
if (watcher != null && ability != null && ability.isPresent()) {
|
||||||
|
for (Effect effect : ability.get().getAllEffects()) {
|
||||||
|
if (effect instanceof DoNothingEffect) {
|
||||||
|
UUID originalID = (UUID) effect.getValue("key");
|
||||||
|
if (watcher.getActivatedThisTurnAbilities().keySet().contains(event.getSourceId())) {
|
||||||
|
if (watcher.getActivatedThisTurnAbilities().get(event.getSourceId()).contains(originalID)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||||
|
return "This ability can only be activated once each turn.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DoNothingEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
DoNothingEffect() {
|
||||||
|
super(Outcome.Neutral);
|
||||||
|
}
|
||||||
|
|
||||||
|
DoNothingEffect(final DoNothingEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoNothingEffect copy() {
|
||||||
|
return new DoNothingEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,6 @@ import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -53,22 +52,10 @@ import mage.util.CardUtil;
|
||||||
*/
|
*/
|
||||||
public abstract class ActivatedAbilityImpl extends AbilityImpl implements ActivatedAbility {
|
public abstract class ActivatedAbilityImpl extends AbilityImpl implements ActivatedAbility {
|
||||||
|
|
||||||
static class ActivationInfo {
|
|
||||||
|
|
||||||
public int turnNum;
|
|
||||||
public int activationCounter;
|
|
||||||
|
|
||||||
public ActivationInfo(int turnNum, int activationCounter) {
|
|
||||||
this.turnNum = turnNum;
|
|
||||||
this.activationCounter = activationCounter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TimingRule timing = TimingRule.INSTANT;
|
protected TimingRule timing = TimingRule.INSTANT;
|
||||||
protected TargetController mayActivate = TargetController.YOU;
|
protected TargetController mayActivate = TargetController.YOU;
|
||||||
protected UUID activatorId;
|
protected UUID activatorId;
|
||||||
protected boolean checkPlayableMode;
|
protected boolean checkPlayableMode;
|
||||||
private int maxActivationsPerTurn;
|
|
||||||
|
|
||||||
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
||||||
super(abilityType, zone);
|
super(abilityType, zone);
|
||||||
|
@ -171,30 +158,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
@Override
|
@Override
|
||||||
public abstract ActivatedAbilityImpl copy();
|
public abstract ActivatedAbilityImpl copy();
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean activate(Game game, boolean noMana) {
|
|
||||||
if (hasMoreActivationsThisTurn(game)) {
|
|
||||||
if (super.activate(game, noMana)) {
|
|
||||||
ActivatedAbilityImpl.ActivationInfo activationInfo = getActivationInfo(game);
|
|
||||||
if (activationInfo == null) {
|
|
||||||
activationInfo = new ActivatedAbilityImpl.ActivationInfo(game.getTurnNum(), 1);
|
|
||||||
} else if (activationInfo.turnNum != game.getTurnNum()) {
|
|
||||||
activationInfo.turnNum = game.getTurnNum();
|
|
||||||
activationInfo.activationCounter = 1;
|
|
||||||
} else {
|
|
||||||
activationInfo.activationCounter++;
|
|
||||||
}
|
|
||||||
setActivationInfo(activationInfo, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canActivate(UUID playerId, Game game) {
|
public boolean canActivate(UUID playerId, Game game) {
|
||||||
//20091005 - 602.2
|
//20091005 - 602.2
|
||||||
if (hasMoreActivationsThisTurn(game)) {
|
|
||||||
switch (mayActivate) {
|
switch (mayActivate) {
|
||||||
case ANY:
|
case ANY:
|
||||||
break;
|
break;
|
||||||
|
@ -239,15 +205,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasMoreActivationsThisTurn(Game game) {
|
|
||||||
ActivatedAbilityImpl.ActivationInfo activationInfo = this.getActivationInfo(game);
|
|
||||||
return activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < maxActivationsPerTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) {
|
public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) {
|
||||||
return getManaCostsToPay().getOptions();
|
return getManaCostsToPay().getOptions();
|
||||||
|
@ -295,21 +255,4 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
return checkPlayableMode;
|
return checkPlayableMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxActivationsPerTurn(int maxActivationsPerTurn) {
|
|
||||||
this.maxActivationsPerTurn = maxActivationsPerTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ActivatedAbilityImpl.ActivationInfo getActivationInfo(Game game) {
|
|
||||||
Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn"+this.getOriginalId().toString(), sourceId, game));
|
|
||||||
Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount"+this.getOriginalId().toString(), sourceId, game));
|
|
||||||
if (turnNum == null || activationCount == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new ActivatedAbilityImpl.ActivationInfo(turnNum, activationCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setActivationInfo(ActivatedAbilityImpl.ActivationInfo activationInfo, Game game) {
|
|
||||||
game.getState().setValue(CardUtil.getCardZoneString("activationsTurn"+this.getOriginalId().toString(), sourceId, game), activationInfo.turnNum);
|
|
||||||
game.getState().setValue(CardUtil.getCardZoneString("activationsCount"+this.getOriginalId().toString(), sourceId, game), activationInfo.activationCounter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue