mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
Fixed Thousand-Year Storm and added hints to Aetherflux Reservoir and Sentinel Tower (#6645)
This commit is contained in:
parent
13f7f2a035
commit
4dc99fbb58
3 changed files with 116 additions and 52 deletions
|
@ -10,6 +10,7 @@ import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.common.DamageTargetEffect;
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -28,12 +29,14 @@ public final class AetherfluxReservoir extends CardImpl {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
|
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.
|
// 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.
|
// Pay 50 life: Aetherflux Reservoir deals 50 damage to any target.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50));
|
Ability abilityPayLife = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50));
|
||||||
ability.addTarget(new TargetAnyTarget());
|
abilityPayLife.addTarget(new TargetAnyTarget());
|
||||||
this.addAbility(ability);
|
this.addAbility(abilityPayLife);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AetherfluxReservoir(final AetherfluxReservoir card) {
|
public AetherfluxReservoir(final AetherfluxReservoir card) {
|
||||||
|
|
|
@ -2,10 +2,13 @@ package mage.cards.s;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SpellCastAllTriggeredAbility;
|
import mage.abilities.common.SpellCastAllTriggeredAbility;
|
||||||
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.common.DamageTargetEffect;
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -44,13 +47,18 @@ public final class SentinelTower extends CardImpl {
|
||||||
|
|
||||||
class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
|
class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
|
||||||
|
|
||||||
|
private String damageInfo;
|
||||||
|
|
||||||
SentinelTowerTriggeredAbility() {
|
SentinelTowerTriggeredAbility() {
|
||||||
super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false);
|
super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false);
|
||||||
this.addTarget(new TargetAnyTarget());
|
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) {
|
SentinelTowerTriggeredAbility(final SentinelTowerTriggeredAbility effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.damageInfo = effect.damageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,6 +86,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
damageInfo = " (<b>" + damageToDeal + " damage</b>)";
|
||||||
for (Effect effect : this.getEffects()) {
|
for (Effect effect : this.getEffects()) {
|
||||||
if (effect instanceof DamageTargetEffect) {
|
if (effect instanceof DamageTargetEffect) {
|
||||||
((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal));
|
((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal));
|
||||||
|
@ -92,7 +101,8 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility {
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "Whenever an instant or sorcery spell is cast during your turn, "
|
return "Whenever an instant or sorcery spell is cast during your turn, "
|
||||||
+ "{this} deals damage to any target equal to 1 "
|
+ "{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;
|
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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||||
|
@ -13,7 +15,7 @@ import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.WatcherScope;
|
import mage.constants.WatcherScope;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterInstantOrSorcerySpell;
|
import mage.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
@ -23,9 +25,11 @@ import mage.watchers.Watcher;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author jasc7636
|
||||||
*/
|
*/
|
||||||
public final class ThousandYearStorm extends CardImpl {
|
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}");
|
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.
|
// 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) {
|
public ThousandYearStorm(final ThousandYearStorm card) {
|
||||||
|
@ -48,12 +52,12 @@ public final class ThousandYearStorm extends CardImpl {
|
||||||
|
|
||||||
class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
|
class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
|
||||||
|
|
||||||
String stormCountInfo = null;
|
private String stormCountInfo;
|
||||||
|
|
||||||
public ThousandYearStormAbility() {
|
public ThousandYearStormAbility() {
|
||||||
super(Zone.BATTLEFIELD, new ThousandYearStormEffect(), new FilterInstantOrSorcerySpell(), false, true);
|
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", ThousandYearSpellsCastThatTurnValue.instance));
|
this.addHint(new ValueHint("You've cast instant and sorcery this turn", ThousandYearStormSpellsCastThatTurnValue.instance));
|
||||||
this.addWatcher(new ThousandYearWatcher());
|
this.stormCountInfo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThousandYearStormAbility(final ThousandYearStormAbility ability) {
|
public ThousandYearStormAbility(final ThousandYearStormAbility ability) {
|
||||||
|
@ -63,12 +67,33 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
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)) {
|
if (super.checkTrigger(event, game)) {
|
||||||
int stormCount = ThousandYearSpellsCastThatTurnValue.instance.calculate(game, this, null);
|
ThousandYearStormWatcher watcher = game.getState().getWatcher(ThousandYearStormWatcher.class);
|
||||||
stormCountInfo = " (<b>storm count: " + Math.max(0, stormCount - 1) + "</b>) ";
|
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 true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,13 +110,16 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThousandYearStormEffect extends OneShotEffect {
|
class ThousandYearStormEffect extends OneShotEffect {
|
||||||
|
private int stormCount;
|
||||||
|
|
||||||
public ThousandYearStormEffect() {
|
public ThousandYearStormEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
|
this.stormCount = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThousandYearStormEffect(final ThousandYearStormEffect effect) {
|
public ThousandYearStormEffect(final ThousandYearStormEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.stormCount = effect.stormCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -102,82 +130,72 @@ class ThousandYearStormEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source));
|
Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source));
|
||||||
Player controller = spell != null ? game.getPlayer(spell.getControllerId()) : null;
|
if (stormCount >= 0 && spell != null) {
|
||||||
if (spell != null && controller != null) {
|
spell.createCopyOnStack(game, source, source.getControllerId(), true, stormCount);
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStormCount(int stormCount) {
|
||||||
|
this.stormCount = stormCount;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getText(Mode mode) {
|
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";
|
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);
|
super(WatcherScope.GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void watch(GameEvent event, Game game) {
|
public void watch(GameEvent event, Game game) {
|
||||||
if (event.getType() == GameEvent.EventType.SPELL_CAST && !sourceId.equals(event.getTargetId())) {
|
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
|
||||||
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
|
MageObject object = game.getObject(event.getTargetId());
|
||||||
if (spell != null && spell.isInstantOrSorcery()) {
|
if (object != null && (object.isInstant() || object.isSorcery())) {
|
||||||
UUID playerId = event.getPlayerId();
|
UUID playerId = event.getPlayerId();
|
||||||
if (playerId != null) {
|
List<MageObjectReference> spellsCast = spellsThisTurn.getOrDefault(playerId, new ArrayList<MageObjectReference>());
|
||||||
String stateSearchId = spell.getId().toString() + sourceId.toString();
|
spellsCast.add(new MageObjectReference(object, game));
|
||||||
// calc current spell
|
spellsThisTurn.put(playerId, spellsCast);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
amountOfInstantSorcerySpellsCastOnCurrentTurn.clear();
|
for (List<MageObjectReference> mor : spellsThisTurn.values()) {
|
||||||
|
mor.clear();
|
||||||
|
}
|
||||||
|
spellsThisTurn.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAmountOfSpellsPlayerCastOnCurrentTurn(UUID playerId) {
|
public List<MageObjectReference> getSpellsThisTurn(UUID playerId) {
|
||||||
return amountOfInstantSorcerySpellsCastOnCurrentTurn.getOrDefault(playerId, 0);
|
return spellsThisTurn.getOrDefault(playerId, new ArrayList<MageObjectReference>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ThousandYearSpellsCastThatTurnValue implements DynamicValue {
|
enum ThousandYearStormSpellsCastThatTurnValue implements DynamicValue {
|
||||||
|
|
||||||
instance;
|
instance;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
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) {
|
if (watcher == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId());
|
return watcher.getSpellsThisTurn(sourceAbility.getControllerId()).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ThousandYearSpellsCastThatTurnValue copy() {
|
public ThousandYearStormSpellsCastThatTurnValue copy() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue