CField: click with meta key down is handled by the very input class. (a parameter added to selectCard)

VCombat: !parentCell.getSelected() won't NPE any longer (unless if parentCell is null for that thread), moved most thread-unsafe actions from update() to ctor and populate
PhaseHandler: bCombat is AtomicBoolean to be retrieved correctly from any thread.
This commit is contained in:
Maxmtg
2013-04-20 07:41:20 +00:00
parent 609164d7c5
commit 75384b78e3
19 changed files with 89 additions and 119 deletions

View File

@@ -12,7 +12,7 @@ public interface Input {
// showMessage() is always the first method called
void showMessage();
void selectCard(Card c);
void selectCard(Card c, boolean isMetaDown);
void selectPlayer(Player player);

View File

@@ -80,7 +80,7 @@ public class InputAttack extends InputBase {
@Override
public final void selectButtonOK() {
if (!game.getCombat().getAttackers().isEmpty()) {
game.getPhaseHandler().setCombat(true);
game.getPhaseHandler().setCombat();
}
if (game.getCombat().getRemainingDefenders() != 0) {
@@ -93,7 +93,15 @@ public class InputAttack extends InputBase {
/** {@inheritDoc} */
@Override
public final void selectCard(final Card card) {
public final void selectCard(final Card card, boolean isMetaDown) {
final List<Card> att = game.getCombat().getAttackers();
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
card.untap();
game.getCombat().removeFromCombat(card);
CombatUtil.showCombat(game);
return;
}
if (card.isAttacking() || card.getController() != Singletons.getControl().getPlayer()) {
return;
}
@@ -112,7 +120,7 @@ public class InputAttack extends InputBase {
// just to make sure the attack symbol is marked
human.getZone(ZoneType.Battlefield).updateObservers();
CombatUtil.showCombat();
CombatUtil.showCombat(game);
ButtonUtil.enableOnlyOk();
}
else {

View File

@@ -44,7 +44,7 @@ public abstract class InputBase implements java.io.Serializable, Input {
public abstract void showMessage();
@Override
public void selectCard(final Card c) { }
public void selectCard(final Card c, boolean isMetaDown) { }
@Override
public void selectPlayer(final Player player) { }
@Override

View File

@@ -47,24 +47,18 @@ public class InputBlock extends InputBase {
private Card currentAttacker = null;
private final HashMap<Card, List<Card>> allBlocking = new HashMap<Card, List<Card>>();
private final GameState game;
/**
* TODO: Write javadoc for Constructor.
* @param priority
*/
public InputBlock(Player human) {
public InputBlock(Player human, GameState game) {
super(human);
this.game = game;
}
/**
* <p>
* removeFromAllBlocking.
* </p>
*
* @param c
* a {@link forge.Card} object.
*/
public final void removeFromAllBlocking(final Card c) {
private final void removeFromAllBlocking(final Card c) {
this.allBlocking.remove(c);
}
@@ -89,17 +83,16 @@ public class InputBlock extends InputBase {
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
}
CombatUtil.showCombat();
CombatUtil.showCombat(game);
}
/** {@inheritDoc} */
@Override
public final void selectButtonOK() {
final GameState game = Singletons.getModel().getGame();
if (CombatUtil.finishedMandatoryBlocks(game.getCombat(), player)) {
// Done blocking
ButtonUtil.reset();
CombatUtil.orderMultipleCombatants(game.getCombat());
CombatUtil.orderMultipleCombatants(game);
currentAttacker = null;
allBlocking.clear();
@@ -109,11 +102,22 @@ public class InputBlock extends InputBase {
/** {@inheritDoc} */
@Override
public final void selectCard(final Card card) {
public final void selectCard(final Card card, boolean isMetaDown) {
if (isMetaDown) {
if (card.getController() == Singletons.getControl().getPlayer() ) {
game.getCombat().removeFromCombat(card);
}
removeFromAllBlocking(card);
CombatUtil.showCombat(game);
return;
}
// is attacking?
boolean reminder = true;
if (Singletons.getModel().getGame().getCombat().getAttackers().contains(card)) {
if (game.getCombat().getAttackers().contains(card)) {
this.currentAttacker = card;
reminder = false;
} else {

View File

@@ -73,7 +73,7 @@ public class InputCleanup extends InputBase {
/** {@inheritDoc} */
@Override
public final void selectCard(final Card card) {
public final void selectCard(final Card card, boolean isMetaDown) {
Zone zone = game.getZoneOf(card);
if (!zone.is(ZoneType.Hand, Singletons.getControl().getPlayer()))
return;

View File

@@ -58,7 +58,7 @@ public class InputLockUI implements Input {
CMatchUI.SINGLETON_INSTANCE.showMessage(message);
}
@Override public void selectCard(Card c) {}
@Override public void selectCard(Card c, boolean isMetaDown) {}
@Override public void selectPlayer(Player player) {}
@Override public void selectButtonOK() {}
@Override public void selectButtonCancel() {}

View File

@@ -129,7 +129,7 @@ public class InputMulligan extends InputBase {
}
@Override
public void selectCard(Card c0) {
public void selectCard(Card c0, boolean isMetaDown) {
Zone z0 = match.getCurrentGame().getZoneOf(c0);
if (c0.getName().equals("Serum Powder") && z0.is(ZoneType.Hand)) {
if (GuiDialog.confirm(c0, "Use " + c0.getName() + "'s ability?")) {

View File

@@ -181,7 +181,7 @@ public class InputPartialParisMulligan extends InputBase {
}
@Override
public void selectCard(Card c0) {
public void selectCard(Card c0, boolean isMetaDown) {
if(lastExiled.contains(c0))
{
lastExiled.remove(c0);

View File

@@ -80,7 +80,7 @@ public class InputPassPriority extends InputBase {
/** {@inheritDoc} */
@Override
public final void selectCard(final Card card) {
public final void selectCard(final Card card, boolean isMetaDown) {
final SpellAbility ab = player.getController().getAbilityToPlay(player.getGame().getAbilitesOfCard(card, player));
if ( null != ab) {
Runnable execAbility = new Runnable() {

View File

@@ -48,7 +48,7 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn
}
@Override
public final void selectCard(Card c) {
public final void selectCard(Card c, boolean isMetaDown) {
if( finished ) return;
onCardSelected(c);
}

View File

@@ -828,7 +828,7 @@ public class AiController {
final List<Card> att = game.getCombat().getAttackers();
if (!att.isEmpty()) {
game.getPhaseHandler().setCombat(true);
game.getPhaseHandler().setCombat();
}
for (final Card element : att) {

View File

@@ -32,7 +32,7 @@ public class AiInputBlock extends InputBase {
// TODO Auto-generated method stub
final List<Card> blockers = player.getCreaturesInPlay();
game.setCombat(ComputerUtilBlock.getBlockers(player, game.getCombat(), blockers));
CombatUtil.orderMultipleCombatants(game.getCombat());
CombatUtil.orderMultipleCombatants(game);
game.getPhaseHandler().setPlayersPriorityPermission(false);
// was not added to stack, so will be replaced by plain update

View File

@@ -425,16 +425,20 @@ public class CombatUtil {
return true;
}
public static void orderMultipleCombatants(final Combat combat) {
public static void orderMultipleCombatants(final GameState game) {
final Combat combat = game.getCombat();
CombatUtil.orderMultipleBlockers(combat);
CombatUtil.showCombat(game);
CombatUtil.orderBlockingMultipleAttackers(combat);
CombatUtil.showCombat(game);
}
private static void orderMultipleBlockers(final Combat combat) {
// If there are multiple blockers, the Attacker declares the Assignment Order
final Player player = combat.getAttackingPlayer();
final List<Card> attackers = combat.getAttackers();
for (final Card attacker : attackers) {
for (final Card attacker : combat.getAttackers()) {
List<Card> blockers = combat.getBlockers(attacker);
if (blockers.size() <= 1) {
continue;
@@ -442,7 +446,7 @@ public class CombatUtil {
List<Card> orderedBlockers = player.getController().orderBlockers(attacker, blockers);
combat.setBlockerList(attacker, orderedBlockers);
}
CombatUtil.showCombat();
// Refresh Combat Panel
}
@@ -457,7 +461,6 @@ public class CombatUtil {
List<Card> orderedAttacker = blocker.getController().getController().orderAttackers(blocker, attackers);
combat.setAttackersBlockedByList(blocker, orderedAttacker);
}
CombatUtil.showCombat();
// Refresh Combat Panel
}
@@ -1081,11 +1084,11 @@ public class CombatUtil {
* showCombat.
* </p>
*/
public static void showCombat() {
public static void showCombat(GameState game) {
// TODO(sol) ShowCombat seems to be resetting itself when switching away and switching back?
String text = "";
if (Singletons.getModel().getGame().getPhaseHandler().inCombat()) {
text = getCombatDescription(Singletons.getModel().getGame().getCombat());
if (game.getPhaseHandler().inCombat()) {
text = getCombatDescription(game.getCombat());
SDisplayUtil.showTab(EDocID.REPORT_COMBAT.getDoc());
}
VCombat.SINGLETON_INSTANCE.updateCombat(text);

View File

@@ -20,6 +20,7 @@ package forge.game.phase;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicBoolean;
import com.esotericsoftware.minlog.Log;
@@ -71,7 +72,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
private Player pPlayerPriority = null;
private Player pFirstPriority = null;
private boolean bPhaseEffects = true;
private boolean bCombat = false;
private AtomicBoolean bCombat = new AtomicBoolean(false);
private boolean bRepeat = false;
/** The need to next phase. */
@@ -203,7 +204,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
* @return a boolean.
*/
public final boolean inCombat() {
return this.bCombat;
return this.bCombat.get();
}
/**
@@ -214,8 +215,8 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
* @param b
* a boolean.
*/
public final void setCombat(final boolean b) {
this.bCombat = b;
public final void setCombat() {
this.bCombat.set(true);
}
/**
@@ -293,7 +294,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY:
if (this.inCombat()) {
PhaseUtil.handleDeclareAttackers(game);
CombatUtil.showCombat();
CombatUtil.showCombat(game);
} else {
this.setPlayersPriorityPermission(false);
}
@@ -302,7 +303,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
case COMBAT_DECLARE_BLOCKERS:
if (this.inCombat()) {
game.getCombat().verifyCreaturesInPlay();
CombatUtil.showCombat();
CombatUtil.showCombat(game);
} else {
this.setPlayersPriorityPermission(false);
}
@@ -313,7 +314,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
// blocked and trigger blocking things
if (this.inCombat()) {
PhaseUtil.handleDeclareBlockers(game);
CombatUtil.showCombat();
CombatUtil.showCombat(game);
} else {
this.setPlayersPriorityPermission(false);
}
@@ -331,7 +332,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
} else {
game.getCombat().dealAssignedDamage();
game.getAction().checkStateEffects();
CombatUtil.showCombat();
CombatUtil.showCombat(game);
}
}
break;
@@ -347,7 +348,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
} else {
game.getCombat().dealAssignedDamage();
game.getAction().checkStateEffects();
CombatUtil.showCombat();
CombatUtil.showCombat(game);
}
}
break;
@@ -356,12 +357,12 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
// End Combat always happens
game.getEndOfCombat().executeUntil();
game.getEndOfCombat().executeAt();
CombatUtil.showCombat();
CombatUtil.showCombat(game);
//SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
break;
case MAIN2:
CombatUtil.showCombat();
CombatUtil.showCombat(game);
//SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
break;
@@ -462,7 +463,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
//SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
game.getCombat().reset();
this.getPlayerTurn().resetAttackedThisCombat();
this.bCombat = false;
this.bCombat.set(false);
break;

View File

@@ -60,7 +60,7 @@ public class PlayerControllerHuman extends PlayerController {
player = p;
defaultInput = new InputPassPriority(player);
blockInput = new InputBlock(getPlayer());
blockInput = new InputBlock(getPlayer(), game0);
cleanupInput = new InputCleanup(getPlayer());
autoPassPriorityInput = new InputAutoPassPriority(getPlayer());
}

View File

@@ -4,9 +4,6 @@ import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -80,10 +77,7 @@ public enum FNetOverlay {
// pnl.add(new FLabel.Builder().text("Loading new game...").fontSize(22).build(), "h 40px!, align center");
// Block all input events below the overlay
pnl.addMouseListener(new MouseAdapter() { });
pnl.addMouseMotionListener(new MouseMotionAdapter() { });
pnl.addKeyListener(new KeyAdapter() { });
txtLog.setOpaque(true);
txtLog.setFocusable(true);
txtLog.setBackground(FSkin.getColor(FSkin.Colors.CLR_ZEBRA));

View File

@@ -138,7 +138,7 @@ public class InputProxy implements Observer {
public final void selectCard(final Card card) {
Input inp = getInput();
if ( null != inp )
inp.selectCard(card);
inp.selectCard(card, false);
}
/** {@inheritDoc} */

View File

@@ -40,11 +40,8 @@ import forge.card.cardfactory.CardFactory;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.SpellAbility;
import forge.control.input.Input;
import forge.control.input.InputAttack;
import forge.control.input.InputBlock;
import forge.control.input.InputPayManaBase;
import forge.game.GameState;
import forge.game.phase.CombatUtil;
import forge.game.player.HumanPlayer;
import forge.game.player.Player;
import forge.game.zone.PlayerZone;
@@ -56,7 +53,6 @@ import forge.gui.framework.ICDoc;
import forge.gui.match.CMatchUI;
import forge.gui.match.controllers.CMessage;
import forge.gui.toolbox.FLabel;
import forge.view.arcane.CardPanel;
/**
* Controls Swing components of a player's field instance.
@@ -397,48 +393,13 @@ public class CField implements ICDoc {
if (c == null || !c.isInZone(ZoneType.Battlefield)) {
return;
}
// Why does CField filter cards here? That's Input's responsibility to detect incorrect choices!
if (c.isTapped() && input instanceof InputPayManaBase) {
final CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(c.getUniqueNumber());
for (final CardPanel cp : cardPanel.getAttachedPanels()) {
if (cp.getCard().isUntapped()) {
break;
}
}
}
final List<Card> att = Singletons.getModel().getGame().getCombat().getAttackers();
if ((c.isTapped() || c.hasSickness() || (c.hasKeyword("Vigilance") && att.contains(c))) && (input instanceof InputAttack)) {
final CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(c.getUniqueNumber());
for (final CardPanel cp : cardPanel.getAttachedPanels()) {
if (cp.getCard().isUntapped() && !cp.getCard().hasSickness()) {
break;
}
}
}
if (e.isMetaDown()) {
if (att.contains(c) && input instanceof InputAttack && !c.hasKeyword("CARDNAME attacks each turn if able.")) {
c.untap();
Singletons.getModel().getGame().getCombat().removeFromCombat(c);
CombatUtil.showCombat();
} else if (input instanceof InputBlock) {
if (c.getController() == Singletons.getControl().getPlayer() ) {
Singletons.getModel().getGame().getCombat().removeFromCombat(c);
}
((InputBlock) input).removeFromAllBlocking(c);
CombatUtil.showCombat();
}
} else if ( input != null ){
//Yosei, the Morning Star required cards to be chosen on computer side
//earlier it was enforced that cards must be in player zone
//this can potentially break some other functionality
//(tapping lands works ok but some custom cards may not...)
//in weird case card has no controller revert to default behaviour
input.selectCard(c);
//Yosei, the Morning Star required cards to be chosen on computer side
//earlier it was enforced that cards must be in player zone
//this can potentially break some other functionality
//(tapping lands works ok but some custom cards may not...)
if ( input != null ){
input.selectCard(c, e.isMetaDown());
}
}

View File

@@ -18,7 +18,6 @@
package forge.gui.match.views;
import javax.swing.JTextArea;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
import net.miginfocom.swing.MigLayout;
@@ -42,7 +41,17 @@ public enum VCombat implements IVDoc<CCombat> {
// Fields used with interface IVDoc
private DragCell parentCell;
private final DragTab tab = new DragTab("Combat");
final JTextArea tar = new JTextArea();
private VCombat() {
tar.setOpaque(false);
tar.setBorder(new MatteBorder(0, 0, 0, 0, FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tar.setFocusable(false);
tar.setLineWrap(true);
}
//========== Overridden methods
/* (non-Javadoc)
@@ -50,7 +59,9 @@ public enum VCombat implements IVDoc<CCombat> {
*/
@Override
public void populate() {
// (Panel uses observers to update, no permanent components here.)
parentCell.getBody().removeAll();
parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0, wrap"));
parentCell.getBody().add(tar, "w 95%!, gapleft 3%, gaptop 1%, h 95%");
}
/* (non-Javadoc)
@@ -98,21 +109,9 @@ public enum VCombat implements IVDoc<CCombat> {
/** @param s0 &emsp; {@link java.lang.String} */
public void updateCombat(final String s0) {
// No need to update this unless it's showing
if (!parentCell.getSelected().equals(this)) { return; }
parentCell.getBody().removeAll();
parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0, wrap"));
final Border border = new MatteBorder(0, 0, 0, 0, FSkin.getColor(FSkin.Colors.CLR_BORDERS));
if (!this.equals(parentCell.getSelected())) { return; }
tab.setText("Combat : " + Singletons.getModel().getGame().getCombat().getAttackers().size());
final JTextArea tar = new JTextArea(s0);
tar.setOpaque(false);
tar.setBorder(border);
tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tar.setFocusable(false);
tar.setLineWrap(true);
parentCell.getBody().add(tar, "w 95%!, gapleft 3%, gaptop 1%, h 95%");
tar.setText(s0);
}
}