Fixed Thousand-Year Storm and added hints to Aetherflux Reservoir and Sentinel Tower (#6645)

This commit is contained in:
Jakob 2020-07-08 18:10:09 +02:00 committed by GitHub
parent 13f7f2a035
commit 4dc99fbb58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 52 deletions

View file

@ -10,6 +10,7 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -28,12 +29,14 @@ public final class AetherfluxReservoir extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
// Whenever you cast a spell, you gain 1 life for each spell you've cast this turn.
this.addAbility(new SpellCastControllerTriggeredAbility(new GainLifeEffect(new AetherfluxReservoirDynamicValue()), false));
Ability abilityGainLife = new SpellCastControllerTriggeredAbility(new GainLifeEffect(new AetherfluxReservoirDynamicValue()), false);
abilityGainLife.addHint(new ValueHint("You've cast spells this turn", new AetherfluxReservoirDynamicValue()));
this.addAbility(abilityGainLife);
// Pay 50 life: Aetherflux Reservoir deals 50 damage to any target.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50));
ability.addTarget(new TargetAnyTarget());
this.addAbility(ability);
Ability abilityPayLife = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50));
abilityPayLife.addTarget(new TargetAnyTarget());
this.addAbility(abilityPayLife);
}
public AetherfluxReservoir(final AetherfluxReservoir card) {

View file

@ -2,10 +2,13 @@ package mage.cards.s;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastAllTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -44,13 +47,18 @@ public final class SentinelTower extends CardImpl {
class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
private String damageInfo;
SentinelTowerTriggeredAbility() {
super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false);
this.addTarget(new TargetAnyTarget());
this.addHint(new ValueHint("There were cast instant and sorcery this turn", SentinelTowerSpellsCastValue.instance));
this.damageInfo = null;
}
SentinelTowerTriggeredAbility(final SentinelTowerTriggeredAbility effect) {
super(effect);
this.damageInfo = effect.damageInfo;
}
@Override
@ -78,6 +86,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
break;
}
}
damageInfo = " (<b>" + damageToDeal + " damage</b>)";
for (Effect effect : this.getEffects()) {
if (effect instanceof DamageTargetEffect) {
((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal));
@ -92,7 +101,8 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
public String getRule() {
return "Whenever an instant or sorcery spell is cast during your turn, "
+ "{this} deals damage to any target equal to 1 "
+ "plus the number of instant and sorcery spells cast before that spell this turn.";
+ "plus the number of instant and sorcery spells cast before that spell this turn."
+ (damageInfo != null ? damageInfo : "");
}
}
@ -124,3 +134,36 @@ class SentinelTowerWatcher extends Watcher {
return spellsThisTurn;
}
}
enum SentinelTowerSpellsCastValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
SentinelTowerWatcher watcher = game.getState().getWatcher(SentinelTowerWatcher.class);
if (watcher == null) {
return 0;
}
List<MageObjectReference> spellsCast = watcher.getSpellsThisTurn();
if (spellsCast == null) {
return 0;
}
return spellsCast.size();
}
@Override
public SentinelTowerSpellsCastValue copy() {
return instance;
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "There was an instant or sorcery spell in this turn";
}
}

View file

