GUI: added card hints in choose replacement effect dialog

This commit is contained in:
Oleg Agafonov 2024-07-19 00:05:57 +04:00
parent 67ff2da060
commit 7b2e9b390c
7 changed files with 50 additions and 26 deletions

View file

@ -2192,7 +2192,7 @@ public class ComputerPlayer extends PlayerImpl {
} }
@Override @Override
public int chooseReplacementEffect(Map<String, String> rEffects, Game game) { public int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game) {
log.debug("chooseReplacementEffect"); log.debug("chooseReplacementEffect");
//TODO: implement this //TODO: implement this
return 0; return 0;

View file

@ -1,5 +1,6 @@
package mage.player.ai; package mage.player.ai;
import mage.MageObject;
import mage.abilities.*; import mage.abilities.*;
import mage.abilities.common.PassAbility; import mage.abilities.common.PassAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
@ -341,11 +342,11 @@ public final class SimulatedPlayerMCTS extends MCTSPlayer {
} }
@Override @Override
public int chooseReplacementEffect(Map<String, String> rEffects, Game game) { public int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game) {
if (this.isHuman()) { if (this.isHuman()) {
return RandomUtil.nextInt(rEffects.size()); return RandomUtil.nextInt(effectsMap.size());
} }
return super.chooseReplacementEffect(rEffects, game); return super.chooseReplacementEffect(effectsMap, objectsMap, game);
} }
@Override @Override

View file

