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:
Susucre 2024-07-30 15:47:39 +02:00 committed by GitHub
parent 503e842b51
commit c0eab28626
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 1105 additions and 596 deletions

View file

@ -16,6 +16,7 @@ import mage.players.Player;
import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
@ -79,10 +80,20 @@ public class SpellAbility extends ActivatedAbilityImpl {
* can be casted that are affected by the CastAsInstant effect.
* (i.e. Vizier of the Menagerie and issue #5816)
*/
public boolean spellCanBeActivatedRegularlyNow(UUID playerId, Game game) {
private static final Set<MageIdentifier> activationSetAllowAll = new HashSet();
static {
activationSetAllowAll.add(MageIdentifier.Default);
}
/**
* @return the set of cast method MageIdentifer that are allowed to be cast at this time (if MageIdentifier.Default is in it, there is no restriction)
*/
public Set<MageIdentifier> spellCanBeActivatedNow(UUID playerId, Game game) {
MageObject object = game.getObject(sourceId);
if (object == null) {
return false;
return Collections.emptySet();
}
// forced to cast (can be part id or main id)
@ -93,23 +104,48 @@ public class SpellAbility extends ActivatedAbilityImpl {
}
for (UUID idToCheck : idsToCheck) {
if (game.getState().getValue("PlayFromNotOwnHandZone" + idToCheck) != null) {
return (Boolean) game.getState().getValue("PlayFromNotOwnHandZone" + idToCheck); // card like Chandra, Torch of Defiance +1 loyal ability)
if ((Boolean) game.getState().getValue("PlayFromNotOwnHandZone" + idToCheck)) {
return activationSetAllowAll;
} else {
return Collections.emptySet();
}
}
}
return !game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game).isEmpty() // check this first to allow Offering in main phase
|| timing == TimingRule.INSTANT
// OfferingAbility is doing side effects in its asThough computation.
// so we call it before the timing check.
// TODO: maybe Offering could be reworked with the MageIdentifier solution of linking
// CAST_AS_INSTANT with alternative cast methods?
Set<ApprovingObject> asInstantApprovers = game.getContinuousEffects()
.asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game);
if (timing == TimingRule.INSTANT
|| object.isInstant(game)
|| object.hasAbility(FlashAbility.getInstance(), game)
|| game.canPlaySorcery(playerId);
|| game.canPlaySorcery(playerId)) {
return activationSetAllowAll;
}
// In case there is a need for as AsThoughEffectType.CAST_AS_INSTANT, we do collect the MageIdentifer of the approving objects
// to match later on with the real method to cast. When only non-Default MageIdentifier are used, only some of the alternative
// cast are possible to activate.
Set<MageIdentifier> setOfIdentifier = new HashSet<>();
setOfIdentifier.addAll(
asInstantApprovers
.stream()
.map(ApprovingObject::getApprovingAbility)
.map(Ability::getIdentifier)
.collect(Collectors.toSet())
);
return setOfIdentifier;
}
@Override
public ActivationStatus canActivate(UUID playerId, Game game) {
// spells can be cast from non hand zones, so must use custom check
// no super.canActivate() call
if (this.spellCanBeActivatedRegularlyNow(playerId, game)) {
Set<MageIdentifier> allowedIdentifiers = this.spellCanBeActivatedNow(playerId, game);
if (!allowedIdentifiers.isEmpty()) {
if (spellAbilityType == SpellAbilityType.SPLIT
|| spellAbilityType == SpellAbilityType.SPLIT_AFTERMATH) {
return ActivationStatus.getFalse();