mirror of
https://github.com/correl/mage.git
synced 2025-01-11 11:05:23 +00:00
added modal abilities + Slagstorm
This commit is contained in:
parent
3a0b73cee9
commit
14d863a8f2
38 changed files with 484 additions and 60 deletions
|
@ -34,6 +34,8 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -50,6 +52,10 @@ public class AbilityPickerView implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
public AbilityPickerView(Map<UUID, String> modes) {
|
||||
this.choices = modes;
|
||||
}
|
||||
|
||||
public Map<UUID, String> getChoices() {
|
||||
return choices;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ import mage.MageObject;
|
|||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
|
@ -860,6 +862,13 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mode chooseMode(Modes modes, Ability source, Game game) {
|
||||
logger.debug("chooseMode");
|
||||
//TODO: improve this;
|
||||
return modes.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility chooseTriggeredAbility(TriggeredAbilities abilities, Game game) {
|
||||
logger.debug("chooseTriggeredAbility");
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
package mage.player.human;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -41,6 +42,8 @@ import mage.Constants.Zone;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
|
@ -564,6 +567,30 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> {
|
|||
activateAbility(abilities.get(response.getUUID()), game);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mode chooseMode(Modes modes, Ability source, Game game) {
|
||||
if (modes.size() > 1) {
|
||||
MageObject obj = game.getObject(source.getSourceId());
|
||||
Map<UUID, String> modeMap = new HashMap<UUID, String>();
|
||||
for (Mode mode: modes.values()) {
|
||||
String modeText = mode.getEffects().getText(source);
|
||||
if (obj != null)
|
||||
modeText = modeText.replace("{source}", obj.getName());
|
||||
modeMap.put(mode.getId(), modeText);
|
||||
}
|
||||
game.fireGetModeEvent(playerId, "Choose Mode", modeMap);
|
||||
waitForResponse();
|
||||
if (response.getUUID() != null) {
|
||||
for (Mode mode: modes.values()) {
|
||||
if (mode.getId().equals(response.getUUID()))
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return modes.getMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseString(String responseString) {
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -50,6 +50,7 @@ import java.util.zip.GZIPOutputStream;
|
|||
|
||||
import mage.Constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Modes;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.decks.Deck;
|
||||
|
@ -155,6 +156,9 @@ public class GameController implements GameCallback {
|
|||
case CHOOSE_ABILITY:
|
||||
chooseAbility(event.getPlayerId(), event.getAbilities());
|
||||
break;
|
||||
case CHOOSE_MODE:
|
||||
chooseMode(event.getPlayerId(), event.getModes());
|
||||
break;
|
||||
case CHOOSE:
|
||||
choose(event.getPlayerId(), event.getMessage(), event.getChoices());
|
||||
break;
|
||||
|
@ -352,6 +356,12 @@ public class GameController implements GameCallback {
|
|||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void chooseMode(UUID playerId, Map<UUID, String> modes) throws MageException {
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).chooseAbility(new AbilityPickerView(modes));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void choose(UUID playerId, String message, Set<String> choices) throws MageException {
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).choose(message, choices);
|
||||
|
|
|
@ -95,7 +95,7 @@ class FinestHourAbility extends TriggeredAbilityImpl<FinestHourAbility> {
|
|||
if (event.getType() == EventType.DECLARED_ATTACKERS) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
this.addTarget(new TargetCreaturePermanent());
|
||||
this.targets.get(0).add(game.getCombat().getAttackers().get(0), game);
|
||||
getTargets().get(0).add(game.getCombat().getAttackers().get(0), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ class FontOfMythosAbility extends TriggeredAbilityImpl<FontOfMythosAbility> {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == EventType.DRAW_STEP_PRE) {
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.targets.get(0).add(event.getPlayerId(),game);
|
||||
getTargets().get(0).add(event.getPlayerId(),game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -101,7 +101,7 @@ class WallOfReverenceTriggeredAbility extends TriggeredAbilityImpl<WallOfReveren
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "At the beginning of your end step, " + effects.getText(this);
|
||||
return "At the beginning of your end step, " + modes.getText(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class HowlingMineAbility extends TriggeredAbilityImpl<HowlingMineAbility> {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == EventType.DRAW_STEP_PRE) {
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -83,7 +83,7 @@ class LilianasCaressAbility extends TriggeredAbilityImpl<LilianasCaressAbility>
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == EventType.DISCARDED_CARD && game.getOpponents(controllerId).contains(event.getPlayerId())) {
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -89,7 +89,7 @@ class WildEvocationAbility extends TriggeredAbilityImpl<WildEvocationAbility> {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == EventType.DRAW_STEP_PRE) {
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
101
Mage.Sets/src/mage/sets/mirrodinbesieged/Slagstorm.java
Normal file
101
Mage.Sets/src/mage/sets/mirrodinbesieged/Slagstorm.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.sets.mirrodinbesieged;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.Constants.CardType;
|
||||
import mage.Constants.Rarity;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.DamageAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Loki
|
||||
*/
|
||||
public class Slagstorm extends CardImpl<Slagstorm> {
|
||||
|
||||
public Slagstorm (UUID ownerId) {
|
||||
super(ownerId, 75, "Slagstorm", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{1}{R}{R}");
|
||||
this.expansionSetCode = "MBS";
|
||||
this.color.setRed(true);
|
||||
this.getSpellAbility().addEffect(new DamageAllEffect(3, FilterCreaturePermanent.getDefault()));
|
||||
Mode mode = new Mode();
|
||||
mode.getEffects().add(new SlagstormEffect());
|
||||
this.getSpellAbility().addMode(mode);
|
||||
}
|
||||
|
||||
public Slagstorm (final Slagstorm card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slagstorm copy() {
|
||||
return new Slagstorm(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SlagstormEffect extends OneShotEffect<SlagstormEffect> {
|
||||
SlagstormEffect() {
|
||||
super(Constants.Outcome.Damage);
|
||||
}
|
||||
|
||||
SlagstormEffect(final SlagstormEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
for (UUID playerId: game.getPlayer(source.getControllerId()).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null)
|
||||
player.damage(3, source.getId(), game, false, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlagstormEffect copy() {
|
||||
return new SlagstormEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Ability source) {
|
||||
return "Slagstorm deals 3 damage to each player";
|
||||
}
|
||||
}
|
|
@ -100,7 +100,7 @@ class SuturePriestFirstTriggeredAbility extends TriggeredAbilityImpl<SuturePries
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever another creature enters the battlefield under your control, " + effects.getText(this);
|
||||
return "Whenever another creature enters the battlefield under your control, " + modes.getText(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ class SwordOfWarAndPeaceAbility extends TriggeredAbilityImpl<SwordOfWarAndPeaceA
|
|||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event;
|
||||
Permanent p = game.getPermanent(event.getSourceId());
|
||||
if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) {
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ class SwordOfBodyAndMindAbility extends TriggeredAbilityImpl<SwordOfBodyAndMindA
|
|||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event;
|
||||
Permanent p = game.getPermanent(event.getSourceId());
|
||||
if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) {
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ class RafiqOfTheManyAbility extends TriggeredAbilityImpl<RafiqOfTheManyAbility>
|
|||
if (event.getType() == EventType.DECLARED_ATTACKERS && game.getActivePlayerId().equals(this.controllerId) ) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
this.addTarget(new TargetCreaturePermanent());
|
||||
this.targets.get(0).add(game.getCombat().getAttackers().get(0), game);
|
||||
getTargets().get(0).add(game.getCombat().getAttackers().get(0), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ class HammerOfRuinTriggeredAbility extends TriggeredAbilityImpl<HammerOfRuinTrig
|
|||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event;
|
||||
Permanent p = game.getPermanent(event.getSourceId());
|
||||
if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) {
|
||||
FilterPermanent filter = (FilterPermanent) targets.get(0).getFilter();
|
||||
FilterPermanent filter = (FilterPermanent)getTargets().get(0).getFilter();
|
||||
filter.getControllerId().add(event.getPlayerId());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -330,4 +330,11 @@ public interface Ability extends Serializable {
|
|||
* @return A new copy of this ability.
|
||||
*/
|
||||
public Ability copy();
|
||||
|
||||
public boolean isModal();
|
||||
|
||||
public void addMode(Mode mode);
|
||||
|
||||
public Modes getModes();
|
||||
|
||||
}
|
||||
|
|
|
@ -73,9 +73,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
protected Costs<Cost> costs;
|
||||
protected ArrayList<AlternativeCost> alternativeCosts = new ArrayList<AlternativeCost>();
|
||||
protected Costs<Cost> optionalCosts;
|
||||
protected Targets targets;
|
||||
protected Choices choices;
|
||||
protected Effects effects;
|
||||
protected Modes modes;
|
||||
protected Zone zone;
|
||||
protected String name;
|
||||
protected boolean usesStack = true;
|
||||
|
@ -92,9 +90,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
this.manaCostsToPay = new ManaCostsImpl<ManaCost>();
|
||||
this.costs = new CostsImpl<Cost>();
|
||||
this.optionalCosts = new CostsImpl<Cost>();
|
||||
this.effects = new Effects();
|
||||
this.targets = new Targets();
|
||||
this.choices = new Choices();
|
||||
this.modes = new Modes();
|
||||
}
|
||||
|
||||
public AbilityImpl(final AbilityImpl<T> ability) {
|
||||
|
@ -113,9 +109,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
for (AlternativeCost cost: ability.alternativeCosts) {
|
||||
this.alternativeCosts.add((AlternativeCost)cost.copy());
|
||||
}
|
||||
this.targets = ability.targets.copy();
|
||||
this.choices = ability.choices.copy();
|
||||
this.effects = ability.effects.copy();
|
||||
this.modes = ability.modes.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,13 +146,16 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
// 20110204 - 700.2
|
||||
if (!modes.choose(game, this))
|
||||
return false;
|
||||
//20100716 - 601.2b
|
||||
if (choices.size() > 0 && choices.choose(game, this) == false) {
|
||||
if (getChoices().size() > 0 && getChoices().choose(game, this) == false) {
|
||||
logger.debug("activate failed - choice");
|
||||
return false;
|
||||
}
|
||||
//20100716 - 601.2b
|
||||
if (targets.size() > 0 && targets.chooseTargets(effects.get(0).getOutcome(), this.controllerId, this, game) == false) {
|
||||
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
||||
logger.debug("activate failed - target");
|
||||
return false;
|
||||
}
|
||||
|
@ -258,13 +255,13 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
|
||||
@Override
|
||||
public Effects getEffects() {
|
||||
return effects;
|
||||
return modes.getMode().getEffects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Effects getEffects(EffectType effectType) {
|
||||
Effects typedEffects = new Effects();
|
||||
for (Effect effect: effects) {
|
||||
for (Effect effect: getEffects()) {
|
||||
if (effect.getEffectType() == effectType) {
|
||||
typedEffects.add(effect);
|
||||
}
|
||||
|
@ -274,7 +271,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
|
||||
@Override
|
||||
public Choices getChoices() {
|
||||
return choices;
|
||||
return modes.getMode().getChoices();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -323,7 +320,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
sbRule.append(effects.getText(this));
|
||||
sbRule.append(modes.getText(this));
|
||||
|
||||
return sbRule.toString();
|
||||
}
|
||||
|
@ -371,34 +368,49 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
|||
@Override
|
||||
public void addEffect(Effect effect) {
|
||||
if (effect != null) {
|
||||
this.effects.add(effect);
|
||||
getEffects().add(effect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTarget(Target target) {
|
||||
if (target != null) {
|
||||
this.targets.add(target);
|
||||
getTargets().add(target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChoice(Choice choice) {
|
||||
if (choice != null) {
|
||||
this.choices.add(choice);
|
||||
getChoices().add(choice);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Targets getTargets() {
|
||||
return this.targets;
|
||||
return modes.getMode().getTargets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getFirstTarget() {
|
||||
return targets.getFirstTarget();
|
||||
return getTargets().getFirstTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModal() {
|
||||
return this.modes.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMode(Mode mode) {
|
||||
this.modes.addMode(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Modes getModes() {
|
||||
return modes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRule();
|
||||
|
|
|
@ -148,7 +148,7 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
|
|||
return false;
|
||||
//20091005 - 602.5d/602.5e
|
||||
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId)) {
|
||||
if (costs.canPay(sourceId, controllerId, game) && targets.canChoose(sourceId, playerId, game)) {
|
||||
if (costs.canPay(sourceId, controllerId, game) && getTargets().canChoose(sourceId, playerId, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -174,9 +174,9 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
|
|||
protected String getMessageText(Game game) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(game.getObject(this.sourceId).getName());
|
||||
if (this.targets.size() > 0) {
|
||||
if (getTargets().size() > 0) {
|
||||
sb.append(" targeting ");
|
||||
for (Target target: targets) {
|
||||
for (Target target: getTargets()) {
|
||||
sb.append(target.getTargetedName(game));
|
||||
}
|
||||
}
|
||||
|
|
79
Mage/src/mage/abilities/Mode.java
Normal file
79
Mage/src/mage/abilities/Mode.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.choices.Choices;
|
||||
import mage.target.Targets;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Mode {
|
||||
|
||||
protected UUID id;
|
||||
protected Targets targets;
|
||||
protected Choices choices;
|
||||
protected Effects effects;
|
||||
|
||||
public Mode() {
|
||||
this.id = UUID.randomUUID();
|
||||
this.targets = new Targets();
|
||||
this.choices = new Choices();
|
||||
this.effects = new Effects();
|
||||
}
|
||||
|
||||
public Mode(Mode mode) {
|
||||
this.id = mode.id;
|
||||
this.targets = mode.targets.copy();
|
||||
this.choices = mode.choices.copy();
|
||||
this.effects = mode.effects.copy();
|
||||
}
|
||||
|
||||
public Mode copy() {
|
||||
return new Mode(this);
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Targets getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
public Choices getChoices() {
|
||||
return choices;
|
||||
}
|
||||
|
||||
public Effects getEffects() {
|
||||
return effects;
|
||||
}
|
||||
}
|
109
Mage/src/mage/abilities/Modes.java
Normal file
109
Mage/src/mage/abilities/Modes.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Modes extends HashMap<UUID, Mode> {
|
||||
|
||||
private UUID modeId;
|
||||
|
||||
public Modes() {
|
||||
Mode mode = new Mode();
|
||||
this.put(mode.getId(), mode);
|
||||
this.modeId = mode.getId();
|
||||
}
|
||||
|
||||
public Modes(Modes modes) {
|
||||
this.modeId = modes.modeId;
|
||||
for (Mode mode: modes.values()) {
|
||||
this.put(mode.getId(), mode.copy());
|
||||
}
|
||||
}
|
||||
|
||||
public Modes copy() {
|
||||
return new Modes(this);
|
||||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return get(modeId);
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
if (this.containsKey(mode.getId()))
|
||||
this.modeId = mode.getId();
|
||||
}
|
||||
|
||||
public void addMode(Mode mode) {
|
||||
this.put(mode.getId(), mode);
|
||||
}
|
||||
|
||||
public boolean choose(Game game, Ability source) {
|
||||
if (this.size() > 1) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Mode choice = player.chooseMode(this, source, game);
|
||||
if (choice == null)
|
||||
return false;
|
||||
setMode(choice);
|
||||
return true;
|
||||
}
|
||||
this.modeId = this.values().iterator().next().getId();
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getText(Ability source) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Choose one - ");
|
||||
for (Mode mode: this.values()) {
|
||||
sb.append(mode.getEffects().getText(source)).append("; or ");
|
||||
}
|
||||
sb.delete(sb.length() - 5, sb.length());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getText(Ability source, String sourceName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Choose one - ");
|
||||
for (Mode mode: this.values()) {
|
||||
sb.append(mode.getEffects().getText(source)).append("; or ");
|
||||
}
|
||||
sb.delete(sb.length() - 5, sb.length());
|
||||
String text = sb.toString();
|
||||
text = text.replace("{this}", sourceName);
|
||||
text = text.replace("{source}", sourceName);
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
|
@ -61,7 +61,7 @@ public class SpellAbility extends ActivatedAbilityImpl<SpellAbility> {
|
|||
object.getAbilities().containsKey(FlashAbility.getInstance().getId()) ||
|
||||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, game) ||
|
||||
game.canPlaySorcery(playerId))) {
|
||||
if (costs.canPay(sourceId, controllerId, game) && targets.canChoose(sourceId, playerId, game)) {
|
||||
if (costs.canPay(sourceId, controllerId, game) && getTargets().canChoose(sourceId, playerId, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +82,8 @@ public class SpellAbility extends ActivatedAbilityImpl<SpellAbility> {
|
|||
}
|
||||
|
||||
public void clear() {
|
||||
this.choices.clearChosen();
|
||||
this.targets.clearChosen();
|
||||
getChoices().clearChosen();
|
||||
getTargets().clearChosen();
|
||||
this.manaCosts.clearPaid();
|
||||
this.costs.clearPaid();
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ public abstract class TriggeredAbilityImpl<T extends TriggeredAbilityImpl<T>> ex
|
|||
sb.append("Use ").append(this.getRule()).append("ability");
|
||||
}
|
||||
sb.append("?");
|
||||
if (!player.chooseUse(this.effects.get(0).getOutcome(), sb.toString(), game)) {
|
||||
if (!player.chooseUse(getEffects().get(0).getOutcome(), sb.toString(), game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,11 +52,11 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl<Begi
|
|||
public String getRule() {
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return "At the beginning of your upkeep, " + effects.getText(this);
|
||||
return "At the beginning of your upkeep, " + getEffects().getText(this);
|
||||
case OPPONENT:
|
||||
return "At the beginning of each opponent's upkeep, " + effects.getText(this);
|
||||
return "At the beginning of each opponent's upkeep, " + getEffects().getText(this);
|
||||
case ANY:
|
||||
return "At the beginning of each player's upkeep, " + effects.getText(this);
|
||||
return "At the beginning of each player's upkeep, " + getEffects().getText(this);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == EventType.DAMAGED_PLAYER && event.getSourceId().equals(this.sourceId)) {
|
||||
this.targets.clear();
|
||||
getTargets().clear();
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.targets.get(0).add(event.getPlayerId(), game);
|
||||
getTargets().get(0).add(event.getPlayerId(), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -29,6 +29,6 @@ public class AtTheEndOfCombatDelayedTriggeredAbility extends DelayedTriggeredAbi
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "At end of combat, " + effects.getText(this);
|
||||
return "At end of combat, " + modes.getText(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl<Conditiona
|
|||
public ConditionalTriggeredAbility(TriggeredAbility ability, Condition condition, String text) {
|
||||
super(ability.getZone(), null);
|
||||
this.ability = ability;
|
||||
this.effects = ability.getEffects();
|
||||
this.modes = ability.getModes();
|
||||
this.condition = condition;
|
||||
this.text = text;
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl<Conditiona
|
|||
ability.setSourceId(this.getSourceId());
|
||||
if (ability.checkTrigger(event, game)) {
|
||||
if (condition.apply(game, this)) {
|
||||
this.targets.clear();
|
||||
this.targets.addAll(ability.getTargets());
|
||||
getTargets().clear();
|
||||
getTargets().addAll(ability.getTargets());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,11 +63,11 @@ public class KickerAbility extends StaticAbility<KickerAbility> {
|
|||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
Player player = game.getPlayer(this.getControllerId());
|
||||
String message = "Use kicker - " + this.effects.get(0).getText(this) + "?";
|
||||
String message = "Use kicker - " + getEffects().get(0).getText(this) + "?";
|
||||
Card card = game.getCard(sourceId);
|
||||
// replace by card name or just plain "this"
|
||||
message = message.replace("{this}", card == null ? "this" : card.getName());
|
||||
if (player.chooseUse(this.effects.get(0).getOutcome(), message, game)) {
|
||||
if (player.chooseUse(getEffects().get(0).getOutcome(), message, game)) {
|
||||
game.bookmarkState();
|
||||
if (super.activate(game, noMana)) {
|
||||
game.removeLastBookmark();
|
||||
|
@ -101,7 +101,7 @@ public class KickerAbility extends StaticAbility<KickerAbility> {
|
|||
}
|
||||
if (costs.size() > 0)
|
||||
sb.append(costs.getText());
|
||||
sb.append(":").append(effects.getText(this));
|
||||
sb.append(":").append(modes.getText(this));
|
||||
if (replaces)
|
||||
sb.append(" instead");
|
||||
return sb.toString();
|
||||
|
|
|
@ -87,7 +87,7 @@ public class MultikickerAbility extends KickerAbility {
|
|||
}
|
||||
if (costs.size() > 0)
|
||||
sb.append(costs.getText());
|
||||
sb.append(":").append(effects.getText(this));
|
||||
sb.append(":").append(modes.getText(this));
|
||||
if (replaces)
|
||||
sb.append(" instead");
|
||||
return sb.toString();
|
||||
|
|
|
@ -42,6 +42,7 @@ import mage.MageItem;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
|
@ -128,6 +129,7 @@ public interface Game extends MageItem, Serializable {
|
|||
public void firePlayManaEvent(UUID playerId, String message);
|
||||
public void firePlayXManaEvent(UUID playerId, String message);
|
||||
public void fireGetChoiceEvent(UUID playerId, String message, Collection<? extends ActivatedAbility> choices);
|
||||
public void fireGetModeEvent(UUID playerId, String message, Map<UUID, String> modes);
|
||||
public void fireGetAmountEvent(UUID playerId, String message, int min, int max);
|
||||
public void fireInformEvent(String message);
|
||||
public void fireUpdatePlayersEvent();
|
||||
|
|
|
@ -785,6 +785,11 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
playerQueryEventSource.chooseAbility(playerId, message, choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireGetModeEvent(UUID playerId, String message, Map<UUID, String> modes) {
|
||||
playerQueryEventSource.chooseMode(playerId, message, modes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireSelectTargetEvent(UUID playerId, String message, Set<UUID> targets, boolean required, Map<String, Serializable> options) {
|
||||
playerQueryEventSource.target(playerId, message, targets, required, options);
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.*;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
|
@ -46,7 +47,7 @@ import mage.game.permanent.Permanent;
|
|||
public class PlayerQueryEvent extends EventObject implements ExternalEvent, Serializable {
|
||||
|
||||
public enum QueryType {
|
||||
ASK, CHOOSE, CHOOSE_ABILITY, PICK_TARGET, PICK_ABILITY, SELECT, PLAY_MANA, PLAY_X_MANA, AMOUNT, LOOK, PICK_CARD, CONSTRUCT
|
||||
ASK, CHOOSE, CHOOSE_ABILITY, CHOOSE_MODE, PICK_TARGET, PICK_ABILITY, SELECT, PLAY_MANA, PLAY_X_MANA, AMOUNT, LOOK, PICK_CARD, CONSTRUCT
|
||||
}
|
||||
|
||||
private String message;
|
||||
|
@ -63,6 +64,7 @@ public class PlayerQueryEvent extends EventObject implements ExternalEvent, Seri
|
|||
private int max;
|
||||
private Deck deck;
|
||||
private Map<String, Serializable> options;
|
||||
private Map<UUID, String> modes;
|
||||
|
||||
private PlayerQueryEvent(UUID playerId, String message, Collection<? extends Ability> abilities, Set<String> choices, Set<UUID> targets, Cards cards, QueryType queryType, int min, int max, boolean required, Map<String, Serializable> options) {
|
||||
this(playerId, message, abilities, choices, targets, cards, queryType, min, max, required);
|
||||
|
@ -110,6 +112,14 @@ public class PlayerQueryEvent extends EventObject implements ExternalEvent, Seri
|
|||
this.required = required;
|
||||
}
|
||||
|
||||
private PlayerQueryEvent(UUID playerId, String message, Map<UUID, String> modes) {
|
||||
super(playerId);
|
||||
this.queryType = QueryType.CHOOSE_MODE;
|
||||
this.message = message;
|
||||
this.playerId = playerId;
|
||||
this.modes = modes;
|
||||
}
|
||||
|
||||
public static PlayerQueryEvent askEvent(UUID playerId, String message) {
|
||||
return new PlayerQueryEvent(playerId, message, null, null, null, null, QueryType.ASK, 0, 0, false);
|
||||
}
|
||||
|
@ -117,6 +127,11 @@ public class PlayerQueryEvent extends EventObject implements ExternalEvent, Seri
|
|||
public static PlayerQueryEvent chooseAbilityEvent(UUID playerId, String message, Collection<? extends ActivatedAbility> choices) {
|
||||
return new PlayerQueryEvent(playerId, message, choices, null, null, null, QueryType.CHOOSE_ABILITY, 0, 0, false);
|
||||
}
|
||||
|
||||
public static PlayerQueryEvent chooseModeEvent(UUID playerId, String message, Map<UUID, String> modes) {
|
||||
return new PlayerQueryEvent(playerId, message, modes);
|
||||
}
|
||||
|
||||
public static PlayerQueryEvent chooseEvent(UUID playerId, String message, Set<String> choices) {
|
||||
return new PlayerQueryEvent(playerId, message, null, choices, null, null, QueryType.CHOOSE, 0, 0, false);
|
||||
}
|
||||
|
@ -225,4 +240,8 @@ public class PlayerQueryEvent extends EventObject implements ExternalEvent, Seri
|
|||
public Map<String, Serializable> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public Map<UUID, String> getModes() {
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import java.io.Serializable;
|
|||
import java.util.*;
|
||||
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
|
@ -63,6 +65,10 @@ public class PlayerQueryEventSource implements EventSource<PlayerQueryEvent>, Se
|
|||
dispatcher.fireEvent(PlayerQueryEvent.chooseAbilityEvent(playerId, message, choices));
|
||||
}
|
||||
|
||||
public void chooseMode(UUID playerId, String message, Map<UUID, String> modes) {
|
||||
dispatcher.fireEvent(PlayerQueryEvent.chooseModeEvent(playerId, message, modes));
|
||||
}
|
||||
|
||||
public void target(UUID playerId, String message, Set<UUID> targets, boolean required) {
|
||||
dispatcher.fireEvent(PlayerQueryEvent.targetEvent(playerId, message, targets, required));
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ package mage.game.stack;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import mage.Constants.AbilityType;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.costs.AlternativeCost;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
|
@ -288,9 +290,7 @@ public class StackAbility implements StackObject, Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalCost(Cost cost) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
public void addOptionalCost(Cost cost) {}
|
||||
|
||||
@Override
|
||||
public boolean checkIfClause(Game game) {
|
||||
|
@ -298,11 +298,22 @@ public class StackAbility implements StackObject, Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void newId() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
public void newId() {}
|
||||
|
||||
public Ability getStackAbility() {
|
||||
return ability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModal() {
|
||||
return ability.isModal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMode(Mode mode) {}
|
||||
|
||||
@Override
|
||||
public Modes getModes() {
|
||||
return ability.getModes();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ import mage.MageObject;
|
|||
import mage.abilities.Abilities;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.Modes;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
|
@ -156,6 +158,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
public abstract boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game);
|
||||
public abstract int chooseEffect(List<ReplacementEffect> rEffects, Game game);
|
||||
public abstract TriggeredAbility chooseTriggeredAbility(TriggeredAbilities abilities, Game game);
|
||||
public abstract Mode chooseMode(Modes modes, Ability source, Game game);
|
||||
public abstract void selectAttackers(Game game);
|
||||
public abstract void selectBlockers(Game game);
|
||||
public abstract UUID chooseBlockerOrder(List<Permanent> blockers, Game game);
|
||||
|
|
|
@ -46,6 +46,7 @@ import mage.abilities.Abilities;
|
|||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.PlayLandAbility;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
@ -936,8 +937,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
@Override
|
||||
public List<Ability> getPlayableOptions(Ability ability, Game game) {
|
||||
List<Ability> options = new ArrayList<Ability>();
|
||||
|
||||
if (ability.getTargets().getUnchosen().size() > 0)
|
||||
|
||||
if (ability.isModal())
|
||||
addModeOptions(options, ability, game);
|
||||
else if (ability.getTargets().getUnchosen().size() > 0)
|
||||
addTargetOptions(options, ability, 0, game);
|
||||
else if (ability.getChoices().getUnchosen().size() > 0)
|
||||
addChoiceOptions(options, ability, 0, game);
|
||||
|
@ -947,6 +950,21 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
return options;
|
||||
}
|
||||
|
||||
private void addModeOptions(List<Ability> options, Ability option, Game game) {
|
||||
for (Mode mode: option.getModes().values()) {
|
||||
Ability newOption = option.copy();
|
||||
newOption.getModes().setMode(mode);
|
||||
if (option.getTargets().getUnchosen().size() > 0)
|
||||
addTargetOptions(options, option, 0, game);
|
||||
else if (option.getChoices().getUnchosen().size() > 0)
|
||||
addChoiceOptions(options, option, 0, game);
|
||||
else if (option.getCosts().getTargets().getUnchosen().size() > 0)
|
||||
addCostTargetOptions(options, option, 0, game);
|
||||
else
|
||||
options.add(newOption);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTargetOptions(List<Ability> options, Ability option, int targetNum, Game game) {
|
||||
for (UUID targetId: option.getTargets().getUnchosen().get(targetNum).possibleTargets(option.getSourceId(), playerId, game)) {
|
||||
Ability newOption = option.copy();
|
||||
|
|
Loading…
Reference in a new issue