mirror of
https://github.com/magefree/mage.git
synced 2025-12-23 03:51:58 -08:00
- Improved TargetCardInASingleGraveyard to restrict all targets after the 1st to the same graveyard as the first chosen target
- Added slight documentation to Target and TargetCard - Minor cleanup to Unlicensedhearse
This commit is contained in:
parent
82708e4273
commit
eb63ea1e32
4 changed files with 86 additions and 17 deletions
|
|
@ -39,13 +39,15 @@ enum UnlicensedHearseValue implements DynamicValue {
|
||||||
if (unlicensedHearse == null) {
|
if (unlicensedHearse == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the source card, not the source object of the ability to grab the correct zcc
|
// use the source card, not the source object of the ability to grab the correct zcc
|
||||||
ExileZone cardsExiledWithUnlicensedHearse
|
ExileZone cardsExiledWithUnlicensedHearse = game.getExile().getExileZone(
|
||||||
= game.getExile().getExileZone(
|
CardUtil.getExileZoneId(game, unlicensedHearse.getId(), unlicensedHearse.getZoneChangeCounter(game))
|
||||||
CardUtil.getExileZoneId(game, unlicensedHearse.getId(), unlicensedHearse.getZoneChangeCounter(game)));
|
);
|
||||||
if (cardsExiledWithUnlicensedHearse == null) {
|
if (cardsExiledWithUnlicensedHearse == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cardsExiledWithUnlicensedHearse.size();
|
return cardsExiledWithUnlicensedHearse.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,8 +74,7 @@ public final class UnlicensedHearse extends CardImpl {
|
||||||
this.toughness = new MageInt(0);
|
this.toughness = new MageInt(0);
|
||||||
|
|
||||||
// {T}: Exile up to two target cards from a single graveyard.
|
// {T}: Exile up to two target cards from a single graveyard.
|
||||||
Ability ability
|
Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new TapSourceCost());
|
||||||
= new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new TapSourceCost());
|
|
||||||
ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARD_CARDS));
|
ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARD_CARDS));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
|
@ -81,8 +82,9 @@ public final class UnlicensedHearse extends CardImpl {
|
||||||
this.addAbility(
|
this.addAbility(
|
||||||
new SimpleStaticAbility(
|
new SimpleStaticAbility(
|
||||||
Zone.ALL,
|
Zone.ALL,
|
||||||
new SetPowerToughnessSourceEffect(UnlicensedHearseValue.instance, Duration.EndOfGame))
|
new SetPowerToughnessSourceEffect(UnlicensedHearseValue.instance, Duration.EndOfGame)
|
||||||
.addHint(hint));
|
).addHint(hint)
|
||||||
|
);
|
||||||
|
|
||||||
// Crew 2
|
// Crew 2
|
||||||
this.addAbility(new CrewAbility(2));
|
this.addAbility(new CrewAbility(2));
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,14 @@ public interface Target extends Serializable {
|
||||||
// methods for targets
|
// methods for targets
|
||||||
boolean canChoose(UUID sourceControllerId, Ability source, Game game);
|
boolean canChoose(UUID sourceControllerId, Ability source, Game game);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of all possible targets that match the criteria of the implemented Target class.
|
||||||
|
*
|
||||||
|
* @param sourceControllerId UUID of the ability's controller
|
||||||
|
* @param source Ability which requires the targets
|
||||||
|
* @param game Current game
|
||||||
|
* @return Set of the UUIDs of possible targets
|
||||||
|
*/
|
||||||
Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game);
|
Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game);
|
||||||
|
|
||||||
boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game);
|
boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ public class TargetCard extends TargetObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if there are enough {@link Card} that can be chosen.
|
* Checks if there are enough {@link Card cards} in the appropriate zone that the player can choose from among them
|
||||||
|
* or if they are autochosen since there are fewer than the minimum number.
|
||||||
*
|
*
|
||||||
* @param sourceControllerId - controller of the target event source
|
* @param sourceControllerId - controller of the target event source
|
||||||
* @param source
|
* @param source
|
||||||
|
|
@ -160,6 +161,7 @@ public class TargetCard extends TargetObject {
|
||||||
switch (zone) {
|
switch (zone) {
|
||||||
case HAND:
|
case HAND:
|
||||||
for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) {
|
for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) {
|
||||||
|
// TODO: Why for sourceId == null?
|
||||||
if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
|
if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
|
||||||
possibleTargets.add(card.getId());
|
possibleTargets.add(card.getId());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@ package mage.target.common;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.CommanderCardType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.TargetEvent;
|
||||||
|
import mage.players.Player;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
|
@ -20,24 +24,77 @@ public class TargetCardInASingleGraveyard extends TargetCard {
|
||||||
super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filter.copy().withMessage(filter.getMessage() + " from a single graveyard"));
|
super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filter.copy().withMessage(filter.getMessage() + " from a single graveyard"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetCardInASingleGraveyard(final TargetCardInASingleGraveyard target) {
|
private TargetCardInASingleGraveyard(final TargetCardInASingleGraveyard target) {
|
||||||
super(target);
|
super(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||||
UUID firstTarget = this.getFirstTarget();
|
UUID firstTarget = this.getFirstTarget();
|
||||||
if (firstTarget != null) {
|
if (firstTarget == null) {
|
||||||
Card card = game.getCard(firstTarget);
|
|
||||||
Card targetCard = game.getCard(id);
|
|
||||||
if (card == null || targetCard == null
|
|
||||||
|| !card.isOwnedBy(targetCard.getOwnerId())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Card card = game.getCard(firstTarget);
|
||||||
|
Card targetCard = game.getCard(id);
|
||||||
|
if (card == null || targetCard == null || !card.isOwnedBy(targetCard.getOwnerId())) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.canTarget(id, source, game);
|
return super.canTarget(id, source, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of UUIDs of all possible targets
|
||||||
|
*
|
||||||
|
* @param sourceControllerId UUID of the ability's controller
|
||||||
|
* @param source Ability which requires the targets
|
||||||
|
* @param game Current game
|
||||||
|
* @return Set of the UUIDs of possible targets
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||||
|
Set<UUID> possibleTargets = new HashSet<>();
|
||||||
|
UUID sourceId = source != null ? source.getSourceId() : null;
|
||||||
|
|
||||||
|
UUID controllerOfFirstTarget = null;
|
||||||
|
|
||||||
|
// If any targets have been chosen, get the UUID of the owner in order to limit the targets to that owner's graveyard
|
||||||
|
if (!targets.isEmpty()) {
|
||||||
|
for (UUID cardInGraveyardId : targets.keySet()) {
|
||||||
|
Card targetCard = game.getCard(cardInGraveyardId);
|
||||||
|
if (targetCard == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID ownerOfCardId = targetCard.getOwnerId();
|
||||||
|
controllerOfFirstTarget = ownerOfCardId;
|
||||||
|
break; // Only need the first UUID since they will all be the same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||||
|
// If the playerId of this iteration is not the same as that of any existing target, then continue
|
||||||
|
// All cards must be from the same player's graveyard.
|
||||||
|
if (controllerOfFirstTarget != null && !playerId.equals(controllerOfFirstTarget)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = game.getPlayer(playerId);
|
||||||
|
if (player == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) {
|
||||||
|
// TODO: Why for sourceId == null?
|
||||||
|
if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
|
||||||
|
possibleTargets.add(card.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return possibleTargets;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetCardInASingleGraveyard copy() {
|
public TargetCardInASingleGraveyard copy() {
|
||||||
return new TargetCardInASingleGraveyard(this);
|
return new TargetCardInASingleGraveyard(this);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue