* GUI: added auto-choose for replacement effects (remember answer in dialog + reset answer in popup menu + new option in preferences; #4360, #328, #4219, #6676, #7914);

This commit is contained in:
Oleg Agafonov 2021-08-09 11:25:51 +04:00
parent c081d3fa33
commit c9ab896d24
11 changed files with 311 additions and 77 deletions

View file

@ -189,7 +189,7 @@ public class ContinuousEffects implements Serializable {
}
}
} else {
logger.error("No abilities for continuous effect: " + effect.toString());
logger.error("No abilities for continuous effect: " + effect);
}
break;
default:
@ -1282,7 +1282,7 @@ public class ContinuousEffects implements Serializable {
logger.error("Effect is null: " + source.toString());
return;
} else if (source == null) {
logger.warn("Adding effect without ability : " + effect.toString());
logger.warn("Adding effect without ability : " + effect);
}
switch (effect.getEffectType()) {
case REPLACEMENT:
@ -1369,6 +1369,8 @@ public class ContinuousEffects implements Serializable {
}
public Map<String, String> getReplacementEffectsTexts(Map<ReplacementEffect, Set<Ability>> rEffects, Game game) {
// 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
Map<String, String> texts = new LinkedHashMap<>();
for (Map.Entry<ReplacementEffect, Set<Ability>> entry : rEffects.entrySet()) {
if (entry.getValue() != null) {

View file

@ -1,55 +1,92 @@
package mage.choices;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public interface Choice {
public interface Choice extends Serializable, Copyable<Choice> {
String getMessage();
void setMessage(String message);
String getSubMessage();
void setSubMessage(String subMessage);
void clearChoice();
boolean isChosen();
boolean isChosenSpecial();
boolean isRequired();
Choice copy();
// special mode for all choices
void setSpecial(boolean enabled, boolean canBeEmpty, String text, String hint);
boolean isSpecialEnabled();
boolean isSpecialCanBeEmpty();
String getSpecialText();
String getSpecialHint();
// string choice
void setChoices(Set<String> choices);
Set<String> getChoices();
void setChoice(String choice);
void setChoice(String choice, boolean isSpecial);
String getChoice();
default void setChoice(String choice) {
setChoice(choice, false);
}
// key-value choice
boolean isKeyChoice();
void setKeyChoices(Map<String, String> choices);
Map<String,String> getKeyChoices();
void setChoiceByKey(String choiceKey);
Map<String, String> getKeyChoices();
void setChoiceByKey(String choiceKey, boolean isSpecial);
String getChoiceKey();
String getChoiceValue();
default void setChoiceByKey(String choiceKey) {
setChoiceByKey(choiceKey, false);
}
// search
boolean isSearchEnabled();
void setSearchEnabled(boolean isEnabled);
void setSearchText(String searchText);
String getSearchText();
// sorting
boolean isSortEnabled();
void setSortData(Map<String, Integer> sortData);
Map<String, Integer> getSortData();
// random choice
// random choice (for AI usage)
void setRandomChoice();
boolean setChoiceByAnswers(List<String> answers, boolean removeSelectAnswerFromList);
}

View file

@ -2,15 +2,15 @@ package mage.choices;
import mage.util.RandomUtil;
import java.io.Serializable;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class ChoiceImpl implements Choice, Serializable {
public class ChoiceImpl implements Choice {
protected boolean chosen;
protected boolean chosenNormal;
protected boolean chosenSpecial;
protected final boolean required;
protected String choice;
protected String choiceKey;
@ -22,6 +22,13 @@ public class ChoiceImpl implements Choice, Serializable {
protected boolean searchEnabled = true; // enable for all windows by default
protected String searchText;
// special button with #-answer
// warning, only for human's GUI, not AI
protected boolean specialEnabled = false;
protected boolean specialCanBeEmpty = false; // enable if you want to select "nothing", but not cancel
protected String specialText = "";
protected String specialHint = "";
public ChoiceImpl() {
this(false);
}
@ -30,9 +37,10 @@ public class ChoiceImpl implements Choice, Serializable {
this.required = required;
}
public ChoiceImpl(ChoiceImpl choice) {
public ChoiceImpl(final ChoiceImpl choice) {
this.choice = choice.choice;
this.chosen = choice.chosen;
this.chosenNormal = choice.chosenNormal;
this.chosenSpecial = choice.chosenSpecial;
this.required = choice.required;
this.message = choice.message;
this.subMessage = choice.subMessage;
@ -42,18 +50,28 @@ public class ChoiceImpl implements Choice, Serializable {
this.choiceKey = choice.choiceKey;
this.keyChoices = choice.keyChoices; // list should never change for the same object so copy by reference TODO: check errors with that, it that ok? Color list is static
this.sortData = choice.sortData;
this.specialEnabled = choice.specialEnabled;
this.specialCanBeEmpty = choice.specialCanBeEmpty;
this.specialText = choice.specialText;
this.specialHint = choice.specialHint;
}
@Override
public boolean isChosen() {
return chosen;
return chosenNormal || chosenSpecial;
}
@Override
public boolean isChosenSpecial() {
return chosenSpecial;
}
@Override
public void clearChoice() {
choice = null;
choiceKey = null;
chosen = false;
this.choice = null;
this.choiceKey = null;
this.chosenNormal = false;
this.chosenSpecial = false;
}
@Override
@ -92,10 +110,17 @@ public class ChoiceImpl implements Choice, Serializable {
}
@Override
public void setChoice(String choice) {
public void setChoice(String choice, boolean isSpecial) {
if (choices.contains(choice)) {
this.choice = choice;
this.chosen = true;
this.chosenNormal = true;
this.chosenSpecial = isSpecial;
}
if (isSpecial && this.specialCanBeEmpty && (choice == null || choice.isEmpty())) {
clearChoice();
this.chosenNormal = false;
this.chosenSpecial = true;
}
}
@ -134,12 +159,19 @@ public class ChoiceImpl implements Choice, Serializable {
}
@Override
public void setChoiceByKey(String choiceKey) {
public void setChoiceByKey(String choiceKey, boolean isSpecial) {
String choiceToSet = keyChoices.get(choiceKey);
if (choiceToSet != null) {
this.choice = choiceToSet;
this.choiceKey = choiceKey;
this.chosen = true;
this.chosenNormal = true;
this.chosenSpecial = isSpecial;
}
if (isSpecial && this.specialCanBeEmpty && (choiceKey == null || choiceKey.isEmpty())) {
clearChoice();
this.chosenNormal = false;
this.chosenSpecial = true;
}
}
@ -191,14 +223,14 @@ public class ChoiceImpl implements Choice, Serializable {
String[] vals = this.getKeyChoices().keySet().toArray(new String[0]);
if (vals.length > 0) {
int choiceNum = RandomUtil.nextInt(vals.length);
this.setChoiceByKey(vals[choiceNum]);
this.setChoiceByKey(vals[choiceNum], false);
}
} else {
// string mode
String[] vals = this.getChoices().toArray(new String[0]);
if (vals.length > 0) {
int choiceNum = RandomUtil.nextInt(vals.length);
this.setChoice(vals[choiceNum]);
this.setChoice(vals[choiceNum], false);
}
}
}
@ -211,18 +243,18 @@ public class ChoiceImpl implements Choice, Serializable {
for (String needChoice : answers) {
for (Map.Entry<String, String> currentChoice : this.getKeyChoices().entrySet()) {
if (currentChoice.getKey().equals(needChoice)) {
this.setChoiceByKey(needChoice);
this.setChoiceByKey(needChoice, false);
answers.remove(needChoice);
return true;
}
}
}
// no key answer found, try to macht by text starting with
// no key answer found, try to match by text starting with
for (String needChoice : answers) {
for (Map.Entry<String, String> currentChoice : this.getKeyChoices().entrySet()) {
if (currentChoice.getValue().startsWith(needChoice)) {
this.setChoiceByKey(currentChoice.getKey());
this.setChoiceByKey(currentChoice.getKey(), false);
answers.remove(needChoice);
return true;
}
@ -233,7 +265,7 @@ public class ChoiceImpl implements Choice, Serializable {
for (String needChoice : answers) {
for (String currentChoice : this.getChoices()) {
if (currentChoice.equals(needChoice)) {
this.setChoice(needChoice);
this.setChoice(needChoice, false);
answers.remove(needChoice);
return true;
}
@ -242,4 +274,32 @@ public class ChoiceImpl implements Choice, Serializable {
}
return false; // can't find answer
}
@Override
public void setSpecial(boolean enabled, boolean canBeEmpty, String text, String hint) {
this.specialEnabled = enabled;
this.specialCanBeEmpty = canBeEmpty;
this.specialText = text;
this.specialHint = hint;
}
@Override
public boolean isSpecialEnabled() {
return this.specialEnabled;
}
@Override
public boolean isSpecialCanBeEmpty() {
return this.specialCanBeEmpty;
}
@Override
public String getSpecialText() {
return this.specialText;
}
@Override
public String getSpecialHint() {
return this.specialHint;
}
}

View file

@ -23,6 +23,7 @@ public class UserData implements Serializable {
protected boolean passPriorityCast;
protected boolean passPriorityActivation;
protected boolean autoOrderTrigger;
protected boolean useSameSettingsForReplacementEffects;
protected boolean useFirstManaAbility = false;
private String userIdStr;
protected Map<UUID, Set<UUID>> requestedHandPlayersList; // game -> players list
@ -36,10 +37,22 @@ public class UserData implements Serializable {
private int constructedRating;
private int limitedRating;
public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced,
boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps,
String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted,
boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) {
public UserData(UserGroup userGroup,
int avatarId,
boolean showAbilityPickerForced,
boolean allowRequestShowHandCards,
boolean confirmEmptyManaPool,
UserSkipPrioritySteps userSkipPrioritySteps,
String flagName,
boolean askMoveToGraveOrder,
boolean manaPoolAutomatic,
boolean manaPoolAutomaticRestricted,
boolean passPriorityCast,
boolean passPriorityActivation,
boolean autoOrderTrigger,
boolean useSameSettingsForReplacementEffects,
boolean useFirstManaAbility,
String userIdStr) {
this.groupId = userGroup.getGroupId();
this.avatarId = avatarId;
this.showAbilityPickerForced = showAbilityPickerForced;
@ -53,6 +66,7 @@ public class UserData implements Serializable {
this.passPriorityCast = passPriorityCast;
this.passPriorityActivation = passPriorityActivation;
this.autoOrderTrigger = autoOrderTrigger;
this.useSameSettingsForReplacementEffects = useSameSettingsForReplacementEffects;
this.useFirstManaAbility = useFirstManaAbility;
this.matchHistory = "";
this.matchQuitRatio = 0;
@ -76,13 +90,31 @@ public class UserData implements Serializable {
this.passPriorityCast = userData.passPriorityCast;
this.passPriorityActivation = userData.passPriorityActivation;
this.autoOrderTrigger = userData.autoOrderTrigger;
this.useSameSettingsForReplacementEffects = userData.useSameSettingsForReplacementEffects;
this.useFirstManaAbility = userData.useFirstManaAbility;
this.userIdStr = userData.userIdStr;
// todo: why we don't update user stats here? => can't be updated from client side
}
public static UserData getDefaultUserDataView() {
return new UserData(UserGroup.DEFAULT, 0, false, false, true, new UserSkipPrioritySteps(), getDefaultFlagName(), false, true, true, false, false, false, false, "");
return new UserData(
UserGroup.DEFAULT,
0,
false,
false,
true,
new UserSkipPrioritySteps(),
getDefaultFlagName(),
false,
true,
true,
false,
false,
true,
true,
false,
""
);
}
public void setGroupId(int groupId) {
@ -115,10 +147,7 @@ public class UserData implements Serializable {
public boolean isAllowRequestHandToPlayer(UUID gameId, UUID requesterPlayerId) {
// once per game
boolean allowToPlayer = true;
if (requestedHandPlayersList.containsKey(gameId) && requestedHandPlayersList.get(gameId).contains(requesterPlayerId)) {
allowToPlayer = false;
}
boolean allowToPlayer = !requestedHandPlayersList.containsKey(gameId) || !requestedHandPlayersList.get(gameId).contains(requesterPlayerId);
return isAllowRequestHandToAll() && allowToPlayer;
}
@ -206,6 +235,10 @@ public class UserData implements Serializable {
return autoOrderTrigger;
}
public boolean isUseSameSettingsForReplacementEffects() {
return useSameSettingsForReplacementEffects;
}
public void setAutoOrderTrigger(boolean autoOrderTrigger) {
this.autoOrderTrigger = autoOrderTrigger;
}