mirror of
https://github.com/magefree/mage.git
synced 2026-01-10 04:42:07 -08:00
refactor: fixed that TargetCard doesn't work with Zone.ALL;
This commit is contained in:
parent
bfceb07c58
commit
450f7bd907
13 changed files with 257 additions and 38 deletions
|
|
@ -125,7 +125,7 @@ public class WishEffect extends OneShotEffect {
|
|||
|
||||
TargetCard target = new TargetCard(Zone.ALL, filter);
|
||||
target.withNotTarget(true);
|
||||
if (controller.choose(Outcome.Benefit, filteredCards, target, source, game)) {
|
||||
if (controller.choose(Outcome.PutCardInPlay, filteredCards, target, source, game)) {
|
||||
Card card = controller.getSideboard().get(target.getFirstTarget(), game);
|
||||
if (card == null && alsoFromExile) {
|
||||
card = game.getCard(target.getFirstTarget());
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ public enum Outcome {
|
|||
LoseLife(false),
|
||||
ExtraTurn(true),
|
||||
BecomeCreature(true),
|
||||
PutCreatureInPlay(true),
|
||||
PutCardInPlay(true),
|
||||
PutLandInPlay(true),
|
||||
PutCreatureInPlay(true, true),
|
||||
PutCardInPlay(true, true),
|
||||
PutLandInPlay(true, true),
|
||||
GainControl(false),
|
||||
DrawCard(true),
|
||||
Discard(false),
|
||||
Sacrifice(false),
|
||||
PlayForFree(true),
|
||||
PlayForFree(true, true),
|
||||
ReturnToHand(false),
|
||||
Exile(false),
|
||||
Protect(true),
|
||||
|
|
@ -46,7 +46,7 @@ public enum Outcome {
|
|||
// AI sorting targets by priorities (own or opponents) and selects most valueable or weakest
|
||||
private final boolean good;
|
||||
|
||||
// no different between own or opponent targets (example: copy must choose from all permanents)
|
||||
// no different between own or opponent targets (example: copy must choose from all permanents, free cast from selected cards, etc)
|
||||
private boolean anyTargetHasSameValue;
|
||||
|
||||
Outcome(boolean good) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
|
@ -63,6 +64,13 @@ public interface Target extends Copyable<Target>, Serializable {
|
|||
*/
|
||||
Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game);
|
||||
|
||||
default Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game, Set<UUID> cards) {
|
||||
// do not override
|
||||
return possibleTargets(sourceControllerId, source, game).stream()
|
||||
.filter(id -> cards == null || cards.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority method to make a choice from cards and other places, not a player.chooseXXX
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -110,6 +110,12 @@ public class TargetCard extends TargetObject {
|
|||
possibleTargets += countPossibleTargetInCommandZone(game, player, sourceControllerId, source,
|
||||
filter, isNotTarget(), this.minNumberOfTargets - possibleTargets);
|
||||
break;
|
||||
case ALL:
|
||||
possibleTargets += countPossibleTargetInAnyZone(game, player, sourceControllerId, source,
|
||||
filter, isNotTarget(), this.minNumberOfTargets - possibleTargets);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported TargetCard zone: " + zone);
|
||||
}
|
||||
if (possibleTargets >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
|
@ -214,6 +220,25 @@ public class TargetCard extends TargetObject {
|
|||
return possibleTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* count up to N possible target cards in ANY zone
|
||||
*/
|
||||
protected static int countPossibleTargetInAnyZone(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget, int countUpTo) {
|
||||
UUID sourceId = source != null ? source.getSourceId() : null;
|
||||
int possibleTargets = 0;
|
||||
for (Card card : game.getCards()) {
|
||||
if (sourceId == null || isNotTarget || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
|
||||
if (filter.match(card, game)) {
|
||||
possibleTargets++;
|
||||
if (possibleTargets >= countUpTo) {
|
||||
return possibleTargets; // early return for faster computation.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
|
||||
return possibleTargets(sourceControllerId, null, game);
|
||||
|
|
@ -245,6 +270,11 @@ public class TargetCard extends TargetObject {
|
|||
case COMMAND:
|
||||
possibleTargets.addAll(getAllPossibleTargetInCommandZone(game, player, sourceControllerId, source, filter, isNotTarget()));
|
||||
break;
|
||||
case ALL:
|
||||
possibleTargets.addAll(getAllPossibleTargetInAnyZone(game, player, sourceControllerId, source, filter, isNotTarget()));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported TargetCard zone: " + zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -332,6 +362,22 @@ public class TargetCard extends TargetObject {
|
|||
return possibleTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* set of all matching target in ANY zone
|
||||
*/
|
||||
protected static Set<UUID> getAllPossibleTargetInAnyZone(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
UUID sourceId = source != null ? source.getSourceId() : null;
|
||||
for (Card card : game.getCards()) {
|
||||
if (sourceId == null || isNotTarget || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
|
||||
if (filter.match(card, sourceControllerId, source, game)) {
|
||||
possibleTargets.add(card.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
// TODO: check all class targets, if it override canTarget then make sure it override ALL 3 METHODS with canTarget and possibleTargets (method with cards doesn't need)
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1556,7 +1556,7 @@ public final class CardUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static boolean checkForPlayable(Cards cards, FilterCard filter, Ability source, Player player, Game game, SpellCastTracker spellCastTracker, boolean playLand) {
|
||||
private static boolean cardsHasCastableParts(Cards cards, FilterCard filter, Ability source, Player player, Game game, SpellCastTracker spellCastTracker, boolean playLand) {
|
||||
return cards
|
||||
.getCards(game)
|
||||
.stream()
|
||||
|
|
@ -1580,19 +1580,40 @@ public final class CardUtil {
|
|||
CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter);
|
||||
return;
|
||||
}
|
||||
int spellsCast = 0;
|
||||
int castCount = 0;
|
||||
int maxCastCount = Integer.min(cards.size(), maxSpells);
|
||||
cards.removeZone(Zone.STACK, game);
|
||||
while (player.canRespond() && spellsCast < maxSpells && !cards.isEmpty()) {
|
||||
if (CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker, playLand)) {
|
||||
spellsCast++;
|
||||
cards.removeZone(Zone.STACK, game);
|
||||
} else if (!checkForPlayable(
|
||||
cards, filter, source, player, game, spellCastTracker, playLand
|
||||
) || !player.chooseUse(
|
||||
Outcome.PlayForFree, "Continue casting spells?", source, game
|
||||
)) {
|
||||
if (!cardsHasCastableParts(cards, filter, source, player, game, spellCastTracker, playLand)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (player.canRespond()) {
|
||||
boolean wasCast = CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker, playLand);
|
||||
|
||||
// nothing to cast
|
||||
cards.removeZone(Zone.STACK, game);
|
||||
if (cards.isEmpty() || !cardsHasCastableParts(cards, filter, source, player, game, spellCastTracker, playLand)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (wasCast) {
|
||||
// no more tries to cast
|
||||
castCount++;
|
||||
if (castCount >= maxCastCount) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// player want to cancel
|
||||
if (player.isComputer()) {
|
||||
// AI can't choose good spell, so stop
|
||||
break;
|
||||
} else {
|
||||
// Human can choose wrong spell part, so allow to continue
|
||||
if (!player.chooseUse(Outcome.PlayForFree, "Continue casting spells?", source, game)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue