forked from External/mage
implement [MH3] Primal Prayers ; use choice panel for cast mode choice ; allow some restricted "as thought as it had flash" to work only on matching alternative cast. (#12420)
This commit is contained in:
parent
503e842b51
commit
c0eab28626
67 changed files with 1105 additions and 596 deletions
|
|
@ -19,6 +19,9 @@ import mage.abilities.hint.Hint;
|
|||
import mage.abilities.icon.CardIcon;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceHintType;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.Dungeon;
|
||||
|
|
@ -255,7 +258,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
public boolean activate(Game game, Set<MageIdentifier> allowedIdentifiers, boolean noMana) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
|
|
@ -302,7 +305,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
// or her intentions to pay any or all of those costs (see rule 601.2e).
|
||||
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
|
||||
if (isMainPartAbility) {
|
||||
activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game);
|
||||
if (!activateAlternateOrAdditionalCosts(sourceObject, allowedIdentifiers, noMana, controller, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 117.6. Some mana costs contain no mana symbols. This represents an unpayable cost. An ability can
|
||||
|
|
@ -451,8 +456,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
return activated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if choices for the activation were made (can be to activate with the regular cost)
|
||||
*/
|
||||
@Override
|
||||
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
|
||||
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, Set<MageIdentifier> allowedIdentifiers, boolean noMana, Player controller, Game game) {
|
||||
boolean canUseAlternativeCost = true;
|
||||
boolean canUseAdditionalCost = true;
|
||||
|
||||
|
|
@ -494,48 +502,104 @@ public abstract class AbilityImpl implements Ability {
|
|||
canUseAlternativeCost = false;
|
||||
}
|
||||
|
||||
boolean alternativeCostUsed = false;
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
// it's important to apply alternative cost first
|
||||
// example: Omniscience gives free mana as alternative, but Entwine ability adds {2} as additional
|
||||
Abilities<Ability> abilities = CardUtil.getAbilities(sourceObject, game);
|
||||
// TODO: Why the check for permanent?
|
||||
if (sourceObject == null || sourceObject instanceof Permanent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1. ALTERNATIVE COSTS
|
||||
for (Ability ability : abilities) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (canUseAlternativeCost && !noMana && ability instanceof AlternativeSourceCosts) {
|
||||
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
||||
if (alternativeSpellCosts.isAvailable(this, game)) {
|
||||
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
|
||||
// only one alternative costs may be activated
|
||||
alternativeCostUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// controller specific alternate spell costs
|
||||
if (canUseAlternativeCost && !noMana && !alternativeCostUsed) {
|
||||
for (AlternativeSourceCosts alternativeSourceCosts : controller.getAlternativeSourceCosts()) {
|
||||
if (alternativeSourceCosts.isAvailable(this, game)) {
|
||||
if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) {
|
||||
// only one alternative costs may be activated
|
||||
alternativeCostUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// it's important to apply alternative cost first
|
||||
// example: Omniscience gives free mana as alternative, but Entwine ability adds {2} as additional
|
||||
Abilities<Ability> abilities = CardUtil.getAbilities(sourceObject, game);
|
||||
|
||||
// 2. ADDITIONAL COST
|
||||
for (Ability ability : abilities) {
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
// 1. ALTERNATIVE COSTS
|
||||
// Collect all possible alternatives costs:
|
||||
List<AlternativeSourceCosts> possibleAlternatives = new ArrayList<>();
|
||||
for (Ability ability : abilities) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (canUseAlternativeCost && !noMana && ability instanceof AlternativeSourceCosts) {
|
||||
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
||||
if (alternativeSpellCosts.isAvailable(this, game)
|
||||
&& alternativeSpellCosts.canActivateAlternativeCostsNow(this, game)
|
||||
&& (allowedIdentifiers.contains(MageIdentifier.Default) || allowedIdentifiers.contains(ability.getIdentifier()))) {
|
||||
possibleAlternatives.add(alternativeSpellCosts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alternativeCostUsed;
|
||||
// controller specific alternate spell costs
|
||||
if (canUseAlternativeCost && !noMana) {
|
||||
for (AlternativeSourceCosts alternativeSourceCosts : controller.getAlternativeSourceCosts()) {
|
||||
if (alternativeSourceCosts.isAvailable(this, game)
|
||||
&& alternativeSourceCosts.canActivateAlternativeCostsNow(this, game)
|
||||
&& (allowedIdentifiers.contains(MageIdentifier.Default) || allowedIdentifiers.contains(alternativeSourceCosts.getIdentifier()))) {
|
||||
possibleAlternatives.add(alternativeSourceCosts);
|
||||
}
|
||||
}
|
||||
}
|
||||
Player player = game.getPlayer(getControllerId());
|
||||
if (player == null) {
|
||||
// No controller to activate.
|
||||
return false;
|
||||
}
|
||||
Choice choice = new ChoiceImpl(false); // not required, cancelling will cancel the cast (as you could do once in the pay mana mode).
|
||||
choice.setSubMessage("for casting " + CardUtil.getSourceLogName(game, "", this, "", ""));
|
||||
AlternativeSourceCosts alternativeChosen = null;
|
||||
if (!possibleAlternatives.isEmpty()) {
|
||||
// At least one alternative cost is available.
|
||||
// We open a menu for the player to choose up to one.
|
||||
boolean mustChooseAlternative = !(allowedIdentifiers.contains(MageIdentifier.Default) || allowedIdentifiers.contains(getIdentifier()));
|
||||
choice.setMessage(
|
||||
mustChooseAlternative
|
||||
? "Choose an alternative cost"
|
||||
: "You may choose an alternative cost"
|
||||
);
|
||||
Map<String, Integer> sort = new LinkedHashMap<>();
|
||||
int i;
|
||||
for (i = 0; i < possibleAlternatives.size(); i++) {
|
||||
String key = Integer.toString(i + 1);
|
||||
sort.put(key, i);
|
||||
AlternativeSourceCosts alternative = possibleAlternatives.get(i);
|
||||
MageObject object = alternative.getSourceObject(game);
|
||||
choice.withItem(
|
||||
key,
|
||||
possibleAlternatives.get(i).getAlternativeCostText(this, game),
|
||||
i,
|
||||
object != null ? ChoiceHintType.GAME_OBJECT : null,
|
||||
object != null ? object.getId().toString() : null
|
||||
);
|
||||
}
|
||||
if (!mustChooseAlternative) {
|
||||
// add the non-alternative cast as the last option.
|
||||
String key = Integer.toString(i + 1);
|
||||
sort.put(key, i);
|
||||
choice.withItem(
|
||||
key,
|
||||
"Cast with no alternative cost: " + this.getManaCosts().getText(),
|
||||
i,
|
||||
ChoiceHintType.GAME_OBJECT,
|
||||
sourceObject.getId().toString()
|
||||
);
|
||||
}
|
||||
if (!player.choose(Outcome.Benefit, choice, game)) {
|
||||
return false;
|
||||
}
|
||||
String choiceKey = choice.getChoiceKey();
|
||||
if (sort.containsKey(choiceKey)) {
|
||||
int choiceNumber = sort.get(choiceKey);
|
||||
if (choiceNumber < possibleAlternatives.size()) {
|
||||
alternativeChosen = possibleAlternatives.get(choiceNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (alternativeChosen != null) {
|
||||
alternativeChosen.activateAlternativeCosts(this, game);
|
||||
}
|
||||
// 2. ADDITIONAL COST
|
||||
for (Ability ability : abilities) {
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue