Reworking effects which allow casting spells from a selection of cards (ready for review) (#8136)

* added function for casting spells with specific attributes from a selection of cards

* updated cascade to use new method

* refactored various cards to use new methods

* added TestPlayer method

* fixed a small error

* text fix

* broke out some repeated code

* added missing notTarget setting

* add additional retain zone check

* some more cards refactored

* more refactoring

* added interface for split/modal cards

* reworked spell casting methods

* reworked multiple cast to prevent unnecessary dialogs

* fixed test failures due to change in functionality

* add AI code

* small nonfunctional change

* reworked Kaya, the Inexorable

* added currently failing test

* added more tests

* updated Geode Golem implementation

* fixed adventure/cascade interaction, added/updated tests

* some nonfunctional refactoring

* added interface for subcards

* [AFC] Implemented Fevered Suspicion

* [AFC] Implemented Extract Brain

* [AFC] updated Arcane Endeavor implementation

* [C17] reworked implementation of Izzet Chemister

* [ZEN] reworked implemented of Chandra Ablaze

* additional merge fix

* [SLD] updated Eleven, the Mage

* [NEO] Implemented Discover the Impossible

* [NEO] Implemented The Dragon-Kami Reborn / Dragon-Kami's Egg

* [NEO] Implemented Invoke Calamity

* [AFR] Implemented Rod of Absorption

* [VOC] Implemented Spectral Arcanist

* [VOC] added additional printings

* [NEO] added all variants

* [SLD] updated implementation of Ken, Burning Brawler
This commit is contained in:
Evan Kranzler 2022-03-09 08:03:54 -05:00 committed by GitHub
parent 7fb089db48
commit bbb9382150
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 2551 additions and 2059 deletions

View file

@ -1571,72 +1571,75 @@ public abstract class PlayerImpl implements Player, Serializable {
* @param noMana
* @return
*/
public static LinkedHashMap<UUID, ActivatedAbility> getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) {
public static LinkedHashMap<UUID, SpellAbility> getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) {
// it uses simple check from spellCanBeActivatedRegularlyNow
// reason: no approved info here (e.g. forced to choose spell ability from cast card)
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
LinkedHashMap<UUID, SpellAbility> useable = new LinkedHashMap<>();
Abilities<Ability> allAbilities;
if (object instanceof Card) {
allAbilities = ((Card) object).getAbilities(game);
} else {
allAbilities = object.getAbilities();
}
for (Ability ability : allAbilities) {
if (ability instanceof SpellAbility) {
SpellAbility spellAbility = (SpellAbility) ability;
switch (spellAbility.getSpellAbilityType()) {
case BASE_ALTERNATE:
// rules:
// If you cast a spell without paying its mana cost, you cant choose to cast it for
// any alternative costs. You can, however, pay additional costs, such as kicker costs.
// If the card has any mandatory additional costs, those must be paid to cast the spell.
// (2021-02-05)
if (!noMana) {
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability
}
return useable;
for (SpellAbility spellAbility : allAbilities
.stream()
.filter(SpellAbility.class::isInstance)
.map(SpellAbility.class::cast)
.collect(Collectors.toList())) {
switch (spellAbility.getSpellAbilityType()) {
case BASE_ALTERNATE:
// rules:
// If you cast a spell without paying its mana cost, you cant choose to cast it for
// any alternative costs. You can, however, pay additional costs, such as kicker costs.
// If the card has any mandatory additional costs, those must be paid to cast the spell.
// (2021-02-05)
if (!noMana) {
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability
}
break;
case SPLIT_FUSED:
// rules:
// If you cast a split card with fuse from your hand without paying its mana cost,
// you can choose to use its fuse ability and cast both halves without paying their mana costs.
if (zone == Zone.HAND) {
if (spellAbility.canChooseTarget(game, playerId)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
case SPLIT:
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
return useable;
}
break;
case SPLIT_FUSED:
// rules:
// If you cast a split card with fuse from your hand without paying its mana cost,
// you can choose to use its fuse ability and cast both halves without paying their mana costs.
if (zone == Zone.HAND) {
if (spellAbility.canChooseTarget(game, playerId)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
case SPLIT:
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(
((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility()
);
}
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(
((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility()
);
}
return useable;
case SPLIT_AFTERMATH:
if (zone == Zone.GRAVEYARD) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
return useable;
case SPLIT_AFTERMATH:
if (zone == Zone.GRAVEYARD) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
} else {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}
} else {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}
return useable;
default:
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
}
return useable;
default:
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
}
return useable;