GUI: improved choose creature type dialog - important creature types added to the start of the list and marked as my/opponent (closes #8478)

This commit is contained in:
Oleg Agafonov 2024-07-19 03:17:53 +04:00
parent 7b2e9b390c
commit a974af3c61
41 changed files with 239 additions and 138 deletions

View file

@ -105,12 +105,17 @@ public class PickChoiceDialog extends MageDialog {
} }
} }
// sorting // custom sorting
if (choice.isSortEnabled()) { if (choice.isSortEnabled()) {
this.allItems.sort((o1, o2) -> { this.allItems.sort((o1, o2) -> {
Integer n1 = choice.getSortData().get(o1.getKey()); Integer n1 = choice.getSortData().get(o1.getKey());
Integer n2 = choice.getSortData().get(o2.getKey()); Integer n2 = choice.getSortData().get(o2.getKey());
return Integer.compare(n1, n2); if (n1.equals(n2)) {
// default sorting by value
return o1.value.compareTo(o2.value);
} else {
return Integer.compare(n1, n2);
}
}); });
} }

View file

@ -547,6 +547,7 @@ public class HumanPlayer extends PlayerImpl {
while (canRespond()) { while (canRespond()) {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { if (!isExecutingMacro()) {
replacementEffectChoice.onChooseStart(game, playerId);
game.fireChooseChoiceEvent(playerId, replacementEffectChoice); game.fireChooseChoiceEvent(playerId, replacementEffectChoice);
} }
waitForResponse(game); waitForResponse(game);
@ -571,6 +572,7 @@ public class HumanPlayer extends PlayerImpl {
int index = 0; int index = 0;
for (String key : effectsMap.keySet()) { for (String key : effectsMap.keySet()) {
if (replacementEffectChoice.getChoiceKey().equals(key)) { if (replacementEffectChoice.getChoiceKey().equals(key)) {
replacementEffectChoice.onChooseEnd(game, playerId, replacementEffectChoice.getChoiceKey());
return index; return index;
} }
index++; index++;
@ -624,6 +626,7 @@ public class HumanPlayer extends PlayerImpl {
while (canRespond()) { while (canRespond()) {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { if (!isExecutingMacro()) {
choice.onChooseStart(game, playerId);
game.fireChooseChoiceEvent(playerId, choice); game.fireChooseChoiceEvent(playerId, choice);
} }
waitForResponse(game); waitForResponse(game);
@ -635,9 +638,11 @@ public class HumanPlayer extends PlayerImpl {
} else { } else {
choice.setChoice(val); choice.setChoice(val);
} }
choice.onChooseEnd(game, playerId, val);
return true; return true;
} else if (!choice.isRequired()) { } else if (!choice.isRequired()) {
// cancel // cancel
choice.onChooseEnd(game, playerId, null);
return false; return false;
} }
} }

View file

@ -65,18 +65,18 @@ class AndTheyShallKnowNoFearEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
if (player == null || sourceObject == null) { if (controller == null || sourceObject == null) {
return false; return false;
} }
Choice choice = new ChoiceCreatureType(sourceObject); Choice choice = new ChoiceCreatureType(game, source);
player.choose(outcome, choice, game); controller.choose(outcome, choice, game);
SubType subType = SubType.byDescription(choice.getChoice()); SubType subType = SubType.byDescription(choice.getChoiceKey());
if (subType == null) { if (subType == null) {
return false; return false;
} }
game.informPlayers(player.getLogName() + " chooses " + subType); game.informPlayers(controller.getLogName() + " chooses " + subType);
List<Permanent> permanents = game List<Permanent> permanents = game
.getBattlefield() .getBattlefield()
.getActivePermanents( .getActivePermanents(

View file

@ -50,9 +50,9 @@ enum AphettoDredgingAdjuster implements TargetAdjuster {
@Override @Override
public void adjustTargets(Ability ability, Game game) { public void adjustTargets(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(ability.getSourceId())); Choice typeChoice = new ChoiceCreatureType(game, ability);
if (controller != null && controller.choose(Outcome.PutCreatureInPlay, typeChoice, game)) { if (controller != null && controller.choose(Outcome.PutCreatureInPlay, typeChoice, game)) {
String chosenType = typeChoice.getChoice(); String chosenType = typeChoice.getChoiceKey();
FilterCreatureCard filter = new FilterCreatureCard(chosenType + " cards"); FilterCreatureCard filter = new FilterCreatureCard(chosenType + " cards");
filter.add(SubType.byDescription(chosenType).getPredicate()); filter.add(SubType.byDescription(chosenType).getPredicate());
ability.addTarget(new TargetCardInYourGraveyard(0, 3, filter)); ability.addTarget(new TargetCardInYourGraveyard(0, 3, filter));

View file

@ -74,12 +74,12 @@ class BloodlineShamanEffect extends OneShotEffect {
return false; return false;
} }
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!controller.choose(outcome, typeChoice, game)) { if (!controller.choose(outcome, typeChoice, game)) {
return false; return false;
} }
SubType subType = SubType.byDescription(typeChoice.getChoice()); SubType subType = SubType.byDescription(typeChoice.getChoiceKey());
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
// Reveal the top card of your library. // Reveal the top card of your library.
if (controller.getLibrary().hasCards()) { if (controller.getLibrary().hasCards()) {

View file

@ -139,16 +139,16 @@ class ChooseCreatureTypeEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);
Choice typeChoice = new ChoiceCreatureType(mageObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (controller != null if (controller != null
&& mageObject != null && mageObject != null
&& controller.choose(outcome, typeChoice, game)) { && controller.choose(outcome, typeChoice, game)) {
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(mageObject.getName() + ": " game.informPlayers(mageObject.getName() + ": "
+ controller.getLogName() + " has chosen " + typeChoice.getChoice()); + controller.getLogName() + " has chosen " + typeChoice.getChoiceKey());
} }
game.getState().setValue(mageObject.getId() game.getState().setValue(mageObject.getId()
+ "_type", SubType.byDescription(typeChoice.getChoice())); + "_type", SubType.byDescription(typeChoice.getChoiceKey()));
return true; return true;
} }
return false; return false;

View file

@ -122,20 +122,19 @@ class CallousOppressorChooseCreatureTypeEffect extends OneShotEffect {
} }
Player opponent = game.getPlayer(target.getFirstTarget()); Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent != null && mageObject != null) { if (opponent != null && mageObject != null) {
Choice typeChoice = new ChoiceCreatureType(mageObject); Choice typeChoice = new ChoiceCreatureType(game, source);
typeChoice.setMessage("Choose creature type");
if (!opponent.choose(outcome, typeChoice, game)) { if (!opponent.choose(outcome, typeChoice, game)) {
return false; return false;
} }
if (typeChoice.getChoice() == null) { if (typeChoice.getChoiceKey() == null) {
return false; return false;
} }
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(mageObject.getName() + ": " + opponent.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(mageObject.getName() + ": " + opponent.getLogName() + " has chosen " + typeChoice.getChoiceKey());
} }
game.getState().setValue(mageObject.getId() + "_type", SubType.byDescription(typeChoice.getChoice())); game.getState().setValue(mageObject.getId() + "_type", SubType.byDescription(typeChoice.getChoiceKey()));
if (mageObject instanceof Permanent) { if (mageObject instanceof Permanent) {
((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoiceKey()), game);
} }
return true; return true;
} }

View file

@ -60,9 +60,9 @@ class CoordinatedBarrageEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
Choice choice = new ChoiceCreatureType(game.getObject(source)); Choice choice = new ChoiceCreatureType(game, source);
if (controller.choose(Outcome.Damage, choice, game)) { if (controller.choose(Outcome.Damage, choice, game)) {
String chosenType = choice.getChoice(); String chosenType = choice.getChoiceKey();
FilterControlledPermanent filter = new FilterControlledPermanent(); FilterControlledPermanent filter = new FilterControlledPermanent();
filter.add(SubType.byDescription(chosenType).getPredicate()); filter.add(SubType.byDescription(chosenType).getPredicate());
int damageDealt = game.getBattlefield().count(filter, source.getControllerId(), source, game); int damageDealt = game.getBattlefield().count(filter, source.getControllerId(), source, game);

View file

@ -63,10 +63,10 @@ class DefensiveManeuversEffect extends OneShotEffect {
if (player == null || sourceObject == null) { if (player == null || sourceObject == null) {
return false; return false;
} }
Choice choice = new ChoiceCreatureType(sourceObject); Choice choice = new ChoiceCreatureType(game, source);
SubType subType = null; SubType subType = null;
if (player.choose(outcome, choice, game)) { if (player.choose(outcome, choice, game)) {
subType = SubType.byDescription(choice.getChoice()); subType = SubType.byDescription(choice.getChoiceKey());
} }
if (subType == null) { if (subType == null) {
return false; return false;

View file

@ -59,10 +59,10 @@ class DistantMelodyEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (controller != null && controller.choose(Outcome.BoostCreature, typeChoice, game)) { if (controller != null && controller.choose(Outcome.BoostCreature, typeChoice, game)) {
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
return new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filter)).apply(game, source); return new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filter)).apply(game, source);
} }
return false; return false;

View file

@ -69,14 +69,14 @@ class ElvishSoultillerEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);
if (controller != null && mageObject != null) { if (controller != null && mageObject != null) {
Choice typeChoice = new ChoiceCreatureType(mageObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (controller.choose(outcome, typeChoice, game)) { if (controller.choose(outcome, typeChoice, game)) {
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoiceKey());
} }
Cards cardsToLibrary = new CardsImpl(); Cards cardsToLibrary = new CardsImpl();
FilterCreatureCard filter = new FilterCreatureCard(); FilterCreatureCard filter = new FilterCreatureCard();
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
cardsToLibrary.addAllCards(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game)); cardsToLibrary.addAllCards(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game));
controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false);
controller.shuffleLibrary(source, game); controller.shuffleLibrary(source, game);

View file

@ -55,12 +55,11 @@ class ExtinctionEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);
if (player != null && sourceObject != null) { if (player != null && sourceObject != null) {
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player.choose(outcome, typeChoice, game)) { if (player.choose(outcome, typeChoice, game)) {
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent();
filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) {
creature.destroy(source, game, true); creature.destroy(source, game, true);
} }

View file

@ -68,12 +68,12 @@ class ForTheAncestorsEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
ChoiceCreatureType choice = new ChoiceCreatureType(); ChoiceCreatureType choice = new ChoiceCreatureType(game, source);
player.choose(outcome, choice, game); player.choose(outcome, choice, game);
SubType subType = SubType.byDescription(choice.getChoice()); SubType subType = SubType.byDescription(choice.getChoiceKey());
FilterCard filter; FilterCard filter;
if (subType != null) { if (subType != null) {
filter = new FilterCard(choice.getChoice() + " cards"); filter = new FilterCard(choice.getChoiceKey() + " cards");
filter.add(subType.getPredicate()); filter.add(subType.getPredicate());
} else { } else {
filter = new FilterCard(); filter = new FilterCard();

View file

@ -70,7 +70,7 @@ class GraveSifterEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
typeChoice.setMessage("Choose creature type to return cards from your graveyard"); typeChoice.setMessage("Choose creature type to return cards from your graveyard");
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Set<Card> toHand = new HashSet<>(); Set<Card> toHand = new HashSet<>();
@ -80,9 +80,9 @@ class GraveSifterEffect extends OneShotEffect {
if (player != null) { if (player != null) {
typeChoice.clearChoice(); typeChoice.clearChoice();
if (player.choose(outcome, typeChoice, game)) { if (player.choose(outcome, typeChoice, game)) {
game.informPlayers(player.getLogName() + " has chosen: " + typeChoice.getChoice()); game.informPlayers(player.getLogName() + " has chosen: " + typeChoice.getChoiceKey());
FilterCard filter = new FilterCreatureCard("creature cards with creature type " + typeChoice.getChoice() + " from your graveyard"); FilterCard filter = new FilterCreatureCard("creature cards with creature type " + typeChoice.getChoiceKey() + " from your graveyard");
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
Target target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter); Target target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter);
player.chooseTarget(outcome, target, source, game); player.chooseTarget(outcome, target, source, game);
toHand.addAll(new CardsImpl(target.getTargets()).getCards(game)); toHand.addAll(new CardsImpl(target.getTargets()).getCards(game));

View file

@ -69,11 +69,11 @@ class HarshMercyEffect extends OneShotEffect {
PlayerIteration: PlayerIteration:
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player != null && !player.choose(Outcome.DestroyPermanent, typeChoice, game)) { if (player != null && !player.choose(Outcome.DestroyPermanent, typeChoice, game)) {
continue PlayerIteration; continue PlayerIteration;
} }
String chosenType = typeChoice.getChoice(); String chosenType = typeChoice.getChoiceKey();
if (chosenType != null) { if (chosenType != null) {
game.informPlayers(sourceObject.getIdName() + ": " + player.getLogName() + " has chosen " + chosenType); game.informPlayers(sourceObject.getIdName() + ": " + player.getLogName() + " has chosen " + chosenType);
chosenTypes.add(chosenType); chosenTypes.add(chosenType);

View file

@ -124,11 +124,11 @@ class KaronaFalseGodEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);
if (sourceObject != null && controller != null) { if (sourceObject != null && controller != null) {
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!controller.choose(Outcome.BoostCreature, typeChoice, game)) { if (!controller.choose(Outcome.BoostCreature, typeChoice, game)) {
return false; return false;
} }
String typeChosen = typeChoice.getChoice(); String typeChosen = typeChoice.getChoiceKey();
if (!typeChosen.isEmpty()) { if (!typeChosen.isEmpty()) {
game.informPlayers(controller.getLogName() + " has chosen " + typeChosen); game.informPlayers(controller.getLogName() + " has chosen " + typeChosen);
FilterCreaturePermanent filter = new FilterCreaturePermanent(); FilterCreaturePermanent filter = new FilterCreaturePermanent();

View file

@ -59,11 +59,11 @@ class KindredDominanceEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (controller != null && controller.choose(outcome, typeChoice, game)) { if (controller != null && controller.choose(outcome, typeChoice, game)) {
game.informPlayers(controller.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(controller.getLogName() + " has chosen " + typeChoice.getChoiceKey());
FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures not of the chosen type"); FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures not of the chosen type");
filter.add(Predicates.not(SubType.byDescription(typeChoice.getChoice()).getPredicate())); filter.add(Predicates.not(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate()));
return new DestroyAllEffect(filter).apply(game, source); return new DestroyAllEffect(filter).apply(game, source);
} }
return false; return false;

View file

@ -109,7 +109,7 @@ class LongListOfTheEntsEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
ChoiceCreatureType choice = new ChoiceCreatureType(source.getSourceObject(game)); ChoiceCreatureType choice = new ChoiceCreatureType(game, source);
Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source, 0)); Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source, 0));
int offset; int offset;
Set<SubType> newEntList; Set<SubType> newEntList;
@ -124,9 +124,9 @@ class LongListOfTheEntsEffect extends OneShotEffect {
.stream() .stream()
.map(SubType::toString) .map(SubType::toString)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
choice.getChoices().removeIf(chosenTypes::contains); choice.getKeyChoices().keySet().removeIf(chosenTypes::contains);
player.choose(Outcome.BoostCreature, choice, game); player.choose(Outcome.BoostCreature, choice, game);
SubType subType = SubType.byDescription(choice.getChoice()); SubType subType = SubType.byDescription(choice.getChoiceKey());
if (subType == null) { if (subType == null) {
return false; return false;
} }

View file

@ -59,10 +59,10 @@ class LuminescentRainEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player != null && player.choose(Outcome.BoostCreature, typeChoice, game)) { if (player != null && player.choose(Outcome.BoostCreature, typeChoice, game)) {
FilterControlledPermanent filter = new FilterControlledPermanent(); FilterControlledPermanent filter = new FilterControlledPermanent();
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
return new GainLifeEffect(new PermanentsOnBattlefieldCount(filter, 2)).apply(game, source); return new GainLifeEffect(new PermanentsOnBattlefieldCount(filter, 2)).apply(game, source);
} }
return false; return false;

View file

@ -75,12 +75,12 @@ class MistformSliverEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (player != null && permanent != null) { if (player != null && permanent != null) {
Choice typeChoice = new ChoiceCreatureType(permanent); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!player.choose(Outcome.Detriment, typeChoice, game)) { if (!player.choose(Outcome.Detriment, typeChoice, game)) {
return false; return false;
} }
game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoiceKey());
ContinuousEffect effect = new AddCardSubTypeTargetEffect(SubType.byDescription(typeChoice.getChoice()), Duration.EndOfTurn); ContinuousEffect effect = new AddCardSubTypeTargetEffect(SubType.byDescription(typeChoice.getChoiceKey()), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(permanent, game)); effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source); game.addEffect(effect, source);
} }

View file

@ -77,16 +77,14 @@ class BecomesChosenCreatureTypeControlledEffect extends OneShotEffect {
Card card = game.getCard(source.getSourceId()); Card card = game.getCard(source.getSourceId());
String chosenType = ""; String chosenType = "";
if (player != null && card != null) { if (player != null && card != null) {
Choice typeChoice = new ChoiceCreatureType(); Choice typeChoice = new ChoiceCreatureType(game, source);
String msg = "Choose a creature type";
typeChoice.setMessage(msg);
while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { while (!player.choose(Outcome.BoostCreature, typeChoice, game)) {
if (!player.canRespond()) { if (!player.canRespond()) {
return false; return false;
} }
} }
game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoiceKey());
chosenType = typeChoice.getChoice(); chosenType = typeChoice.getChoiceKey();
if (chosenType != null && !chosenType.isEmpty()) { if (chosenType != null && !chosenType.isEmpty()) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game)) {
ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.byDescription(chosenType)); ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.byDescription(chosenType));

View file

@ -117,13 +117,13 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl {
return; return;
} }
if (fromSubType == null) { if (fromSubType == null) {
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
typeChoice.setMessage("Choose creature type to change to Vampire"); typeChoice.setMessage("Choose creature type to change to Vampire");
if (!controller.choose(outcome, typeChoice, game)) { if (!controller.choose(outcome, typeChoice, game)) {
discard(); discard();
return; return;
} }
fromSubType = SubType.byDescription(typeChoice.getChoice()); fromSubType = SubType.byDescription(typeChoice.getChoiceKey());
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " has chosen the creature type: " + fromSubType.toString()); game.informPlayers(controller.getLogName() + " has chosen the creature type: " + fromSubType.toString());
} }

View file

@ -67,11 +67,11 @@ class OutbreakEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player != null && player.choose(outcome, typeChoice, game)) { if (player != null && player.choose(outcome, typeChoice, game)) {
game.informPlayers(player.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(player.getLogName() + " has chosen " + typeChoice.getChoiceKey());
FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures of the chosen type"); FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures of the chosen type");
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
ContinuousEffect effect = new BoostAllEffect(-1, -1, Duration.WhileOnBattlefield, filter, false); ContinuousEffect effect = new BoostAllEffect(-1, -1, Duration.WhileOnBattlefield, filter, false);
game.addEffect(effect, source); game.addEffect(effect, source);
return true; return true;

View file

@ -64,10 +64,10 @@ class PacksDisdainEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player != null if (player != null
&& player.choose(Outcome.UnboostCreature, typeChoice, game)) { && player.choose(Outcome.UnboostCreature, typeChoice, game)) {
FilterControlledPermanent filter = new FilterControlledPermanent(SubType.byDescription(typeChoice.getChoice())); FilterControlledPermanent filter = new FilterControlledPermanent(SubType.byDescription(typeChoice.getChoiceKey()));
DynamicValue negativePermanentsCount = new PermanentsOnBattlefieldCount(filter, -1); DynamicValue negativePermanentsCount = new PermanentsOnBattlefieldCount(filter, -1);
ContinuousEffect effect = new BoostTargetEffect(negativePermanentsCount, negativePermanentsCount, Duration.EndOfTurn); ContinuousEffect effect = new BoostTargetEffect(negativePermanentsCount, negativePermanentsCount, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));

View file

@ -65,11 +65,11 @@ class PatriarchsBiddingEffect extends OneShotEffect {
Set<String> chosenTypes = new HashSet<>(); Set<String> chosenTypes = new HashSet<>();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!player.choose(Outcome.PutCreatureInPlay, typeChoice, game)) { if (!player.choose(Outcome.PutCreatureInPlay, typeChoice, game)) {
continue; continue;
} }
String chosenType = typeChoice.getChoice(); String chosenType = typeChoice.getChoiceKey();
game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + chosenType); game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + chosenType);
chosenTypes.add(chosenType); chosenTypes.add(chosenType);
} }

View file

@ -65,9 +65,9 @@ class PeerPressureEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Choice choice = new ChoiceCreatureType(game.getObject(source)); Choice choice = new ChoiceCreatureType(game, source);
if (controller != null && controller.choose(Outcome.GainControl, choice, game)) { if (controller != null && controller.choose(Outcome.GainControl, choice, game)) {
String chosenType = choice.getChoice(); String chosenType = choice.getChoiceKey();
game.informPlayers(controller.getLogName() + " has chosen " + chosenType); game.informPlayers(controller.getLogName() + " has chosen " + chosenType);
UUID playerWithMost = null; UUID playerWithMost = null;
int maxControlled = 0; int maxControlled = 0;

View file

@ -66,11 +66,11 @@ class RiptideChronologistEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);
if (player != null && sourceObject != null) { if (player != null && sourceObject != null) {
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player.choose(outcome, typeChoice, game)) { if (player.choose(outcome, typeChoice, game)) {
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent();
filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) {
creature.untap(game); creature.untap(game);
} }

View file

@ -69,13 +69,13 @@ class RiptideShapeshifterEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) { if (controller != null && sourceObject != null) {
Choice choice = new ChoiceCreatureType(sourceObject); Choice choice = new ChoiceCreatureType(game, source);
if (!controller.choose(Outcome.BoostCreature, choice, game)) { if (!controller.choose(Outcome.BoostCreature, choice, game)) {
return false; return false;
} }
Cards revealedCards = new CardsImpl(); Cards revealedCards = new CardsImpl();
for (Card card : controller.getLibrary().getCards(game)) { for (Card card : controller.getLibrary().getCards(game)) {
if (card.isCreature(game) && card.hasSubtype(SubType.byDescription(choice.getChoice()), game)) { if (card.isCreature(game) && card.hasSubtype(SubType.byDescription(choice.getChoiceKey()), game)) {
controller.moveCards(card, Zone.BATTLEFIELD, source, game); controller.moveCards(card, Zone.BATTLEFIELD, source, game);
break; break;
} }

View file

@ -62,12 +62,12 @@ class RoarOfTheCrowdEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player != null) { if (player != null) {
Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!player.choose(Outcome.LoseLife, typeChoice, game)) { if (!player.choose(Outcome.LoseLife, typeChoice, game)) {
return false; return false;
} }
FilterControlledPermanent filter = new FilterControlledPermanent(); FilterControlledPermanent filter = new FilterControlledPermanent();
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
return new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)).apply(game, source); return new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)).apply(game, source);
} }
return false; return false;

