mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
* Implemeented consumable flag for asThoughtEffects and a player choice which effect to use if multiple consumable effects allow the same action.
This commit is contained in:
parent
8105d8b26c
commit
90c6637dc2
10 changed files with 78 additions and 18 deletions
|
@ -57,7 +57,7 @@ public final class GisaAndGeralf extends CardImpl {
|
|||
class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
GisaAndGeralfCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay);
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay, true);
|
||||
staticText = "During each of your turns, you may cast a Zombie creature card from your graveyard";
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ class KaradorGhostChieftainCostReductionEffect extends CostModificationEffectImp
|
|||
class KaradorGhostChieftainCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
KaradorGhostChieftainCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay);
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay, true);
|
||||
staticText = "During each of your turns, you may cast one creature card from your graveyard";
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public final class KessDissidentMage extends CardImpl {
|
|||
class KessDissidentMageCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
KessDissidentMageCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit, true);
|
||||
staticText = "During each of your turns, you may cast an instant or sorcery card from your graveyard";
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ enum LurrusOfTheDreamDenCompanionCondition implements CompanionCondition {
|
|||
class LurrusOfTheDreamDenCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
LurrusOfTheDreamDenCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit, true);
|
||||
staticText = "During each of your turns, you may cast one permanent spell with converted mana cost 2 or less from your graveyard";
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public final class MuldrothaTheGravetide extends CardImpl {
|
|||
class MuldrothaTheGravetideCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
public MuldrothaTheGravetideCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit, true);
|
||||
staticText = "During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. "
|
||||
+ "<i>(If a card has multiple permanent types, choose one as you play it.)</i>";
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
|
|||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 7);
|
||||
|
||||
// Exile target creature you control, then return that card to the battlefield under your control.
|
||||
|
@ -96,7 +96,7 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore // It's not possible yet to select which ability to use to allow a asThoughtAs effect
|
||||
// @Ignore // It's not possible yet to select which ability to use to allow a asThoughtAs effect
|
||||
public void test_castFromGraveyardWithDifferentApprovers() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
|
@ -125,6 +125,8 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
|
|||
|
||||
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Accursed Horde");
|
||||
setChoice(playerA, "During each of your turns, you may cast a Zombie creature card from your graveyard"); // Choose the permitting object
|
||||
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion");
|
||||
|
||||
|
||||
|
|
|
@ -20,4 +20,6 @@ public interface AsThoughEffect extends ContinuousEffect {
|
|||
|
||||
@Override
|
||||
AsThoughEffect copy();
|
||||
|
||||
boolean isConsumable();
|
||||
}
|
||||
|
|
|
@ -17,16 +17,23 @@ import mage.players.Player;
|
|||
public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements AsThoughEffect {
|
||||
|
||||
protected AsThoughEffectType type;
|
||||
boolean consumable;
|
||||
|
||||
public AsThoughEffectImpl(AsThoughEffectType type, Duration duration, Outcome outcome) {
|
||||
this(type, duration, outcome, false);
|
||||
}
|
||||
|
||||
public AsThoughEffectImpl(AsThoughEffectType type, Duration duration, Outcome outcome, boolean consumable) {
|
||||
super(duration, outcome);
|
||||
this.type = type;
|
||||
this.effectType = EffectType.ASTHOUGH;
|
||||
this.consumable = consumable;
|
||||
}
|
||||
|
||||
public AsThoughEffectImpl(final AsThoughEffectImpl effect) {
|
||||
super(effect);
|
||||
this.type = effect.type;
|
||||
this.consumable = effect.consumable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,4 +100,9 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsumable() {
|
||||
return consumable;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.StaticAbility;
|
||||
|
@ -31,6 +30,8 @@ import java.util.*;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.ApprovingObject;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceImpl;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -333,7 +334,7 @@ public class ContinuousEffects implements Serializable {
|
|||
* @param event
|
||||
* @param game
|
||||
* @return a list of all {@link ReplacementEffect} that apply to the current
|
||||
* event
|
||||
* event
|
||||
*/
|
||||
private Map<ReplacementEffect, Set<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) {
|
||||
Map<ReplacementEffect, Set<Ability>> replaceEffects = new HashMap<>();
|
||||
|
@ -342,7 +343,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
// boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || event.getType().equals(EventType.DESTROYED_PERMANENT);
|
||||
//get all applicable transient Replacement effects
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext();) {
|
||||
ReplacementEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
@ -375,7 +376,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext();) {
|
||||
PreventionEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
@ -506,7 +507,7 @@ public class ContinuousEffects implements Serializable {
|
|||
* @param controllerId
|
||||
* @param game
|
||||
* @return sourceId of the permitting effect if any exists otherwise returns
|
||||
* null
|
||||
* null
|
||||
*/
|
||||
public ApprovingObject asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
|
||||
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
|
||||
|
@ -531,13 +532,18 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
Set<ApprovingObject> possibleApprovingObjects = new HashSet<>();
|
||||
for (AsThoughEffect effect : asThoughEffectsList) {
|
||||
Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (affectedAbility == null) {
|
||||
// applies to own ability (one effect can be used in multiple abilities)
|
||||
if (effect.applies(idToCheck, ability, controllerId, game)) {
|
||||
return new ApprovingObject(ability, game);
|
||||
if (effect.isConsumable() && !game.inCheckPlayableState()) {
|
||||
possibleApprovingObjects.add(new ApprovingObject(ability, game));
|
||||
} else {
|
||||
return new ApprovingObject(ability, game);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// applies to affected ability
|
||||
|
@ -548,11 +554,38 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
|
||||
if (effect.applies(idToCheck, affectedAbility, ability, game, controllerId)) {
|
||||
return new ApprovingObject(ability, game);
|
||||
if (effect.isConsumable() && !game.inCheckPlayableState()) {
|
||||
possibleApprovingObjects.add(new ApprovingObject(ability, game));
|
||||
} else {
|
||||
return new ApprovingObject(ability, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (possibleApprovingObjects.size() == 1) {
|
||||
return possibleApprovingObjects.iterator().next();
|
||||
} else if (possibleApprovingObjects.size() > 1) {
|
||||
// Select the ability that you use to permit the action
|
||||
Map<String, String> keyChoices = new HashMap<>();
|
||||
for(ApprovingObject approvingObject :possibleApprovingObjects) {
|
||||
MageObject mageObject = game.getObject(approvingObject.getApprovingAbility().getSourceId());
|
||||
keyChoices.put(approvingObject.getApprovingAbility().getId().toString(),
|
||||
(approvingObject.getApprovingAbility().getRule(mageObject == null ? "" : mageObject.getName()))
|
||||
+ (mageObject == null ? "" : " (" + mageObject.getIdName() + ")"));
|
||||
}
|
||||
Choice choicePermitting = new ChoiceImpl(true);
|
||||
choicePermitting.setMessage("Choose the permitting object");
|
||||
choicePermitting.setKeyChoices(keyChoices);
|
||||
Player player = game.getPlayer(controllerId);
|
||||
player.choose(Outcome.Detriment, choicePermitting, game);
|
||||
for(ApprovingObject approvingObject: possibleApprovingObjects) {
|
||||
if (approvingObject.getApprovingAbility().getId().toString().equals(choicePermitting.getChoiceKey())) {
|
||||
return approvingObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
|
||||
|
@ -800,7 +833,7 @@ public class ContinuousEffects implements Serializable {
|
|||
do {
|
||||
Map<ReplacementEffect, Set<Ability>> rEffects = getApplicableReplacementEffects(event, game);
|
||||
// Remove all consumed effects (ability dependant)
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext(); ) {
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
|
||||
ReplacementEffect entry = it1.next();
|
||||
if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9.
|
||||
Set<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
|
||||
|
@ -985,7 +1018,7 @@ public class ContinuousEffects implements Serializable {
|
|||
.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> dependentTo.contains(entry.getKey().getId())
|
||||
&& entry.getValue().contains(effect.getId()))
|
||||
&& entry.getValue().contains(effect.getId()))
|
||||
.forEach(entry -> {
|
||||
entry.getValue().remove(effect.getId());
|
||||
dependentTo.remove(entry.getKey().getId());
|
||||
|
@ -1019,7 +1052,7 @@ public class ContinuousEffects implements Serializable {
|
|||
continue;
|
||||
}
|
||||
// check if waiting effects can be applied now
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) {
|
||||
Map.Entry<ContinuousEffect, Set<UUID>> entry = iterator.next();
|
||||
if (!appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself
|
||||
continue;
|
||||
|
|
|
@ -215,6 +215,17 @@ public class ChoiceImpl implements Choice, Serializable {
|
|||
answers.remove(needChoice);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// no key answer found, try to macht by text starting with
|
||||
for (String needChoice : answers) {
|
||||
for (Map.Entry<String, String> currentChoice : this.getKeyChoices().entrySet()) {
|
||||
if (currentChoice.getValue().startsWith(needChoice)) {
|
||||
this.setChoiceByKey(currentChoice.getKey());
|
||||
answers.remove(needChoice);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -231,4 +242,4 @@ public class ChoiceImpl implements Choice, Serializable {
|
|||
}
|
||||
return false; // can't find answer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue