mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 19:41:59 -08:00
Reworking effects that allow controlling combat (WIP) (#8159)
* reworked effects that allow controlling combat * [AFC] Implemented Berserker's Frenzy * [AFC] updated Berserker's Frenzy to roll correctly
This commit is contained in:
parent
f5177097cd
commit
f7e821be2f
12 changed files with 366 additions and 492 deletions
107
Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java
Normal file
107
Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
package mage.cards.b;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.RollDieWithResultTableEffect;
|
||||||
|
import mage.abilities.effects.common.combat.BlocksIfAbleTargetEffect;
|
||||||
|
import mage.abilities.effects.common.combat.ChooseBlockersEffect;
|
||||||
|
import mage.abilities.hint.ConditionHint;
|
||||||
|
import mage.abilities.hint.Hint;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
import mage.target.targetpointer.FixedTargets;
|
||||||
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class BerserkersFrenzy extends CardImpl {
|
||||||
|
|
||||||
|
private static final Hint hint = new ConditionHint(BerserkersFrenzyCondition.instance, "Can be cast");
|
||||||
|
|
||||||
|
public BerserkersFrenzy(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
|
||||||
|
|
||||||
|
// Cast this spell only before combat or during combat before blockers are declared.
|
||||||
|
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(
|
||||||
|
null, null, BerserkersFrenzyCondition.instance,
|
||||||
|
"Cast this spell only before combat or during combat before blockers are declared"
|
||||||
|
).addHint(hint));
|
||||||
|
|
||||||
|
// Roll two d20 and ignore the lower roll.
|
||||||
|
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
|
||||||
|
20, "roll two d20 and ignore the lower roll", StaticValue.get(0), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1-14 | Choose any number of creatures. They block this turn if able.
|
||||||
|
effect.addTableEntry(1, 14, new BerserkersFrenzyEffect());
|
||||||
|
|
||||||
|
// 15-20 | You choose which creatures block this turn and how those creatures block.
|
||||||
|
effect.addTableEntry(15, 20, new ChooseBlockersEffect(Duration.EndOfTurn));
|
||||||
|
this.getSpellAbility().addEffect(effect);
|
||||||
|
this.getSpellAbility().addWatcher(new ControlCombatRedundancyWatcher());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BerserkersFrenzy(final BerserkersFrenzy card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BerserkersFrenzy copy() {
|
||||||
|
return new BerserkersFrenzy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BerserkersFrenzyCondition implements Condition {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
if (game.getPhase().getType() == TurnPhase.COMBAT) {
|
||||||
|
return game.getStep().getType().isBefore(PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
}
|
||||||
|
return !game.getTurn().isDeclareAttackersStepStarted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BerserkersFrenzyEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
BerserkersFrenzyEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "choose any number of creatures. They block this turn if able";
|
||||||
|
}
|
||||||
|
|
||||||
|
private BerserkersFrenzyEffect(final BerserkersFrenzyEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BerserkersFrenzyEffect copy() {
|
||||||
|
return new BerserkersFrenzyEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
|
if (player == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TargetPermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE);
|
||||||
|
target.setNotTarget(true);
|
||||||
|
player.choose(outcome, target, source.getSourceId(), game);
|
||||||
|
game.addEffect(new BlocksIfAbleTargetEffect(Duration.EndOfTurn)
|
||||||
|
.setTargetPointer(new FixedTargets(new CardsImpl(target.getTargets()), game)), source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
|
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||||
import mage.abilities.effects.common.combat.BlocksIfAbleAllEffect;
|
import mage.abilities.effects.common.combat.BlocksIfAbleAllEffect;
|
||||||
|
import mage.abilities.effects.common.combat.ChooseBlockersEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
|
|
@ -19,12 +16,12 @@ import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class BrutalHordechief extends CardImpl {
|
public final class BrutalHordechief extends CardImpl {
|
||||||
|
|
@ -36,7 +33,7 @@ public final class BrutalHordechief extends CardImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BrutalHordechief(UUID ownerId, CardSetInfo setInfo) {
|
public BrutalHordechief(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
|
||||||
this.subtype.add(SubType.ORC, SubType.WARRIOR);
|
this.subtype.add(SubType.ORC, SubType.WARRIOR);
|
||||||
this.power = new MageInt(3);
|
this.power = new MageInt(3);
|
||||||
this.toughness = new MageInt(3);
|
this.toughness = new MageInt(3);
|
||||||
|
|
@ -45,10 +42,11 @@ public final class BrutalHordechief extends CardImpl {
|
||||||
this.addAbility(new BrutalHordechiefTriggeredAbility());
|
this.addAbility(new BrutalHordechiefTriggeredAbility());
|
||||||
|
|
||||||
// {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
// {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{3}{R/W}{R/W}"));
|
Ability ability = new SimpleActivatedAbility(
|
||||||
ability.addEffect(new BrutalHordechiefChooseBlockersEffect());
|
new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{R/W}{R/W}")
|
||||||
ability.addWatcher(new ChooseBlockersRedundancyWatcher());
|
);
|
||||||
ability.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
|
ability.addEffect(new ChooseBlockersEffect(Duration.EndOfTurn).setText("and you choose how those creatures block"));
|
||||||
|
ability.addWatcher(new ControlCombatRedundancyWatcher());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,32 +58,6 @@ public final class BrutalHordechief extends CardImpl {
|
||||||
public BrutalHordechief copy() {
|
public BrutalHordechief copy() {
|
||||||
return new BrutalHordechief(this);
|
return new BrutalHordechief(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect() {
|
|
||||||
super(Outcome.Neutral);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher != null) {
|
|
||||||
watcher.increment();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
|
|
||||||
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
|
class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
@ -112,9 +84,9 @@ class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
Permanent source = game.getPermanent(event.getSourceId());
|
Permanent source = game.getPermanent(event.getSourceId());
|
||||||
if (source != null && source.isControlledBy(controllerId)) {
|
if (source != null && source.isControlledBy(getControllerId())) {
|
||||||
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(event.getSourceId(), game);
|
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(event.getSourceId(), game);
|
||||||
this.getEffects().get(0).setTargetPointer(new FixedTarget(defendingPlayerId));
|
this.getEffects().setTargetPointer(new FixedTarget(defendingPlayerId));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -125,50 +97,3 @@ class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
return "Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life.";
|
return "Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
|
||||||
|
|
||||||
public BrutalHordechiefChooseBlockersEffect() {
|
|
||||||
super(Duration.EndOfTurn, Outcome.Benefit, false, false);
|
|
||||||
staticText = "You choose which creatures block this turn and how those creatures block";
|
|
||||||
}
|
|
||||||
|
|
||||||
public BrutalHordechiefChooseBlockersEffect(final BrutalHordechiefChooseBlockersEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BrutalHordechiefChooseBlockersEffect copy() {
|
|
||||||
return new BrutalHordechiefChooseBlockersEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
|
||||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if(watcher == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.decrement();
|
|
||||||
if (watcher.copyCountApply > 0) {
|
|
||||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.copyCountApply = watcher.copyCount;
|
|
||||||
Player blockController = game.getPlayer(source.getControllerId());
|
|
||||||
if (blockController != null) {
|
|
||||||
game.getCombat().selectBlockers(blockController, source, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public final class DivinersPortent extends CardImpl {
|
||||||
// Roll a d20 and add the number of cards in your hand.
|
// Roll a d20 and add the number of cards in your hand.
|
||||||
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
|
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
|
||||||
20, "roll a d20 and add the number " +
|
20, "roll a d20 and add the number " +
|
||||||
"of cards in your hand", CardsInControllerHandCount.instance
|
"of cards in your hand", CardsInControllerHandCount.instance, 0
|
||||||
);
|
);
|
||||||
this.getSpellAbility().addEffect(effect);
|
this.getSpellAbility().addEffect(effect);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
|
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||||
import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition;
|
import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.RequirementEffect;
|
import mage.abilities.effects.RequirementEffect;
|
||||||
import mage.abilities.effects.RestrictionEffect;
|
import mage.abilities.effects.RestrictionEffect;
|
||||||
import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect;
|
import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect;
|
||||||
import mage.abilities.effects.common.combat.CantAttackTargetEffect;
|
import mage.abilities.effects.common.combat.CantAttackTargetEffect;
|
||||||
|
import mage.abilities.effects.common.combat.ChooseBlockersEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.TargetController;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
|
|
@ -23,11 +23,13 @@ import mage.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author L_J
|
* @author L_J
|
||||||
*/
|
*/
|
||||||
public final class MasterWarcraft extends CardImpl {
|
public final class MasterWarcraft extends CardImpl {
|
||||||
|
|
@ -36,20 +38,19 @@ public final class MasterWarcraft extends CardImpl {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R/W}{R/W}");
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R/W}{R/W}");
|
||||||
|
|
||||||
// Cast Master Warcraft only before attackers are declared.
|
// Cast Master Warcraft only before attackers are declared.
|
||||||
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, BeforeAttackersAreDeclaredCondition.instance, "Cast this spell only before attackers are declared"));
|
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(
|
||||||
|
null, null, BeforeAttackersAreDeclaredCondition.instance,
|
||||||
|
"Cast this spell only before attackers are declared"
|
||||||
|
));
|
||||||
|
|
||||||
// You choose which creatures attack this turn.
|
// You choose which creatures attack this turn.
|
||||||
this.getSpellAbility().addEffect(new MasterWarcraftChooseAttackersEffect());
|
this.getSpellAbility().addEffect(new MasterWarcraftChooseAttackersEffect());
|
||||||
|
|
||||||
// You choose which creatures block this turn and how those creatures block.
|
// You choose which creatures block this turn and how those creatures block.
|
||||||
this.getSpellAbility().addEffect(new MasterWarcraftChooseBlockersEffect());
|
this.getSpellAbility().addEffect(new ChooseBlockersEffect(Duration.EndOfTurn).concatBy("<br>"));
|
||||||
|
|
||||||
|
|
||||||
// (only the last resolved Master Warcraft spell's effects apply)
|
// (only the last resolved Master Warcraft spell's effects apply)
|
||||||
this.getSpellAbility().addWatcher(new MasterWarcraftCastWatcher());
|
this.getSpellAbility().addWatcher(new ControlCombatRedundancyWatcher());
|
||||||
this.getSpellAbility().addEffect(new MasterWarcraftCastWatcherIncrementEffect());
|
|
||||||
this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher());
|
|
||||||
this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MasterWarcraft(final MasterWarcraft card) {
|
private MasterWarcraft(final MasterWarcraft card) {
|
||||||
|
|
@ -60,73 +61,22 @@ public final class MasterWarcraft extends CardImpl {
|
||||||
public MasterWarcraft copy() {
|
public MasterWarcraft copy() {
|
||||||
return new MasterWarcraft(this);
|
return new MasterWarcraft(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MasterWarcraftCastWatcherIncrementEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
MasterWarcraftCastWatcherIncrementEffect() {
|
|
||||||
super(Outcome.Neutral);
|
|
||||||
}
|
|
||||||
|
|
||||||
MasterWarcraftCastWatcherIncrementEffect(final MasterWarcraftCastWatcherIncrementEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
MasterWarcraftCastWatcher watcher = game.getState().getWatcher(MasterWarcraftCastWatcher.class);
|
|
||||||
if (watcher != null) {
|
|
||||||
watcher.increment();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MasterWarcraftCastWatcherIncrementEffect copy() {
|
|
||||||
return new MasterWarcraftCastWatcherIncrementEffect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect() {
|
|
||||||
super(Outcome.Neutral);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher != null) {
|
|
||||||
watcher.increment();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
|
|
||||||
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectImpl {
|
class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that will attack this combat (creatures not chosen won't attack this combat)");
|
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that will attack this combat (creatures not chosen won't attack this combat)");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(TargetController.ACTIVE.getControllerPredicate());
|
filter.add(TargetController.ACTIVE.getControllerPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public MasterWarcraftChooseAttackersEffect() {
|
MasterWarcraftChooseAttackersEffect() {
|
||||||
super(Duration.EndOfTurn, Outcome.Benefit, false, false);
|
super(Duration.EndOfTurn, Outcome.Benefit, false, false);
|
||||||
staticText = "You choose which creatures attack this turn";
|
staticText = "You choose which creatures attack this turn";
|
||||||
}
|
}
|
||||||
|
|
||||||
public MasterWarcraftChooseAttackersEffect(final MasterWarcraftChooseAttackersEffect effect) {
|
private MasterWarcraftChooseAttackersEffect(final MasterWarcraftChooseAttackersEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,131 +95,54 @@ class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectI
|
||||||
return event.getType() == GameEvent.EventType.DECLARING_ATTACKERS;
|
return event.getType() == GameEvent.EventType.DECLARING_ATTACKERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
ControlCombatRedundancyWatcher.addAttackingController(source.getControllerId(), duration, game);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
MasterWarcraftCastWatcher watcher = game.getState().getWatcher(MasterWarcraftCastWatcher.class);
|
if (!ControlCombatRedundancyWatcher.checkAttackingController(source.getControllerId(), game)) {
|
||||||
if(watcher == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.decrement();
|
|
||||||
if (watcher.copyCountApply > 0) {
|
|
||||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
watcher.copyCountApply = watcher.copyCount;
|
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Player attackingPlayer = game.getPlayer(game.getCombat().getAttackingPlayerId());
|
Player attackingPlayer = game.getPlayer(game.getCombat().getAttackingPlayerId());
|
||||||
if (controller != null && attackingPlayer != null && !attackingPlayer.getAvailableAttackers(game).isEmpty()) {
|
if (controller == null || attackingPlayer == null || attackingPlayer.getAvailableAttackers(game).isEmpty()) {
|
||||||
Target target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
|
return false; // the attack declaration resumes for the active player as normal
|
||||||
if (controller.chooseTarget(Outcome.Benefit, target, source, game)) {
|
}
|
||||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) {
|
Target target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
|
||||||
|
if (!controller.chooseTarget(Outcome.Benefit, target, source, game)) {
|
||||||
// Choose creatures that will be attacking this combat
|
return false; // the attack declaration resumes for the active player as normal
|
||||||
if (target.getTargets().contains(permanent.getId())) {
|
}
|
||||||
RequirementEffect effect = new AttacksIfAbleTargetEffect(Duration.EndOfCombat);
|
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) {
|
||||||
effect.setText("");
|
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
// Choose creatures that will be attacking this combat
|
||||||
game.addEffect(effect, source);
|
if (target.getTargets().contains(permanent.getId())) {
|
||||||
game.informPlayers(controller.getLogName() + " has decided that " + permanent.getLogName() + " attacks this combat if able");
|
RequirementEffect effect = new AttacksIfAbleTargetEffect(Duration.EndOfCombat);
|
||||||
|
effect.setText("");
|
||||||
// All other creatures can't attack (unless they must attack)
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
} else {
|
game.addEffect(effect, source);
|
||||||
boolean hasToAttack = false;
|
game.informPlayers(controller.getLogName() + " has decided that " + permanent.getLogName() + " attacks this combat if able");
|
||||||
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(permanent, false, game).entrySet()) {
|
|
||||||
RequirementEffect effect2 = entry.getKey();
|
// All other creatures can't attack (unless they must attack)
|
||||||
if (effect2.mustAttack(game)) {
|
} else {
|
||||||
hasToAttack = true;
|
boolean hasToAttack = false;
|
||||||
}
|
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(permanent, false, game).entrySet()) {
|
||||||
}
|
RequirementEffect effect2 = entry.getKey();
|
||||||
if (!hasToAttack) {
|
if (effect2.mustAttack(game)) {
|
||||||
RestrictionEffect effect = new CantAttackTargetEffect(Duration.EndOfCombat);
|
hasToAttack = true;
|
||||||
effect.setText("");
|
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hasToAttack) {
|
||||||
|
RestrictionEffect effect = new CantAttackTargetEffect(Duration.EndOfCombat);
|
||||||
|
effect.setText("");
|
||||||
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // the attack declaration resumes for the active player as normal
|
return false; // the attack declaration resumes for the active player as normal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MasterWarcraftChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
|
||||||
|
|
||||||
public MasterWarcraftChooseBlockersEffect() {
|
|
||||||
super(Duration.EndOfTurn, Outcome.Benefit, false, false);
|
|
||||||
staticText = "You choose which creatures block this turn and how those creatures block";
|
|
||||||
}
|
|
||||||
|
|
||||||
public MasterWarcraftChooseBlockersEffect(final MasterWarcraftChooseBlockersEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MasterWarcraftChooseBlockersEffect copy() {
|
|
||||||
return new MasterWarcraftChooseBlockersEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
|
||||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if(watcher == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.decrement();
|
|
||||||
if (watcher.copyCountApply > 0) {
|
|
||||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.copyCountApply = watcher.copyCount;
|
|
||||||
Player blockController = game.getPlayer(source.getControllerId());
|
|
||||||
if (blockController != null) {
|
|
||||||
game.getCombat().selectBlockers(blockController, source, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MasterWarcraftCastWatcher extends Watcher {
|
|
||||||
|
|
||||||
public int copyCount = 0;
|
|
||||||
public int copyCountApply = 0;
|
|
||||||
|
|
||||||
public MasterWarcraftCastWatcher() {
|
|
||||||
super(WatcherScope.GAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
copyCount = 0;
|
|
||||||
copyCountApply = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void watch(GameEvent event, Game game) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void increment() {
|
|
||||||
copyCount++;
|
|
||||||
copyCountApply = copyCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void decrement() {
|
|
||||||
if (copyCountApply > 0) {
|
|
||||||
copyCountApply--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.DelayedTriggeredAbility;
|
import mage.abilities.DelayedTriggeredAbility;
|
||||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||||
import mage.abilities.condition.CompoundCondition;
|
import mage.abilities.condition.CompoundCondition;
|
||||||
|
|
@ -8,25 +7,23 @@ import mage.abilities.condition.Condition;
|
||||||
import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition;
|
import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition;
|
||||||
import mage.abilities.condition.common.IsPhaseCondition;
|
import mage.abilities.condition.common.IsPhaseCondition;
|
||||||
import mage.abilities.condition.common.MyTurnCondition;
|
import mage.abilities.condition.common.MyTurnCondition;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||||
import mage.abilities.effects.common.RemoveFromCombatTargetEffect;
|
import mage.abilities.effects.common.RemoveFromCombatTargetEffect;
|
||||||
import mage.abilities.effects.common.UntapTargetEffect;
|
import mage.abilities.effects.common.UntapTargetEffect;
|
||||||
|
import mage.abilities.effects.common.combat.ChooseBlockersEffect;
|
||||||
import mage.abilities.hint.ConditionHint;
|
import mage.abilities.hint.ConditionHint;
|
||||||
|
import mage.abilities.hint.Hint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.TurnPhase;
|
import mage.constants.TurnPhase;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.combat.CombatGroup;
|
import mage.game.combat.CombatGroup;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -35,21 +32,26 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class Melee extends CardImpl {
|
public final class Melee extends CardImpl {
|
||||||
|
|
||||||
|
private static final Condition condition = new CompoundCondition(
|
||||||
|
BeforeBlockersAreDeclaredCondition.instance,
|
||||||
|
new IsPhaseCondition(TurnPhase.COMBAT),
|
||||||
|
MyTurnCondition.instance
|
||||||
|
);
|
||||||
|
private static final Hint hint = new ConditionHint(condition, "Can be cast");
|
||||||
|
|
||||||
public Melee(UUID ownerId, CardSetInfo setInfo) {
|
public Melee(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}");
|
||||||
|
|
||||||
// Cast Melee only during your turn and only during combat before blockers are declared.
|
// Cast Melee only during your turn and only during combat before blockers are declared.
|
||||||
Condition condition = new CompoundCondition(BeforeBlockersAreDeclaredCondition.instance,
|
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(
|
||||||
new IsPhaseCondition(TurnPhase.COMBAT),
|
null, null, condition,
|
||||||
MyTurnCondition.instance);
|
"Cast this spell only during your turn and only during combat before blockers are declared"
|
||||||
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, condition, "Cast this spell only during your turn and only during combat before blockers are declared")
|
).addHint(hint));
|
||||||
.addHint(new ConditionHint(condition, "Can cast melee (it's combat phase on your turn)")));
|
|
||||||
|
|
||||||
// You choose which creatures block this combat and how those creatures block.
|
// You choose which creatures block this combat and how those creatures block.
|
||||||
// (only the last resolved Melee spell's blocking effect applies)
|
// (only the last resolved Melee spell's blocking effect applies)
|
||||||
this.getSpellAbility().addEffect(new MeleeChooseBlockersEffect());
|
this.getSpellAbility().addEffect(new ChooseBlockersEffect(Duration.EndOfCombat));
|
||||||
this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher());
|
this.getSpellAbility().addWatcher(new ControlCombatRedundancyWatcher());
|
||||||
this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
|
|
||||||
|
|
||||||
// Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
|
// Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
|
||||||
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new MeleeTriggeredAbility()));
|
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new MeleeTriggeredAbility()));
|
||||||
|
|
@ -63,82 +65,6 @@ public final class Melee extends CardImpl {
|
||||||
public Melee copy() {
|
public Melee copy() {
|
||||||
return new Melee(this);
|
return new Melee(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect() {
|
|
||||||
super(Outcome.Neutral);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher != null) {
|
|
||||||
watcher.increment();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
|
|
||||||
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MeleeChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
|
||||||
|
|
||||||
public MeleeChooseBlockersEffect() {
|
|
||||||
super(Duration.EndOfCombat, Outcome.Benefit, false, false);
|
|
||||||
staticText = "You choose which creatures block this combat and how those creatures block";
|
|
||||||
}
|
|
||||||
|
|
||||||
public MeleeChooseBlockersEffect(final MeleeChooseBlockersEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MeleeChooseBlockersEffect copy() {
|
|
||||||
return new MeleeChooseBlockersEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
|
||||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.decrement();
|
|
||||||
watcher.copyCount--;
|
|
||||||
if (watcher.copyCountApply > 0) {
|
|
||||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
|
||||||
this.discard();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.copyCountApply = watcher.copyCount;
|
|
||||||
Player blockController = game.getPlayer(source.getControllerId());
|
|
||||||
if (blockController != null) {
|
|
||||||
game.getCombat().selectBlockers(blockController, source, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.discard();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MeleeTriggeredAbility extends DelayedTriggeredAbility {
|
class MeleeTriggeredAbility extends DelayedTriggeredAbility {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
package mage.cards.o;
|
package mage.cards.o;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.common.combat.ChooseBlockersEffect;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.keyword.FirstStrikeAbility;
|
import mage.abilities.keyword.FirstStrikeAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.players.Player;
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author noxx
|
* @author noxx
|
||||||
|
|
@ -49,9 +47,8 @@ public final class OdricMasterTactician extends CardImpl {
|
||||||
class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl {
|
class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public OdricMasterTacticianTriggeredAbility() {
|
public OdricMasterTacticianTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new OdricMasterTacticianChooseBlockersEffect());
|
super(Zone.BATTLEFIELD, new ChooseBlockersEffect(Duration.EndOfCombat));
|
||||||
this.addWatcher(new ChooseBlockersRedundancyWatcher());
|
this.addWatcher(new ControlCombatRedundancyWatcher());
|
||||||
this.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) {
|
public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) {
|
||||||
|
|
@ -72,80 +69,4 @@ class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
return game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId);
|
return game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect() {
|
|
||||||
super(Outcome.Neutral);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher != null) {
|
|
||||||
watcher.increment();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
|
|
||||||
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OdricMasterTacticianChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
|
||||||
|
|
||||||
public OdricMasterTacticianChooseBlockersEffect() {
|
|
||||||
super(Duration.EndOfCombat, Outcome.Benefit, false, false);
|
|
||||||
staticText = "Whenever {this} and at least three other creatures attack, you choose which creatures block this combat and how those creatures block";
|
|
||||||
}
|
|
||||||
|
|
||||||
public OdricMasterTacticianChooseBlockersEffect(final OdricMasterTacticianChooseBlockersEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OdricMasterTacticianChooseBlockersEffect copy() {
|
|
||||||
return new OdricMasterTacticianChooseBlockersEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
|
||||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
|
||||||
ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class);
|
|
||||||
if (watcher == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.decrement();
|
|
||||||
watcher.copyCount--;
|
|
||||||
if (watcher.copyCountApply > 0) {
|
|
||||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
|
||||||
this.discard();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
watcher.copyCountApply = watcher.copyCount;
|
|
||||||
Player blockController = game.getPlayer(source.getControllerId());
|
|
||||||
if (blockController != null) {
|
|
||||||
game.getCombat().selectBlockers(blockController, source, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.discard();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public final class Revivify extends CardImpl {
|
||||||
// Roll a d20 and add the number of creature cards in your graveyard that were put there from the battlefield this turn.
|
// Roll a d20 and add the number of creature cards in your graveyard that were put there from the battlefield this turn.
|
||||||
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
|
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
|
||||||
20, "roll a d20 and add the number of creature cards " +
|
20, "roll a d20 and add the number of creature cards " +
|
||||||
"in your graveyard that were put there from the battlefield this turn", xValue
|
"in your graveyard that were put there from the battlefield this turn", xValue, 0
|
||||||
);
|
);
|
||||||
this.getSpellAbility().addEffect(effect);
|
this.getSpellAbility().addEffect(effect);
|
||||||
this.getSpellAbility().addWatcher(new CardsPutIntoGraveyardWatcher());
|
this.getSpellAbility().addWatcher(new CardsPutIntoGraveyardWatcher());
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ public final class ForgottenRealmsCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Bedevil", 179, Rarity.RARE, mage.cards.b.Bedevil.class));
|
cards.add(new SetCardInfo("Bedevil", 179, Rarity.RARE, mage.cards.b.Bedevil.class));
|
||||||
cards.add(new SetCardInfo("Behemoth Sledge", 180, Rarity.UNCOMMON, mage.cards.b.BehemothSledge.class));
|
cards.add(new SetCardInfo("Behemoth Sledge", 180, Rarity.UNCOMMON, mage.cards.b.BehemothSledge.class));
|
||||||
cards.add(new SetCardInfo("Belt of Giant Strength", 38, Rarity.RARE, mage.cards.b.BeltOfGiantStrength.class));
|
cards.add(new SetCardInfo("Belt of Giant Strength", 38, Rarity.RARE, mage.cards.b.BeltOfGiantStrength.class));
|
||||||
|
cards.add(new SetCardInfo("Berserker's Frenzy", 29, Rarity.RARE, mage.cards.b.BerserkersFrenzy.class));
|
||||||
cards.add(new SetCardInfo("Bituminous Blast", 181, Rarity.UNCOMMON, mage.cards.b.BituminousBlast.class));
|
cards.add(new SetCardInfo("Bituminous Blast", 181, Rarity.UNCOMMON, mage.cards.b.BituminousBlast.class));
|
||||||
cards.add(new SetCardInfo("Bogardan Hellkite", 115, Rarity.MYTHIC, mage.cards.b.BogardanHellkite.class));
|
cards.add(new SetCardInfo("Bogardan Hellkite", 115, Rarity.MYTHIC, mage.cards.b.BogardanHellkite.class));
|
||||||
cards.add(new SetCardInfo("Bojuka Bog", 226, Rarity.COMMON, mage.cards.b.BojukaBog.class));
|
cards.add(new SetCardInfo("Bojuka Bog", 226, Rarity.COMMON, mage.cards.b.BojukaBog.class));
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
||||||
private final String prefixText;
|
private final String prefixText;
|
||||||
private final List<TableEntry> resultsTable = new ArrayList<>();
|
private final List<TableEntry> resultsTable = new ArrayList<>();
|
||||||
private final DynamicValue modifier;
|
private final DynamicValue modifier;
|
||||||
|
private final int toIgnore;
|
||||||
|
|
||||||
public RollDieWithResultTableEffect() {
|
public RollDieWithResultTableEffect() {
|
||||||
this(20);
|
this(20);
|
||||||
|
|
@ -37,14 +38,15 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RollDieWithResultTableEffect(int sides, String prefixText) {
|
public RollDieWithResultTableEffect(int sides, String prefixText) {
|
||||||
this(sides, prefixText, StaticValue.get(0));
|
this(sides, prefixText, StaticValue.get(0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RollDieWithResultTableEffect(int sides, String prefixText, DynamicValue modifier) {
|
public RollDieWithResultTableEffect(int sides, String prefixText, DynamicValue modifier, int toIgnore) {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
this.sides = sides;
|
this.sides = sides;
|
||||||
this.prefixText = prefixText;
|
this.prefixText = prefixText;
|
||||||
this.modifier = modifier;
|
this.modifier = modifier;
|
||||||
|
this.toIgnore = toIgnore;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RollDieWithResultTableEffect(final RollDieWithResultTableEffect effect) {
|
protected RollDieWithResultTableEffect(final RollDieWithResultTableEffect effect) {
|
||||||
|
|
@ -55,6 +57,7 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
||||||
this.resultsTable.add(tableEntry.copy());
|
this.resultsTable.add(tableEntry.copy());
|
||||||
}
|
}
|
||||||
this.modifier = effect.modifier.copy();
|
this.modifier = effect.modifier.copy();
|
||||||
|
this.toIgnore = effect.toIgnore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -68,7 +71,9 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int result = player.rollDice(outcome, source, game, sides) + modifier.calculate(game, source, this);
|
int result = player.rollDice(
|
||||||
|
outcome, source, game, sides, 1 + toIgnore, toIgnore
|
||||||
|
).get(0) + modifier.calculate(game, source, this);
|
||||||
this.applyResult(result, game, source);
|
this.applyResult(result, game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
package mage.abilities.effects.common.combat;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author L_J, TheElk801
|
||||||
|
*/
|
||||||
|
public class ChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
public ChooseBlockersEffect(Duration duration) {
|
||||||
|
super(duration, Outcome.Benefit, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChooseBlockersEffect(final ChooseBlockersEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChooseBlockersEffect copy() {
|
||||||
|
return new ChooseBlockersEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
ControlCombatRedundancyWatcher.addBlockingController(source.getControllerId(), this.duration, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
if (!ControlCombatRedundancyWatcher.checkBlockingController(source.getControllerId(), game)) {
|
||||||
|
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Player blockController = game.getPlayer(source.getControllerId());
|
||||||
|
if (blockController != null) {
|
||||||
|
game.getCombat().selectBlockers(blockController, source, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText(Mode mode) {
|
||||||
|
if (staticText != null && !staticText.isEmpty()) {
|
||||||
|
return staticText;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder("you choose which creatures block this ");
|
||||||
|
switch (duration) {
|
||||||
|
case EndOfTurn:
|
||||||
|
sb.append("turn");
|
||||||
|
break;
|
||||||
|
case EndOfCombat:
|
||||||
|
sb.append("combat");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("duration type not supported");
|
||||||
|
}
|
||||||
|
sb.append(" and how those creatures block");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package mage.watchers.common;
|
|
||||||
|
|
||||||
import mage.constants.WatcherScope;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.events.GameEvent;
|
|
||||||
import mage.watchers.Watcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author L_J
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ChooseBlockersRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects
|
|
||||||
|
|
||||||
public int copyCount = 0;
|
|
||||||
public int copyCountApply = 0;
|
|
||||||
|
|
||||||
public ChooseBlockersRedundancyWatcher() {
|
|
||||||
super(WatcherScope.GAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
super.reset();
|
|
||||||
copyCount = 0;
|
|
||||||
copyCountApply = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void watch(GameEvent event, Game game) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void increment() {
|
|
||||||
copyCount++;
|
|
||||||
copyCountApply = copyCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void decrement() {
|
|
||||||
if (copyCountApply > 0) {
|
|
||||||
copyCountApply--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package mage.watchers.common;
|
||||||
|
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.WatcherScope;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author L_J
|
||||||
|
*/
|
||||||
|
public class ControlCombatRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects
|
||||||
|
|
||||||
|
private static final class PlayerDuration {
|
||||||
|
|
||||||
|
private final Duration duration;
|
||||||
|
private final UUID playerId;
|
||||||
|
|
||||||
|
private PlayerDuration(Duration duration, UUID playerId) {
|
||||||
|
this.duration = duration;
|
||||||
|
this.playerId = playerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCombat() {
|
||||||
|
return duration == Duration.EndOfCombat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPlayer(UUID playerId) {
|
||||||
|
return playerId.equals(this.playerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<PlayerDuration> attackingControllers = new ArrayList<>();
|
||||||
|
private final List<PlayerDuration> blockingControllers = new ArrayList<>();
|
||||||
|
|
||||||
|
public ControlCombatRedundancyWatcher() {
|
||||||
|
super(WatcherScope.GAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
attackingControllers.clear();
|
||||||
|
blockingControllers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void watch(GameEvent event, Game game) {
|
||||||
|
if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) {
|
||||||
|
attackingControllers.removeIf(PlayerDuration::isCombat);
|
||||||
|
blockingControllers.removeIf(PlayerDuration::isCombat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addAttackingController(UUID playerId, Duration duration, Game game) {
|
||||||
|
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||||
|
watcher.attackingControllers.add(0, new PlayerDuration(duration, playerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addBlockingController(UUID playerId, Duration duration, Game game) {
|
||||||
|
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||||
|
watcher.blockingControllers.add(0, new PlayerDuration(duration, playerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkAttackingController(UUID playerId, Game game) {
|
||||||
|
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||||
|
return !watcher.attackingControllers.isEmpty() && watcher.attackingControllers.get(0).isPlayer(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkBlockingController(UUID playerId, Game game) {
|
||||||
|
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||||
|
return !watcher.blockingControllers.isEmpty() && watcher.blockingControllers.get(0).isPlayer(playerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue