mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +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;
|
||||
|
||||
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 mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -46,6 +53,7 @@ import mage.constants.Outcome;
|
|||
import mage.constants.SubLayer;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
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.OwnerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
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));
|
||||
|
||||
// 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) {
|
||||
|
@ -167,8 +181,11 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
|
|||
if (filter.match(card, game)) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ActivatedAbility) {
|
||||
ActivatedAbilityImpl copyAbility = (ActivatedAbilityImpl) ability;
|
||||
copyAbility.setMaxActivationsPerTurn(1);
|
||||
UUID originaId = ability.getId();
|
||||
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();
|
||||
Effect effect = new DoNothingEffect();
|
||||
effect.setValue("key", originaId);
|
||||
copyAbility.addEffect(effect);
|
||||
perm.addAbility(copyAbility, card.getId(), game);
|
||||
}
|
||||
}
|
||||
|
@ -184,3 +201,135 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
|
|||
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.command.Emblem;
|
||||
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 {
|
||||
|
||||
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 TargetController mayActivate = TargetController.YOU;
|
||||
protected UUID activatorId;
|
||||
protected boolean checkPlayableMode;
|
||||
private int maxActivationsPerTurn;
|
||||
|
||||
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
super(abilityType, zone);
|
||||
|
@ -172,82 +159,55 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
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++;
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
//20091005 - 602.2
|
||||
switch (mayActivate) {
|
||||
case ANY:
|
||||
break;
|
||||
|
||||
case NOT_YOU:
|
||||
if (controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
setActivationInfo(activationInfo, game);
|
||||
break;
|
||||
|
||||
case OPPONENT:
|
||||
if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OWNER:
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
if (!permanent.getOwnerId().equals(playerId)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case YOU:
|
||||
if (!controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
Permanent enchantment = game.getPermanent(getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (enchanted != null && enchanted.getControllerId().equals(playerId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//20091005 - 602.5d/602.5e
|
||||
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId)
|
||||
|| game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) {
|
||||
if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) {
|
||||
this.activatorId = playerId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
//20091005 - 602.2
|
||||
if (hasMoreActivationsThisTurn(game)) {
|
||||
switch (mayActivate) {
|
||||
case ANY:
|
||||
break;
|
||||
|
||||
case NOT_YOU:
|
||||
if (controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case OPPONENT:
|
||||
if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OWNER:
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
if (!permanent.getOwnerId().equals(playerId)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case YOU:
|
||||
if (!controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
Permanent enchantment = game.getPermanent(getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (enchanted != null && enchanted.getControllerId().equals(playerId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//20091005 - 602.5d/602.5e
|
||||
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId)
|
||||
|| game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) {
|
||||
if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) {
|
||||
this.activatorId = playerId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasMoreActivationsThisTurn(Game game) {
|
||||
ActivatedAbilityImpl.ActivationInfo activationInfo = this.getActivationInfo(game);
|
||||
return activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < maxActivationsPerTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) {
|
||||
return getManaCostsToPay().getOptions();
|
||||
|
@ -295,21 +255,4 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
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