@ -16,10 +16,9 @@ import mage.abilities.mana.ManaAbility;
import mage.cards.*; import mage.cards.*;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceHintType;
import mage.choices.ChoiceImpl; import mage.choices.ChoiceImpl;
import mage.constants.*; import mage.constants.*;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterBlockingCreature;
@ -57,6 +56,9 @@ import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
/** /**
* Human: server side logic to exchange game data between server app and another player's app * Human: server side logic to exchange game data between server app and another player's app
* *
@ -485,12 +487,12 @@ public class HumanPlayer extends PlayerImpl {
} }
@Override @Override
public int chooseReplacementEffect(Map<String, String> rEffects, Game game) { public int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game) {
if (gameInCheckPlayableState(game, true)) { // ignore warning logs until double call for TAPPED_FOR_MANA will be fix if (gameInCheckPlayableState(game, true)) { // ignore warning logs until double call for TAPPED_FOR_MANA will be fix
return 0; return 0;
} }
if (rEffects.size() <= 1) { if (effectsMap.size() <= 1) {
return 0; return 0;
} }
@ -505,8 +507,8 @@ public class HumanPlayer extends PlayerImpl {
for (String autoText : autoSelectReplacementEffects) { for (String autoText : autoSelectReplacementEffects) {
int count = 0; int count = 0;
// find effect with same saved text // find effect with same saved text
for (String effectKey : rEffects.keySet()) { for (String effectKey : effectsMap.keySet()) {
String currentText = prepareReplacementText(rEffects.get(effectKey), useSameSettings); String currentText = prepareReplacementText(effectsMap.get(effectKey), useSameSettings);
if (currentText.equals(autoText)) { if (currentText.equals(autoText)) {
return count; return count;
} }
@ -517,7 +519,17 @@ public class HumanPlayer extends PlayerImpl {
replacementEffectChoice.clearChoice(); replacementEffectChoice.clearChoice();
replacementEffectChoice.getChoices().clear(); replacementEffectChoice.getChoices().clear();
replacementEffectChoice.setKeyChoices(rEffects); replacementEffectChoice.getKeyChoices().clear();
effectsMap.forEach((key, value) -> {
MageObject object = objectsMap.getOrDefault(key, null);
replacementEffectChoice.withItem(
key,
value,
null,
object != null ? ChoiceHintType.GAME_OBJECT : null,
object != null ? object.getId().toString() : null
);
});
// if same choices then select first // if same choices then select first
int differentChoices = 0; int differentChoices = 0;
@ -557,7 +569,7 @@ public class HumanPlayer extends PlayerImpl {
if (replacementEffectChoice.getChoiceKey() != null) { if (replacementEffectChoice.getChoiceKey() != null) {
int index = 0; int index = 0;
for (String key : rEffects.keySet()) { for (String key : effectsMap.keySet()) {
if (replacementEffectChoice.getChoiceKey().equals(key)) { if (replacementEffectChoice.getChoiceKey().equals(key)) {
return index; return index;
} }

View file

@ -2140,8 +2140,8 @@ public class TestPlayer implements Player {
} }
@Override @Override
public int chooseReplacementEffect(Map<String, String> rEffects, Game game) { public int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game) {
if (rEffects.size() <= 1) { if (effectsMap.size() <= 1) {
return 0; return 0;
} }
assertAliasSupportInChoices(false); assertAliasSupportInChoices(false);
@ -2149,7 +2149,7 @@ public class TestPlayer implements Player {
String choice = choices.get(0); String choice = choices.get(0);
int index = 0; int index = 0;
for (Map.Entry<String, String> entry : rEffects.entrySet()) { for (Map.Entry<String, String> entry : effectsMap.entrySet()) {
if (entry.getValue().startsWith(choice)) { if (entry.getValue().startsWith(choice)) {
choices.remove(0); choices.remove(0);
return index; return index;
@ -2160,8 +2160,8 @@ public class TestPlayer implements Player {
assertWrongChoiceUsage(choice); assertWrongChoiceUsage(choice);
} }
this.chooseStrictModeFailed("choice", game, String.join("\n", rEffects.values())); this.chooseStrictModeFailed("choice", game, String.join("\n", effectsMap.values()));
return computerPlayer.chooseReplacementEffect(rEffects, game); return computerPlayer.chooseReplacementEffect(effectsMap, objectsMap, game);
} }
@Override @Override

View file

@ -868,7 +868,10 @@ public class ContinuousEffects implements Serializable {
} else { } else {
//20100716 - 616.1c //20100716 - 616.1c
Player player = game.getPlayer(event.getPlayerId()); Player player = game.getPlayer(event.getPlayerId());
index = player.chooseReplacementEffect(getReplacementEffectsTexts(rEffects, game), game); Map<String, String> effectsMap = new LinkedHashMap<>();
Map<String, MageObject> objectsMap = new LinkedHashMap<>();
prepareReplacementEffectMaps(rEffects, game, effectsMap, objectsMap);
index = player.chooseReplacementEffect(effectsMap, objectsMap, game);
} }
// get the selected effect // get the selected effect
int checked = 0; int checked = 0;
@ -1317,18 +1320,26 @@ public class ContinuousEffects implements Serializable {
} }
} }
public Map<String, String> getReplacementEffectsTexts(Map<ReplacementEffect, Set<Ability>> rEffects, Game game) { public void prepareReplacementEffectMaps(Map<ReplacementEffect, Set<Ability>> rEffects, Game game,
Map<String, String> effectsMap, Map<String, MageObject> objectsMap) {
// warning, autoSelectReplacementEffects uses [object id] in texts as different settings, // warning, autoSelectReplacementEffects uses [object id] in texts as different settings,
// so if you change keys or texts logic then don't forget to change auto-choose too // so if you change keys or texts logic then don't forget to change auto-choose too
Map<String, String> texts = new LinkedHashMap<>(); if (!(effectsMap instanceof LinkedHashMap) || !(objectsMap instanceof LinkedHashMap)) {
throw new IllegalArgumentException("Wrong code usage: must use LinkedHashMap only");
}
effectsMap.clear();
objectsMap.clear();
for (Map.Entry<ReplacementEffect, Set<Ability>> entry : rEffects.entrySet()) { for (Map.Entry<ReplacementEffect, Set<Ability>> entry : rEffects.entrySet()) {
if (entry.getValue() != null) { if (entry.getValue() != null) {
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
MageObject object = game.getObject(ability.getSourceId()); MageObject object = game.getObject(ability.getSourceId());
String key = ability.getId().toString() + '_' + entry.getKey().getId().toString();
if (object != null) { if (object != null) {
texts.put(ability.getId().toString() + '_' + entry.getKey().getId().toString(), object.getIdName() + ": " + ability.getRule(object.getName())); effectsMap.put(key, object.getIdName() + ": " + ability.getRule(object.getName()));
objectsMap.put(key, object);
} else { } else {
texts.put(ability.getId().toString() + '_' + entry.getKey().getId().toString(), entry.getKey().getText(null)); effectsMap.put(key, entry.getKey().getText(null));
objectsMap.put(key, null);
} }
} }
} else { } else {
@ -1337,7 +1348,6 @@ public class ContinuousEffects implements Serializable {
} }
} }
} }
return texts;
} }
public boolean existRequirementEffects() { public boolean existRequirementEffects() {

View file

@ -740,8 +740,8 @@ public interface Player extends MageItem, Copyable<Player> {
// set the value for non mana X costs // set the value for non mana X costs
int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost); int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost);
// TODO: rework choose replacement effects to use array, not map (it'a random order now) // TODO: rework to use pair's list of effect + ability instead string's map
int chooseReplacementEffect(Map<String, String> abilityMap, Game game); int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game);
TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game); TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game);

View file

@ -2,6 +2,7 @@ package mage.players;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import mage.MageItem; import mage.MageItem;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.Modes; import mage.abilities.Modes;
@ -165,7 +166,7 @@ public class StubPlayer extends PlayerImpl {
} }
@Override @Override
public int chooseReplacementEffect(Map<String, String> abilityMap, Game game) { public int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game) {
return 0; return 0;
} }