mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
InputAttack appears a single time, players may click on entities they want to attack.
This commit is contained in:
@@ -17,12 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
package forge.control.input;
|
package forge.control.input;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
import forge.Card;
|
import forge.Card;
|
||||||
import forge.CardPredicates;
|
import forge.CardPredicates;
|
||||||
|
import forge.GameEntity;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
import forge.game.GameState;
|
import forge.game.GameState;
|
||||||
import forge.game.phase.CombatUtil;
|
import forge.game.phase.CombatUtil;
|
||||||
@@ -31,6 +34,7 @@ import forge.game.zone.Zone;
|
|||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gui.framework.SDisplayUtil;
|
import forge.gui.framework.SDisplayUtil;
|
||||||
import forge.gui.match.views.VMessage;
|
import forge.gui.match.views.VMessage;
|
||||||
|
import forge.util.MyObservable;
|
||||||
import forge.view.ButtonUtil;
|
import forge.view.ButtonUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +49,11 @@ public class InputAttack extends InputBase {
|
|||||||
/** Constant <code>serialVersionUID=7849903731842214245L</code>. */
|
/** Constant <code>serialVersionUID=7849903731842214245L</code>. */
|
||||||
private static final long serialVersionUID = 7849903731842214245L;
|
private static final long serialVersionUID = 7849903731842214245L;
|
||||||
|
|
||||||
|
|
||||||
private final GameState game;
|
private final GameState game;
|
||||||
|
private List<GameEntity> defenders;
|
||||||
|
private GameEntity currentDefender;
|
||||||
|
|
||||||
public InputAttack(Player human) {
|
public InputAttack(Player human) {
|
||||||
super(human);
|
super(human);
|
||||||
game = human.getGame();
|
game = human.getGame();
|
||||||
@@ -58,24 +66,22 @@ public class InputAttack extends InputBase {
|
|||||||
// TODO still seems to have some issues with multiple planeswalkers
|
// TODO still seems to have some issues with multiple planeswalkers
|
||||||
|
|
||||||
ButtonUtil.enableOnlyOk();
|
ButtonUtil.enableOnlyOk();
|
||||||
|
defenders = game.getCombat().getDefenders();
|
||||||
|
setCurrentDefender(defenders.isEmpty() ? null : defenders.get(0));
|
||||||
|
|
||||||
final Object o = game.getCombat().nextDefender();
|
if ( null == currentDefender ) {
|
||||||
if (o == null) {
|
System.err.println("InputAttack has no potential defenders!");
|
||||||
return;
|
return; // should even throw here!
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage("Declare Attackers: Select Creatures to Attack " + o.toString());
|
List<Card> possibleAttackers = player.getCardsIn(ZoneType.Battlefield);
|
||||||
|
for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) {
|
||||||
if (game.getCombat().getRemainingDefenders() == 0) { // last Target
|
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat()) ) {
|
||||||
List<Card> possibleAttackers = player.getCardsIn(ZoneType.Battlefield);
|
game.getCombat().addAttacker(c, currentDefender);
|
||||||
for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) {
|
|
||||||
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat()) && !c.isAttacking()) {
|
|
||||||
game.getCombat().addAttacker(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void selectButtonOK() {
|
public final void selectButtonOK() {
|
||||||
@@ -83,43 +89,53 @@ public class InputAttack extends InputBase {
|
|||||||
game.getPhaseHandler().setCombat();
|
game.getPhaseHandler().setCombat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.getCombat().getRemainingDefenders() != 0) {
|
setCurrentDefender(null); // remove highlights
|
||||||
game.getPhaseHandler().repeatPhase();
|
|
||||||
}
|
|
||||||
|
|
||||||
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
||||||
Singletons.getModel().getMatch().getInput().updateObservers();
|
Singletons.getModel().getMatch().getInput().updateObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectPlayer(Player selected) {
|
||||||
|
if(player.isOpponentOf(selected))
|
||||||
|
setCurrentDefender(selected);
|
||||||
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void selectCard(final Card card, boolean isMetaDown) {
|
public final void selectCard(final Card card, boolean isMetaDown) {
|
||||||
final List<Card> att = game.getCombat().getAttackers();
|
final List<Card> att = game.getCombat().getAttackers();
|
||||||
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
|
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
|
||||||
card.untap();
|
|
||||||
game.getCombat().removeFromCombat(card);
|
game.getCombat().removeFromCombat(card);
|
||||||
CombatUtil.showCombat(game);
|
CombatUtil.showCombat(game);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card.isAttacking() || card.getController() != Singletons.getControl().getPlayer()) {
|
if (card.isAttacking(currentDefender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( card.getController().isOpponentOf(player) ) {
|
||||||
|
if ( defenders.contains(card) ) { // planeswalker?
|
||||||
|
setCurrentDefender(card);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Player human = Singletons.getControl().getPlayer();
|
|
||||||
Zone zone = game.getZoneOf(card);
|
Zone zone = game.getZoneOf(card);
|
||||||
if (zone.is(ZoneType.Battlefield, human)
|
if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, game.getCombat())) {
|
||||||
&& CombatUtil.canAttack(card, game.getCombat())) {
|
|
||||||
|
|
||||||
// TODO add the propaganda code here and remove it in
|
// TODO add the propaganda code here and remove it in
|
||||||
// Phase.nextPhase()
|
// Phase.nextPhase()
|
||||||
// if (!CombatUtil.checkPropagandaEffects(card))
|
// if (!CombatUtil.checkPropagandaEffects(card))
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
game.getCombat().addAttacker(card);
|
if( game.getCombat().isAttacking(card)) {
|
||||||
|
game.getCombat().removeFromCombat(card);
|
||||||
|
}
|
||||||
|
game.getCombat().addAttacker(card, currentDefender);
|
||||||
|
|
||||||
// just to make sure the attack symbol is marked
|
// just to make sure the attack symbol is marked
|
||||||
human.getZone(ZoneType.Battlefield).updateObservers();
|
player.getZone(ZoneType.Battlefield).updateObservers();
|
||||||
CombatUtil.showCombat(game);
|
CombatUtil.showCombat(game);
|
||||||
ButtonUtil.enableOnlyOk();
|
ButtonUtil.enableOnlyOk();
|
||||||
}
|
}
|
||||||
@@ -127,4 +143,26 @@ public class InputAttack extends InputBase {
|
|||||||
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
||||||
}
|
}
|
||||||
} // selectCard()
|
} // selectCard()
|
||||||
|
|
||||||
|
private final void setCurrentDefender(GameEntity def) {
|
||||||
|
Set<MyObservable> toUpdate = new HashSet<MyObservable>();
|
||||||
|
currentDefender = def;
|
||||||
|
for( GameEntity ge: defenders ) {
|
||||||
|
if ( ge instanceof Card) {
|
||||||
|
((Card) ge).setUsedToPay(ge == def);
|
||||||
|
toUpdate.add(((Card) ge).getController().getZone(ZoneType.Battlefield));
|
||||||
|
}
|
||||||
|
else if (ge instanceof Player) {
|
||||||
|
((Player) ge).setHighlited(ge == def);
|
||||||
|
toUpdate.add(ge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessage("Declare Attackers.\nSelecting Creatures to Attack " + currentDefender + "\n\nTo attack other players or their planewalkers just click on them");
|
||||||
|
|
||||||
|
// This will instantly highlight targets
|
||||||
|
for(MyObservable updateable : toUpdate) {
|
||||||
|
updateable.updateObservers();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class Combat {
|
|||||||
private List<GameEntity> defenders = new ArrayList<GameEntity>();
|
private List<GameEntity> defenders = new ArrayList<GameEntity>();
|
||||||
private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>();
|
private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>();
|
||||||
private int currentDefender = 0;
|
private int currentDefender = 0;
|
||||||
private int nextDefender = 0;
|
|
||||||
|
|
||||||
// This Hash keeps track of
|
// This Hash keeps track of
|
||||||
private final HashMap<Card, GameEntity> attackerToDefender = new HashMap<Card, GameEntity>();
|
private final HashMap<Card, GameEntity> attackerToDefender = new HashMap<Card, GameEntity>();
|
||||||
@@ -88,7 +88,6 @@ public class Combat {
|
|||||||
|
|
||||||
this.attackingPlayer = null;
|
this.attackingPlayer = null;
|
||||||
this.currentDefender = 0;
|
this.currentDefender = 0;
|
||||||
this.nextDefender = 0;
|
|
||||||
|
|
||||||
this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents());
|
this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents());
|
||||||
}
|
}
|
||||||
@@ -126,24 +125,6 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* nextDefender.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link java.lang.Object} object.
|
|
||||||
*/
|
|
||||||
public final GameEntity nextDefender() {
|
|
||||||
if (this.nextDefender >= this.defenders.size()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentDefender = this.nextDefender;
|
|
||||||
this.nextDefender++;
|
|
||||||
|
|
||||||
return this.defenders.get(this.currentDefender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* getDefender.
|
* getDefender.
|
||||||
@@ -178,17 +159,6 @@ public class Combat {
|
|||||||
return this.currentDefender;
|
return this.currentDefender;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getRemainingDefenders.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a int.
|
|
||||||
*/
|
|
||||||
public final int getRemainingDefenders() {
|
|
||||||
return this.defenders.size() - this.nextDefender;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Getter for the field <code>defenders</code>.
|
* Getter for the field <code>defenders</code>.
|
||||||
|
|||||||
@@ -3124,4 +3124,10 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These are used by UI to mark the player currently being attacked or targeted
|
||||||
|
// Very bad practice! Someone blame on me.
|
||||||
|
private boolean highlited = false;
|
||||||
|
public final void setHighlited(boolean value) { highlited = value; }
|
||||||
|
public final boolean isHighlited() { return highlited; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import javax.swing.JLabel;
|
|||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.border.LineBorder;
|
import javax.swing.border.LineBorder;
|
||||||
import javax.swing.border.MatteBorder;
|
import javax.swing.border.MatteBorder;
|
||||||
|
|
||||||
@@ -105,6 +106,11 @@ public class VField implements IVDoc<CField> {
|
|||||||
private PhaseLabel lblEndTurn = new PhaseLabel("ET");
|
private PhaseLabel lblEndTurn = new PhaseLabel("ET");
|
||||||
private PhaseLabel lblCleanup = new PhaseLabel("CL");
|
private PhaseLabel lblCleanup = new PhaseLabel("CL");
|
||||||
|
|
||||||
|
private final Border borderAvatarSimple = new LineBorder(new Color(0, 0, 0, 0), 1);
|
||||||
|
private final Border borderAvatarHover = new LineBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS), 1);
|
||||||
|
private final Border borderAvatarHighlited = new LineBorder(Color.red, 2);
|
||||||
|
|
||||||
|
|
||||||
//========= Constructor
|
//========= Constructor
|
||||||
/**
|
/**
|
||||||
* Assembles Swing components of a player field instance.
|
* Assembles Swing components of a player field instance.
|
||||||
@@ -144,13 +150,15 @@ public class VField implements IVDoc<CField> {
|
|||||||
@Override
|
@Override
|
||||||
public void mouseEntered(final MouseEvent e) {
|
public void mouseEntered(final MouseEvent e) {
|
||||||
avatarArea.setOpaque(true);
|
avatarArea.setOpaque(true);
|
||||||
avatarArea.setBorder(new LineBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS), 1));
|
if (!player.isHighlited())
|
||||||
|
avatarArea.setBorder(borderAvatarHover);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseExited(final MouseEvent e) {
|
public void mouseExited(final MouseEvent e) {
|
||||||
avatarArea.setOpaque(false);
|
avatarArea.setOpaque(false);
|
||||||
avatarArea.setBorder(new LineBorder(new Color(0, 0, 0, 0), 1));
|
if (!player.isHighlited())
|
||||||
|
avatarArea.setBorder(borderAvatarSimple);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -359,19 +367,14 @@ public class VField implements IVDoc<CField> {
|
|||||||
this.getLblLife().setText("" + p0.getLife());
|
this.getLblLife().setText("" + p0.getLife());
|
||||||
this.getLblPoison().setText("" + p0.getPoisonCounters());
|
this.getLblPoison().setText("" + p0.getPoisonCounters());
|
||||||
|
|
||||||
if (p0.getLife() <= 5) {
|
Color lifeFg = p0.getLife() <= 5 ? Color.red : FSkin.getColor(FSkin.Colors.CLR_TEXT);
|
||||||
this.getLblLife().setForeground(Color.red);
|
this.getLblLife().setForeground(lifeFg);
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.getLblLife().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p0.getPoisonCounters() >= 8) {
|
Color poisonFg = p0.getPoisonCounters() >= 8 ? Color.red : FSkin.getColor(FSkin.Colors.CLR_TEXT);
|
||||||
this.getLblPoison().setForeground(Color.red);
|
this.getLblPoison().setForeground(poisonFg);
|
||||||
}
|
|
||||||
else {
|
this.avatarArea.setBorder(p0.isHighlited() ? borderAvatarHighlited : borderAvatarSimple );
|
||||||
this.getLblPoison().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
|
this.avatarArea.setOpaque(p0.isHighlited());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user