View file

@ -55,11 +55,11 @@ enum SelectiveSnareAdjuster implements TargetAdjuster {
if (player == null) { if (player == null) {
return; return;
} }
Choice choice = new ChoiceCreatureType(); Choice choice = new ChoiceCreatureType(game, ability);
if (!player.choose(Outcome.Benefit, choice, game)) { if (!player.choose(Outcome.Benefit, choice, game)) {
return; return;
} }
SubType subType = SubType.byDescription(choice.getChoice()); SubType subType = SubType.byDescription(choice.getChoiceKey());
int xValue = ability.getManaCostsToPay().getX(); int xValue = ability.getManaCostsToPay().getX();
FilterPermanent filter = new FilterCreaturePermanent(subType.toString() + " creatures"); FilterPermanent filter = new FilterCreaturePermanent(subType.toString() + " creatures");
filter.add(subType.getPredicate()); filter.add(subType.getPredicate());

View file

@ -59,14 +59,14 @@ class StandardizeEffect extends OneShotEffect {
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);
String chosenType = ""; String chosenType = "";
if (player != null && sourceObject != null) { if (player != null && sourceObject != null) {
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
typeChoice.setMessage("Choose a creature type other than Wall"); typeChoice.setMessage("Choose a creature type other than Wall");
typeChoice.getChoices().remove("Wall"); typeChoice.getKeyChoices().keySet().removeIf(c -> c.equals("Wall"));
if (!player.choose(Outcome.BoostCreature, typeChoice, game)) { if (!player.choose(Outcome.BoostCreature, typeChoice, game)) {
return false; return false;
} }
game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoiceKey());
chosenType = typeChoice.getChoice(); chosenType = typeChoice.getChoiceKey();
if (chosenType != null && !chosenType.isEmpty()) { if (chosenType != null && !chosenType.isEmpty()) {
// ADD TYPE TO TARGET // ADD TYPE TO TARGET
game.addEffect(new BecomesSubtypeAllEffect( game.addEffect(new BecomesSubtypeAllEffect(

View file

@ -64,14 +64,14 @@ class TribalUnityEffect extends OneShotEffect {
return false; return false;
} }
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player != null && player.choose(outcome, typeChoice, game)) { if (player != null && player.choose(outcome, typeChoice, game)) {
int boost = amount.calculate(game, source, this); int boost = amount.calculate(game, source, this);
if (typeChoice.getChoice() != null) { if (typeChoice.getChoiceKey() != null) {
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
} }
FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent();
filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
game.addEffect(new BoostAllEffect( game.addEffect(new BoostAllEffect(
boost, boost, Duration.EndOfTurn, filterCreaturePermanent, false), source); boost, boost, Duration.EndOfTurn, filterCreaturePermanent, false), source);
return true; return true;

View file

@ -67,17 +67,17 @@ class TsabosDecreeEffect extends OneShotEffect {
if (sourceObject == null) { if (sourceObject == null) {
return false; return false;
} }
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (!player.choose(outcome, typeChoice, game)) { if (!player.choose(outcome, typeChoice, game)) {
return false; return false;
} }
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game); targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game);
FilterCard filterCard = new FilterCard(); FilterCard filterCard = new FilterCard();
filterCard.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filterCard.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
targetPlayer.discard(new CardsImpl(targetPlayer.getHand().getCards(filterCard, game)), false, source, game); targetPlayer.discard(new CardsImpl(targetPlayer.getHand().getCards(filterCard, game)), false, source, game);
FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent();
filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filterCreaturePermanent.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) {
if (creature.isControlledBy(targetPlayer.getId())) { if (creature.isControlledBy(targetPlayer.getId())) {
creature.destroy(source, game, true); creature.destroy(source, game, true);

View file

@ -65,11 +65,11 @@ class WalkingDesecrationEffect extends OneShotEffect {
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);
if (player != null) { if (player != null) {
if (sourceObject != null) { if (sourceObject != null) {
Choice typeChoice = new ChoiceCreatureType(sourceObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (player.choose(outcome, typeChoice, game)) { if (player.choose(outcome, typeChoice, game)) {
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoiceKey());
FilterCreaturePermanent filter = new FilterCreaturePermanent(); FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); filter.add(SubType.byDescription(typeChoice.getChoiceKey()).getPredicate());
RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn); RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn);
game.addEffect(effect, source); game.addEffect(effect, source);
return true; return true;

View file

@ -60,12 +60,12 @@ class WitchsVengeanceEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
ChoiceCreatureType choice = new ChoiceCreatureType(); ChoiceCreatureType choice = new ChoiceCreatureType(game, source);
if (!player.choose(outcome, choice, game)) { if (!player.choose(outcome, choice, game)) {
return false; return false;
} }
FilterCreaturePermanent filter = new FilterCreaturePermanent(); FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(SubType.byDescription(choice.getChoice()).getPredicate()); filter.add(SubType.byDescription(choice.getChoiceKey()).getPredicate());
game.addEffect(new BoostAllEffect( game.addEffect(new BoostAllEffect(
-3, -3, Duration.EndOfTurn, filter, false -3, -3, Duration.EndOfTurn, filter, false
), source); ), source);

View file

@ -36,14 +36,14 @@ public class ChooseCreatureTypeEffect extends OneShotEffect {
mageObject = game.getObject(source); mageObject = game.getObject(source);
} }
if (controller != null && mageObject != null) { if (controller != null && mageObject != null) {
Choice typeChoice = new ChoiceCreatureType(mageObject); Choice typeChoice = new ChoiceCreatureType(game, source);
if (controller.choose(outcome, typeChoice, game)) { if (controller.choose(outcome, typeChoice, game)) {
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoiceKey());
} }
game.getState().setValue(source.getSourceId() + "_type", SubType.byDescription(typeChoice.getChoice())); game.getState().setValue(source.getSourceId() + "_type", SubType.byDescription(typeChoice.getChoiceKey()));
if (mageObject instanceof Permanent) { if (mageObject instanceof Permanent) {
((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoiceKey()), game);
} }
return true; return true;
} }

View file

@ -50,22 +50,22 @@ public class BecomesChosenCreatureTypeTargetEffect extends OneShotEffect {
Card card = game.getCard(source.getSourceId()); Card card = game.getCard(source.getSourceId());
String chosenType = ""; String chosenType = "";
if (player != null && card != null) { if (player != null && card != null) {
Choice typeChoice = new ChoiceCreatureType(); Choice typeChoice = new ChoiceCreatureType(game, source);
String msg = "Choose a creature type"; String msg = "Choose a creature type";
if (nonWall) { if (nonWall) {
msg += " other than Wall"; msg += " other than Wall";
} }
typeChoice.setMessage(msg); typeChoice.setMessage(msg);
if (nonWall) { if (nonWall) {
typeChoice.getChoices().remove(SubType.WALL.getDescription()); typeChoice.getKeyChoices().remove(SubType.WALL.getDescription());
} }
while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { while (!player.choose(Outcome.BoostCreature, typeChoice, game)) {
if (!player.canRespond()) { if (!player.canRespond()) {
return false; return false;
} }
} }
game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoiceKey());
chosenType = typeChoice.getChoice(); chosenType = typeChoice.getChoiceKey();
if (chosenType != null && !chosenType.isEmpty()) { if (chosenType != null && !chosenType.isEmpty()) {
// ADD TYPE TO TARGET // ADD TYPE TO TARGET
ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(duration, SubType.byDescription(chosenType)); ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(duration, SubType.byDescription(chosenType));

View file

@ -1,11 +1,14 @@
package mage.choices; package mage.choices;
import mage.game.Game;
import mage.players.Player;
import mage.util.Copyable; import mage.util.Copyable;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
/** /**
* @author BetaSteward_at_googlemail.com, JayDi85 * @author BetaSteward_at_googlemail.com, JayDi85
@ -107,4 +110,11 @@ public interface Choice extends Serializable, Copyable<Choice> {
void setRandomChoice(); void setRandomChoice();
boolean setChoiceByAnswers(List<String> answers, boolean removeSelectAnswerFromList); boolean setChoiceByAnswers(List<String> answers, boolean removeSelectAnswerFromList);
/**
* Run additional code before player start to choose (example: add info and hints for choosing player)
*/
void onChooseStart(Game game, UUID choosingPlayerId);
void onChooseEnd(Game game, UUID choosingPlayerId, String choiceResult);
} }

View file

@ -1,35 +1,39 @@
package mage.choices; package mage.choices;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game;
import mage.players.Player;
import java.util.LinkedHashSet; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* Game's choose dialog to ask about creature type. Return getChoice
*/
public class ChoiceCreatureType extends ChoiceImpl { public class ChoiceCreatureType extends ChoiceImpl {
private static final String DEFAULT_MESSAGE = "Choose a creature type"; private static final String DEFAULT_MESSAGE = "Choose a creature type";
public ChoiceCreatureType() { public ChoiceCreatureType(Game game, Ability source) {
this(true, DEFAULT_MESSAGE, null); this(game, source, true, DEFAULT_MESSAGE);
} }
public ChoiceCreatureType(MageObject source) { public ChoiceCreatureType(Game game, Ability source, boolean required, String chooseMessage) {
this(true, DEFAULT_MESSAGE, source);
}
public ChoiceCreatureType(String chooseMessage, MageObject source) {
this(true, chooseMessage, source);
}
public ChoiceCreatureType(boolean required, String chooseMessage, MageObject source) {
super(required); super(required);
this.setChoices(SubType.getCreatureTypes().stream().map(SubType::toString).collect(Collectors.toCollection(LinkedHashSet::new)));
this.setMessage(chooseMessage); this.setMessage(chooseMessage);
if (source != null) { MageObject sourceObject = source == null ? null : game.getObject(source);
this.setSubMessage(source.getIdName()); if (sourceObject != null) {
this.setSubMessage(sourceObject.getLogName());
} }
this.setSearchEnabled(true); this.setSearchEnabled(true);
// collect basic info
// additional info will be added onChooseStart
SubType.getCreatureTypes().stream().map(SubType::toString).forEach(value -> {
this.withItem(value, value, null, null, null);
});
} }
protected ChoiceCreatureType(final ChoiceCreatureType choice) { protected ChoiceCreatureType(final ChoiceCreatureType choice) {
@ -40,4 +44,71 @@ public class ChoiceCreatureType extends ChoiceImpl {
public ChoiceCreatureType copy() { public ChoiceCreatureType copy() {
return new ChoiceCreatureType(this); return new ChoiceCreatureType(this);
} }
@Override
public void onChooseStart(Game game, UUID choosingPlayerId) {
// add additional info about important creature types (collect it from all public zone and own hand)
Set<String> myTypes = new HashSet<>();
Set<String> opponentTypes = new HashSet<>();
game.getState().getPlayersInRange(choosingPlayerId, game).forEach(playerId -> {
Player player = game.getPlayer(playerId);
if (player == null) {
return;
}
Set<String> list = playerId.equals(choosingPlayerId) ? myTypes : opponentTypes;
// own hand
if (playerId.equals(choosingPlayerId)) {
player.getHand().getCards(game).forEach(card -> {
list.addAll(card.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
});
}
// battlefield
game.getBattlefield().getAllActivePermanents(playerId).forEach(permanent -> {
list.addAll(permanent.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
});
// graveyard
player.getGraveyard().getCards(game).forEach(card -> {
list.addAll(card.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
});
// exile
game.getExile().getAllCards(game, playerId).forEach(card -> {
list.addAll(card.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
});
});
// stack
game.getStack().forEach(stackObject -> {
if (stackObject.isControlledBy(choosingPlayerId)) {
myTypes.addAll(stackObject.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
} else {
opponentTypes.addAll(stackObject.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
}
});
// sort order: me -> opponent -> not used
this.keyChoices.forEach((key, value) -> {
String additionalInfo = "";
Integer orderPriority = 0;
if (myTypes.contains(key)) {
additionalInfo += "me";
orderPriority -= 100;
}
if (opponentTypes.contains(key)) {
if (!additionalInfo.isEmpty()) {
additionalInfo += ", ";
}
additionalInfo += "opponent";
orderPriority -= 10;
}
this.keyChoices.put(key, key + (additionalInfo.isEmpty() ? "" : " (" + additionalInfo + ")"));
this.sortData.put(key, orderPriority);
});
}
} }

View file

@ -1,5 +1,6 @@
package mage.choices; package mage.choices;
import mage.game.Game;
import mage.util.CardUtil; import mage.util.CardUtil;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -400,4 +401,14 @@ public class ChoiceImpl implements Choice {
logger.error("Empty choice dialog in " + this.getClass().getCanonicalName(), new Throwable()); logger.error("Empty choice dialog in " + this.getClass().getCanonicalName(), new Throwable());
} }
} }
@Override
public void onChooseStart(Game game, UUID choosingPlayerId) {
// nothing to do
}
@Override
public void onChooseEnd(Game game, UUID choosingPlayerId, String choiceResult) {
// nothing to do
}
} }

View file

@ -15,7 +15,6 @@ import mage.players.Player;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
@ -101,39 +100,43 @@ class VolosJournalTokenEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player == null) { if (player == null) {
return true; return false;
} }
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return false;
}
Set<String> types = VolosJournalToken.getNotedTypes(game, permanent); Set<String> notedTypes = VolosJournalToken.getNotedTypes(game, permanent);
ChoiceCreatureType choice = new ChoiceCreatureType(); ChoiceCreatureType choice = new ChoiceCreatureType(game, source);
// By default ChoiceCreatureType pre-populates all creatures into choices // By default ChoiceCreatureType pre-populates all creatures into choices
// Limit the available choices to those on the creature being cast // Limit the available choices to those on the creature being cast
if (!spell.isAllCreatureTypes(game)) { if (!spell.isAllCreatureTypes(game)) {
choice.setChoices( choice.getKeyChoices().clear();
spell.getSubtype(game) spell.getSubtype(game)
.stream() .stream()
.filter(subType -> subType.getSubTypeSet() == SubTypeSet.CreatureType) .filter(subType -> subType.getSubTypeSet() == SubTypeSet.CreatureType)
.map(SubType::getDescription) .map(SubType::getDescription)
.collect(Collectors.toSet()) .forEach(subType -> {
); choice.withItem(subType, subType, null, null, null);
});
} }
// Remove from the possible choices the subtypes which have already been chosen. // Remove from the possible choices the subtypes which have already been chosen.
choice.getChoices().removeIf(types::contains); choice.getKeyChoices().keySet().removeIf(notedTypes::contains);
switch (choice.getChoices().size()) { switch (choice.getKeyChoices().size()) {
case 0: case 0:
return false; return false;
case 1: case 1:
types.add(choice.getChoices().stream().findFirst().get()); notedTypes.add(choice.getKeyChoices().keySet().stream().findFirst().get());
return true; return true;
} }
player.choose(outcome, choice, game); player.choose(outcome, choice, game);
types.add(choice.getChoice()); notedTypes.add(choice.getChoiceKey());
return true; return true;
} }
} }