UI: improved skips and stops for declare blocker step:

* added options to STOP skip on any or zero blockers available;
 * added auto-stop before declare blockers step (e.g. user can cast instants and crew abilities);
This commit is contained in:
Oleg Agafonov 2019-03-29 18:10:00 +04:00
parent 6606b586a4
commit ff640a942e
4 changed files with 126 additions and 44 deletions

View file

@ -4071,7 +4071,7 @@
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="phases_stopSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="185" max="32767" attributes="0"/>
<EmptySpace pref="160" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -4170,7 +4170,7 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="1"/>
<Property name="rows" type="int" value="8"/>
<Property name="rows" type="int" value="9"/>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="cbStopAttack">
@ -4184,14 +4184,25 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopAttackActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlock">
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny">
<Properties>
<Property name="text" type="java.lang.String" value="STOP skips on declare blockers if blockers are available"/>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="STOP skips on declare blockers if ANY blockers are available"/>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithAnyActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero">
<Properties>
<Property name="text" type="java.lang.String" value="STOP skips on declare blockers if ZERO blockers are available"/>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithZeroActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects">

View file

@ -121,7 +121,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String END_OF_TURN_OTHERS = "endOfTurnOthers";
public static final String KEY_STOP_ATTACK = "stopDeclareAttacksStep";
public static final String KEY_STOP_BLOCK = "stopDeclareBlockersStep";
public static final String KEY_STOP_BLOCK_WITH_ANY = "stopDeclareBlockersStepWithAny";
public static final String KEY_STOP_BLOCK_WITH_ZERO = "stopDeclareBlockersStepWithZero";
public static final String KEY_STOP_ALL_MAIN_PHASES = "stopOnAllMainPhases";
public static final String KEY_STOP_ALL_END_PHASES = "stopOnAllEndPhases";
public static final String KEY_STOP_NEW_STACK_OBJECTS = "stopOnNewStackObjects";
@ -454,7 +455,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
checkBoxEndTurnOthers = new javax.swing.JCheckBox();
phases_stopSettings = new javax.swing.JPanel();
cbStopAttack = new javax.swing.JCheckBox();
cbStopBlock = new javax.swing.JCheckBox();
cbStopBlockWithAny = new javax.swing.JCheckBox();
cbStopBlockWithZero = new javax.swing.JCheckBox();
cbStopOnNewStackObjects = new javax.swing.JCheckBox();
cbStopOnAllMain = new javax.swing.JCheckBox();
cbStopOnAllEnd = new javax.swing.JCheckBox();
@ -655,7 +657,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
showFullImagePath.setSelected(true);
showFullImagePath.setToolTipText("Show the path Xmage is expecting for this card's image (only displays if missing)");
showFullImagePath.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
showFullImagePath.setText("Display image path for missing images");
showFullImagePath.setLabel("Display image path for missing images");
showFullImagePath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showFullImagePathActionPerformed(evt);
@ -1321,7 +1323,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
jLabelEndOfTurn.setText("End of turn:");
phases_stopSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "SKIP settings"));
phases_stopSettings.setLayout(new java.awt.GridLayout(8, 1));
phases_stopSettings.setLayout(new java.awt.GridLayout(9, 1));
cbStopAttack.setSelected(true);
cbStopAttack.setText("STOP skips on declare attackers if attackers are available");
@ -1334,15 +1336,26 @@ public class PreferencesDialog extends javax.swing.JDialog {
});
phases_stopSettings.add(cbStopAttack);
cbStopBlock.setText("STOP skips on declare blockers if blockers are available");
cbStopBlock.setToolTipText("");
cbStopBlock.setActionCommand("");
cbStopBlock.addActionListener(new java.awt.event.ActionListener() {
cbStopBlockWithAny.setSelected(true);
cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available");
cbStopBlockWithAny.setToolTipText("");
cbStopBlockWithAny.setActionCommand("");
cbStopBlockWithAny.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockActionPerformed(evt);
cbStopBlockWithAnyActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlock);
phases_stopSettings.add(cbStopBlockWithAny);
cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available");
cbStopBlockWithZero.setToolTipText("");
cbStopBlockWithZero.setActionCommand("");
cbStopBlockWithZero.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockWithZeroActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlockWithZero);
cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)");
cbStopOnNewStackObjects.setToolTipText("");
@ -1520,7 +1533,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(checkBoxEndTurnOthers))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
.add(phases_stopSettings, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(185, Short.MAX_VALUE))
.addContainerGap(160, Short.MAX_VALUE))
);
tabsPanel.addTab("Phases & Priority", tabPhases);
@ -2700,7 +2713,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
tabsPanel.addTab("Controls", tabControls);
saveButton.setText("Save");
saveButton.setLabel("Save");
saveButton.setMaximumSize(new java.awt.Dimension(100, 30));
saveButton.setMinimumSize(new java.awt.Dimension(100, 30));
saveButton.setPreferredSize(new java.awt.Dimension(100, 30));
@ -2711,7 +2724,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
});
exitButton.setText("Exit");
exitButton.setLabel("Exit");
exitButton.setMaximumSize(new java.awt.Dimension(100, 30));
exitButton.setMinimumSize(new java.awt.Dimension(100, 30));
exitButton.setPreferredSize(new java.awt.Dimension(100, 30));
@ -2857,7 +2870,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS);
save(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopBlockWithAny, KEY_STOP_BLOCK_WITH_ANY, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopBlockWithZero, KEY_STOP_BLOCK_WITH_ZERO, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbStopOnNewStackObjects, KEY_STOP_NEW_STACK_OBJECTS, "true", "false", UPDATE_CACHE_POLICY);
@ -3113,9 +3127,9 @@ public class PreferencesDialog extends javax.swing.JDialog {
// TODO add your handling code here:
}//GEN-LAST:event_cbStopAttackActionPerformed
private void cbStopBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockActionPerformed
private void cbStopBlockWithAnyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithAnyActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopBlockActionPerformed
}//GEN-LAST:event_cbStopBlockWithAnyActionPerformed
private void cbStopOnAllMainActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllMainActionPerformed
// TODO add your handling code here:
@ -3232,6 +3246,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
// TODO add your handling code here:
}//GEN-LAST:event_cbStopOnNewStackObjectsActionPerformed
private void cbStopBlockWithZeroActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithZeroActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopBlockWithZeroActionPerformed
private void showProxySettings() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
switch (proxyType) {
@ -3376,7 +3394,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on", "on");
load(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "true");
load(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "true");
load(prefs, dialog.cbStopBlockWithAny, KEY_STOP_BLOCK_WITH_ANY, "true", "true");
load(prefs, dialog.cbStopBlockWithZero, KEY_STOP_BLOCK_WITH_ZERO, "true", "false");
load(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false");
load(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false");
load(prefs, dialog.cbStopOnNewStackObjects, KEY_STOP_NEW_STACK_OBJECTS, "true", "false");
@ -3544,7 +3563,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
userSkipPrioritySteps.getOpponentTurn().setEndOfTurn(dialog.checkBoxEndTurnOthers.isSelected());
userSkipPrioritySteps.setStopOnDeclareAttackersDuringSkipActions(dialog.cbStopAttack.isSelected());
userSkipPrioritySteps.setStopOnDeclareBlockerIfNoneAvailable(dialog.cbStopBlock.isSelected());
userSkipPrioritySteps.setStopOnDeclareBlockersWithAnyPermanents(dialog.cbStopBlockWithAny.isSelected());
userSkipPrioritySteps.setStopOnDeclareBlockersWithZeroPermanents(dialog.cbStopBlockWithZero.isSelected());
userSkipPrioritySteps.setStopOnAllEndPhases(dialog.cbStopOnAllEnd.isSelected());
userSkipPrioritySteps.setStopOnAllMainPhases(dialog.cbStopOnAllMain.isSelected());
userSkipPrioritySteps.setStopOnStackNewObjects(dialog.cbStopOnNewStackObjects.isSelected());
@ -3914,7 +3934,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
private javax.swing.JCheckBox cbSaveToZipFiles;
private javax.swing.JCheckBox cbShowStormCounter;
private javax.swing.JCheckBox cbStopAttack;
private javax.swing.JCheckBox cbStopBlock;
private javax.swing.JCheckBox cbStopBlockWithAny;
private javax.swing.JCheckBox cbStopBlockWithZero;
private javax.swing.JCheckBox cbStopOnAllEnd;
private javax.swing.JCheckBox cbStopOnAllMain;
private javax.swing.JCheckBox cbStopOnNewStackObjects;

View file

@ -755,8 +755,27 @@ public class HumanPlayer extends PlayerImpl {
}
}
// SKIP buttons - use the skip actions only if the player itself controls its turn
// STOP conditions (temporary stop without skip reset)
boolean quickStop = false;
if (isGameUnderControl()) {
// if was attacked - always stop BEFORE blocker step (to cast extra spells)
if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS
&& game.getCombat().getPlayerDefenders(game).contains(playerId)) {
FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy();
filter.add(new ControllerIdPredicate(playerId));
// stop skip on any/zero permanents available
int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game);
boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents();
boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents();
quickStop = canStopOnAny || canStopOnZero;
}
}
// SKIP - use the skip actions only if the player itself controls its turn
if (!quickStop && isGameUnderControl()) {
if (passedAllTurns || passedTurnSkipStack) {
if (passWithManaPoolCheck(game)) {
return false;
@ -1185,11 +1204,23 @@ public class HumanPlayer extends PlayerImpl {
filter.add(new ControllerIdPredicate(attackingPlayerId));
while (!abort) {
List<UUID> possibleAttackers = new ArrayList<>();
for (Permanent possibleAttacker : game.getBattlefield().getActivePermanents(filter, attackingPlayerId, game)) {
if (possibleAttacker.canAttack(null, game)) {
possibleAttackers.add(possibleAttacker.getId());
}
}
// skip declare attack step
// old version:
// - passedAllTurns, passedUntilEndStepBeforeMyTurn: always skipped
// - other: on disabled option skipped
if (passedAllTurns
|| passedUntilEndStepBeforeMyTurn
|| (!getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackersDuringSkipAction()
.isStopOnDeclareAttackers()
&& (passedTurn
|| passedTurnSkipStack
|| passedUntilEndOfTurn
@ -1198,14 +1229,21 @@ public class HumanPlayer extends PlayerImpl {
return;
}
}
Map<String, Serializable> options = new HashMap<>();
List<UUID> possibleAttackers = new ArrayList<>();
for (Permanent possibleAttacker : game.getBattlefield().getActivePermanents(filter, attackingPlayerId, game)) {
if (possibleAttacker.canAttack(null, game)) {
possibleAttackers.add(possibleAttacker.getId());
/*
// new version:
// - all: on disabled option skipped (if attackers selected)
if (!getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackers()
&& (possibleAttackers.size() > 0)) {
if (checkIfAttackersValid(game)) {
return;
}
}
*/
Map<String, Serializable> options = new HashMap<>();
options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable) possibleAttackers);
if (!possibleAttackers.isEmpty()) {
options.put(Constants.Option.SPECIAL_BUTTON, "All attack");
@ -1424,12 +1462,15 @@ public class HumanPlayer extends PlayerImpl {
updateGameStatePriority("selectBlockers", game);
FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy();
filter.add(new ControllerIdPredicate(defendingPlayerId));
if (game.getBattlefield().count(filter, null, playerId, game) == 0
&& !getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareBlockerIfNoneAvailable()) {
// stop skip on any/zero permanents available
int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game);
boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents();
boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents();
if (!canStopOnAny && !canStopOnZero) {
return;
}
while (!abort) {
prepareForResponse(game);
if (!isExecutingMacro()) {

View file

@ -10,8 +10,9 @@ public class UserSkipPrioritySteps implements Serializable {
final SkipPrioritySteps yourTurn;
final SkipPrioritySteps opponentTurn;
boolean stopOnDeclareAttackersDuringSkipAction = true;
boolean stopOnDeclareBlockerIfNoneAvailable = true;
boolean stopOnDeclareAttackers = true;
boolean stopOnDeclareBlockersWithZeroPermanents = false;
boolean stopOnDeclareBlockersWithAnyPermanents = true;
boolean stopOnAllMainPhases = true;
boolean stopOnAllEndPhases = true;
boolean stopOnStackNewObjects = true;
@ -29,20 +30,28 @@ public class UserSkipPrioritySteps implements Serializable {
return opponentTurn;
}
public boolean isStopOnDeclareBlockerIfNoneAvailable() {
return stopOnDeclareBlockerIfNoneAvailable;
public boolean isStopOnDeclareBlockersWithZeroPermanents() {
return stopOnDeclareBlockersWithZeroPermanents;
}
public void setStopOnDeclareBlockerIfNoneAvailable(boolean stopOnDeclareBlockerIfNoneAvailable) {
this.stopOnDeclareBlockerIfNoneAvailable = stopOnDeclareBlockerIfNoneAvailable;
public void setStopOnDeclareBlockersWithZeroPermanents(boolean stopOnDeclareBlockersWithZeroPermanents) {
this.stopOnDeclareBlockersWithZeroPermanents = stopOnDeclareBlockersWithZeroPermanents;
}
public boolean isStopOnDeclareAttackersDuringSkipAction() {
return stopOnDeclareAttackersDuringSkipAction;
public boolean isStopOnDeclareAttackers() {
return stopOnDeclareAttackers;
}
public void setStopOnDeclareAttackersDuringSkipActions(boolean stopOnDeclareAttackersDuringSkipActions) {
this.stopOnDeclareAttackersDuringSkipAction = stopOnDeclareAttackersDuringSkipActions;
this.stopOnDeclareAttackers = stopOnDeclareAttackersDuringSkipActions;
}
public boolean isStopOnDeclareBlockersWithAnyPermanents() {
return stopOnDeclareBlockersWithAnyPermanents;
}
public void setStopOnDeclareBlockersWithAnyPermanents(boolean stopOnDeclareBlockersWithAnyPermanents) {
this.stopOnDeclareBlockersWithAnyPermanents = stopOnDeclareBlockersWithAnyPermanents;
}
public boolean isStopOnAllMainPhases() {