@ -1,5 +1,7 @@
package mage.cards.t;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
@ -13,7 +15,7 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.filter.common.FilterInstantOrSorcerySpell;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
@ -23,9 +25,11 @@ import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.List;
import java.util.ArrayList;
/**
* @author LevelX2
* @author jasc7636
*/
public final class ThousandYearStorm extends CardImpl {
@ -33,7 +37,7 @@ public final class ThousandYearStorm extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{R}");
// Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies.
this.addAbility(new ThousandYearStormAbility());
this.addAbility(new ThousandYearStormAbility(), new ThousandYearStormWatcher());
}
public ThousandYearStorm(final ThousandYearStorm card) {
@ -48,12 +52,12 @@ public final class ThousandYearStorm extends CardImpl {
class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
String stormCountInfo = null;
private String stormCountInfo;
public ThousandYearStormAbility() {
super(Zone.BATTLEFIELD, new ThousandYearStormEffect(), new FilterInstantOrSorcerySpell(), false, true);
this.addHint(new ValueHint("You've cast instant and sorcery this turn", ThousandYearSpellsCastThatTurnValue.instance));
this.addWatcher(new ThousandYearWatcher());
super(Zone.BATTLEFIELD, new ThousandYearStormEffect(), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false, true);
this.addHint(new ValueHint("You've cast instant and sorcery this turn", ThousandYearStormSpellsCastThatTurnValue.instance));
this.stormCountInfo = null;
}
public ThousandYearStormAbility(final ThousandYearStormAbility ability) {
@ -63,11 +67,32 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
// save storm count info, real count will be calculated to stack ability in resolve effect only
if (super.checkTrigger(event, game)) {
int stormCount = ThousandYearSpellsCastThatTurnValue.instance.calculate(game, this, null);
stormCountInfo = " (<b>storm count: " + Math.max(0, stormCount - 1) + "</b>) ";
return true;
ThousandYearStormWatcher watcher = game.getState().getWatcher(ThousandYearStormWatcher.class);
if (watcher == null) {
return false;
}
UUID playerId = event.getPlayerId();
List<MageObjectReference> spellsCast = watcher.getSpellsThisTurn(playerId);
MageObject object = game.getObject(event.getTargetId());
if (object == null || spellsCast == null) {
return false;
}
int stormCount = 0;
for (MageObjectReference mor : spellsCast) {
stormCount++;
if (mor.refersTo(object, game)) {
break;
}
}
stormCount = Math.max(0, stormCount - 1);
stormCountInfo = " (<b>storm count: " + stormCount + "</b>) ";
for (Effect effect : this.getEffects()) {
if (effect instanceof ThousandYearStormEffect) {
((ThousandYearStormEffect) effect).setStormCount(stormCount);
return true;
}
}
}
return false;
}
@ -85,13 +110,16 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
}
class ThousandYearStormEffect extends OneShotEffect {
private int stormCount;
public ThousandYearStormEffect() {
super(Outcome.Benefit);
this.stormCount = -1;
}
public ThousandYearStormEffect(final ThousandYearStormEffect effect) {
super(effect);
this.stormCount = effect.stormCount;
}
@Override
@ -102,82 +130,72 @@ class ThousandYearStormEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source));
Player controller = spell != null ? game.getPlayer(spell.getControllerId()) : null;
if (spell != null && controller != null) {
ThousandYearWatcher watcher = game.getState().getWatcher(ThousandYearWatcher.class);
if (watcher != null) {
String stateSearchId = spell.getId().toString() + source.getSourceId().toString();
// recall only the spells cast before it
int numberOfCopies = 0;
if (game.getState().getValue(stateSearchId) != null) {
numberOfCopies = (int) game.getState().getValue(stateSearchId);
}
if (numberOfCopies > 0) {
spell.createCopyOnStack(game, source, source.getControllerId(), true, numberOfCopies);
}
return true;
}
if (stormCount >= 0 && spell != null) {
spell.createCopyOnStack(game, source, source.getControllerId(), true, stormCount);
return true;
}
return false;
}
public void setStormCount(int stormCount) {
this.stormCount = stormCount;
}
@Override
public String getText(Mode mode) {
return "copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies";
}
}
class ThousandYearWatcher extends Watcher {
class ThousandYearStormWatcher extends Watcher {
private final Map<UUID, Integer> amountOfInstantSorcerySpellsCastOnCurrentTurn = new HashMap<>();
private final Map<UUID, List<MageObjectReference>> spellsThisTurn = new HashMap<>();
public ThousandYearWatcher() {
public ThousandYearStormWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.SPELL_CAST && !sourceId.equals(event.getTargetId())) {
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
if (spell != null && spell.isInstantOrSorcery()) {
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
MageObject object = game.getObject(event.getTargetId());
if (object != null && (object.isInstant() || object.isSorcery())) {
UUID playerId = event.getPlayerId();
if (playerId != null) {
String stateSearchId = spell.getId().toString() + sourceId.toString();
// calc current spell
amountOfInstantSorcerySpellsCastOnCurrentTurn.putIfAbsent(playerId, 0);
amountOfInstantSorcerySpellsCastOnCurrentTurn.compute(playerId, (k, a) -> a + 1);
// remember only the spells cast before it
game.getState().setValue(stateSearchId, amountOfInstantSorcerySpellsCastOnCurrentTurn.get(playerId) - 1);
}
List<MageObjectReference> spellsCast = spellsThisTurn.getOrDefault(playerId, new ArrayList<MageObjectReference>());
spellsCast.add(new MageObjectReference(object, game));
spellsThisTurn.put(playerId, spellsCast);
}
}
}
@Override
public void reset() {
amountOfInstantSorcerySpellsCastOnCurrentTurn.clear();
for (List<MageObjectReference> mor : spellsThisTurn.values()) {
mor.clear();
}
spellsThisTurn.clear();
}
public int getAmountOfSpellsPlayerCastOnCurrentTurn(UUID playerId) {
return amountOfInstantSorcerySpellsCastOnCurrentTurn.getOrDefault(playerId, 0);
public List<MageObjectReference> getSpellsThisTurn(UUID playerId) {
return spellsThisTurn.getOrDefault(playerId, new ArrayList<MageObjectReference>());
}
}
enum ThousandYearSpellsCastThatTurnValue implements DynamicValue {
enum ThousandYearStormSpellsCastThatTurnValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
ThousandYearWatcher watcher = game.getState().getWatcher(ThousandYearWatcher.class);
ThousandYearStormWatcher watcher = game.getState().getWatcher(ThousandYearStormWatcher.class);
if (watcher == null) {
return 0;
}
return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId());
return watcher.getSpellsThisTurn(sourceAbility.getControllerId()).size();
}
@Override
public ThousandYearSpellsCastThatTurnValue copy() {
public ThousandYearStormSpellsCastThatTurnValue copy() {
return instance;
}