mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
Improvements to player selection of TargetAmount (#11341)
This commit is contained in:
parent
bd298d6179
commit
18c6596cc0
6 changed files with 44 additions and 14 deletions
|
|
@ -89,7 +89,7 @@ public class PickMultiNumberDialog extends MageDialog {
|
||||||
labelList.add(label);
|
labelList.add(label);
|
||||||
|
|
||||||
JSpinner spinner = new JSpinner();
|
JSpinner spinner = new JSpinner();
|
||||||
spinner.setModel(new SpinnerNumberModel(0, messages.get(i).min, messages.get(i).max, 1));
|
spinner.setModel(new SpinnerNumberModel(messages.get(i).min, messages.get(i).min, messages.get(i).max, 1));
|
||||||
spinnerC.weightx = 0.5;
|
spinnerC.weightx = 0.5;
|
||||||
spinnerC.gridx = 1;
|
spinnerC.gridx = 1;
|
||||||
spinnerC.gridy = i;
|
spinnerC.gridy = i;
|
||||||
|
|
|
||||||
|
|
@ -888,6 +888,14 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
int amountTotal = target.getAmountTotal(game, source);
|
int amountTotal = target.getAmountTotal(game, source);
|
||||||
|
if (amountTotal == 0) {
|
||||||
|
return false; // nothing to distribute
|
||||||
|
}
|
||||||
|
MultiAmountType multiAmountType = source.getRule().contains("damage") ? MultiAmountType.DAMAGE : MultiAmountType.P1P1;
|
||||||
|
|
||||||
|
// 601.2d. If the spell requires the player to divide or distribute an effect (such as damage or counters)
|
||||||
|
// among one or more targets, the player announces the division.
|
||||||
|
// Each of these targets must receive at least one of whatever is being divided.
|
||||||
|
|
||||||
// Two steps logic:
|
// Two steps logic:
|
||||||
// 1. Select targets
|
// 1. Select targets
|
||||||
|
|
@ -896,7 +904,7 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
// 1. Select targets
|
// 1. Select targets
|
||||||
while (canRespond()) {
|
while (canRespond()) {
|
||||||
Set<UUID> possibleTargetIds = target.possibleTargets(abilityControllerId, source, game);
|
Set<UUID> possibleTargetIds = target.possibleTargets(abilityControllerId, source, game);
|
||||||
boolean required = target.isRequired(source != null ? source.getSourceId() : null, game);
|
boolean required = target.isRequired(source.getSourceId(), game);
|
||||||
if (possibleTargetIds.isEmpty()
|
if (possibleTargetIds.isEmpty()
|
||||||
|| target.getSize() >= target.getNumberOfTargets()) {
|
|| target.getSize() >= target.getNumberOfTargets()) {
|
||||||
required = false;
|
required = false;
|
||||||
|
|
@ -928,9 +936,9 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
updateGameStatePriority("chooseTargetAmount", game);
|
updateGameStatePriority("chooseTargetAmount", game);
|
||||||
prepareForResponse(game);
|
prepareForResponse(game);
|
||||||
if (!isExecutingMacro()) {
|
if (!isExecutingMacro()) {
|
||||||
// target amount uses for damage only, if you see another use case then message must be changed here and on getMultiAmount call
|
String multiType = multiAmountType == MultiAmountType.DAMAGE ? " to divide %d damage" : " to distribute %d counters";
|
||||||
|
String message = target.getMessage() + String.format(multiType, amountTotal);
|
||||||
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), possibleTargetIds, required, options);
|
game.fireSelectTargetEvent(playerId, new MessageToClient(message, getRelatedObjectName(source, game)), possibleTargetIds, required, options);
|
||||||
}
|
}
|
||||||
waitForResponse(game);
|
waitForResponse(game);
|
||||||
|
|
||||||
|
|
@ -941,7 +949,9 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
if (target.contains(responseId)) {
|
if (target.contains(responseId)) {
|
||||||
// unselect
|
// unselect
|
||||||
target.remove(responseId);
|
target.remove(responseId);
|
||||||
} else if (possibleTargetIds.contains(responseId) && target.canTarget(abilityControllerId, responseId, source, game)) {
|
} else if (possibleTargetIds.contains(responseId)
|
||||||
|
&& target.canTarget(abilityControllerId, responseId, source, game)
|
||||||
|
&& target.getSize() < amountTotal) {
|
||||||
// select
|
// select
|
||||||
target.addTarget(responseId, source, game);
|
target.addTarget(responseId, source, game);
|
||||||
}
|
}
|
||||||
|
|
@ -958,6 +968,26 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
|
|
||||||
// 2. Distribute amount between selected targets
|
// 2. Distribute amount between selected targets
|
||||||
|
|
||||||
|
// if only one target, it gets full amount, no possible choice
|
||||||
|
if (targets.size() == 1) {
|
||||||
|
target.setTargetAmount(targets.get(0), amountTotal, source, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if number of targets equal to amount, each get 1, no possible choice
|
||||||
|
if (targets.size() == amountTotal) {
|
||||||
|
for (UUID targetId : targets) {
|
||||||
|
target.setTargetAmount(targetId, 1, source, game);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should not be able to have more targets than amount, but in such case it's illegal
|
||||||
|
if (targets.size() > amountTotal) {
|
||||||
|
target.clearChosen();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// prepare targets list with p/t or life stats (cause that's dialog used for damage distribute)
|
// prepare targets list with p/t or life stats (cause that's dialog used for damage distribute)
|
||||||
List<String> targetNames = new ArrayList<>();
|
List<String> targetNames = new ArrayList<>();
|
||||||
for (UUID targetId : targets) {
|
for (UUID targetId : targets) {
|
||||||
|
|
@ -978,7 +1008,6 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiAmountType multiAmountType = source.toString().contains("counters") ? MultiAmountType.P1P1 : MultiAmountType.DAMAGE;
|
|
||||||
// ask and assign new amount
|
// ask and assign new amount
|
||||||
List<Integer> targetValues = getMultiAmount(outcome, targetNames, 1, amountTotal, multiAmountType, game);
|
List<Integer> targetValues = getMultiAmount(outcome, targetNames, 1, amountTotal, multiAmountType, game);
|
||||||
for (int i = 0; i < targetValues.size(); i++) {
|
for (int i = 0; i < targetValues.size(); i++) {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class KlauthUnrivaledAncientEffect extends OneShotEffect {
|
||||||
.mapToInt(MageInt::getValue)
|
.mapToInt(MageInt::getValue)
|
||||||
.sum();
|
.sum();
|
||||||
List<Integer> manaList = player.getMultiAmount(
|
List<Integer> manaList = player.getMultiAmount(
|
||||||
outcome, manaSymbols, attackerPower, attackerPower, MultiAmountType.MANA, game
|
outcome, manaSymbols, 0, attackerPower, MultiAmountType.MANA, game
|
||||||
);
|
);
|
||||||
player.getManaPool().addMana(
|
player.getManaPool().addMana(
|
||||||
new KlauthUnrivaledAncientConditionalMana(manaList), game, source, true
|
new KlauthUnrivaledAncientConditionalMana(manaList), game, source, true
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
||||||
|
|
||||||
// Ask player for color distribution
|
// Ask player for color distribution
|
||||||
int manaAmount = amount.calculate(game, source, this);
|
int manaAmount = amount.calculate(game, source, this);
|
||||||
List<Integer> manaList = player.getMultiAmount(this.outcome, manaStrings, manaAmount, manaAmount, MultiAmountType.MANA, game);
|
List<Integer> manaList = player.getMultiAmount(this.outcome, manaStrings, 0, manaAmount, MultiAmountType.MANA, game);
|
||||||
|
|
||||||
// Convert choices to mana
|
// Convert choices to mana
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ public class DynamicManaEffect extends ManaEffect {
|
||||||
manaStrings.add("B");
|
manaStrings.add("B");
|
||||||
manaStrings.add("R");
|
manaStrings.add("R");
|
||||||
manaStrings.add("G");
|
manaStrings.add("G");
|
||||||
List<Integer> choices = controller.getMultiAmount(this.outcome, manaStrings, count, count, MultiAmountType.MANA, game);
|
List<Integer> choices = controller.getMultiAmount(this.outcome, manaStrings, 0, count, MultiAmountType.MANA, game);
|
||||||
computedMana.add(new Mana(choices.get(0), choices.get(1), choices.get(2), choices.get(3), choices.get(4), 0, 0, 0));
|
computedMana.add(new Mana(choices.get(0), choices.get(1), choices.get(2), choices.get(3), choices.get(4), 0, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -758,8 +758,9 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
|
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
|
||||||
*/
|
*/
|
||||||
default List<Integer> getMultiAmount(Outcome outcome, List<String> messages, int min, int max, MultiAmountType type, Game game) {
|
default List<Integer> getMultiAmount(Outcome outcome, List<String> messages, int min, int max, MultiAmountType type, Game game) {
|
||||||
List<MultiAmountMessage> constraints = messages.stream().map(s -> new MultiAmountMessage(s, 0, max)).collect(Collectors.toList());
|
List<MultiAmountMessage> constraints = messages.stream()
|
||||||
|
.map(s -> new MultiAmountMessage(s, min, max))
|
||||||
|
.collect(Collectors.toList());
|
||||||
return getMultiAmountWithIndividualConstraints(outcome, constraints, min, max, type, game);
|
return getMultiAmountWithIndividualConstraints(outcome, constraints, min, max, type, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -768,8 +769,8 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
*
|
*
|
||||||
* @param outcome AI hint
|
* @param outcome AI hint
|
||||||
* @param messages List of options to distribute amount among. Each option has a constraint on the min, max chosen for it
|
* @param messages List of options to distribute amount among. Each option has a constraint on the min, max chosen for it
|
||||||
* @param totalMin Total minimum amount to be distributed
|
* @param min Total minimum amount to be distributed
|
||||||
* @param totalMax Total amount to be distributed
|
* @param max Total amount to be distributed
|
||||||
* @param type MultiAmountType enum to set dialog options such as title and header
|
* @param type MultiAmountType enum to set dialog options such as title and header
|
||||||
* @param game Game
|
* @param game Game
|
||||||
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
|
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue