mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Rewrite of VAssignDamage (I need a damage map from this class [View must not apply damage by itself] but the code shocked me, so rewrote it first)
This commit is contained in:
@@ -272,4 +272,12 @@ public class MatchController {
|
|||||||
public final InputControl getInput() {
|
public final InputControl getInput() {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int getPoisonCountersAmountToLose() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ import java.awt.event.ActionListener;
|
|||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -35,8 +36,11 @@ import javax.swing.border.LineBorder;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import forge.Card;
|
import forge.Card;
|
||||||
|
import forge.CounterType;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
|
import forge.game.MatchController;
|
||||||
|
import forge.game.player.Player;
|
||||||
import forge.gui.SOverlayUtils;
|
import forge.gui.SOverlayUtils;
|
||||||
import forge.gui.toolbox.FButton;
|
import forge.gui.toolbox.FButton;
|
||||||
import forge.gui.toolbox.FLabel;
|
import forge.gui.toolbox.FLabel;
|
||||||
@@ -61,13 +65,13 @@ public class VAssignDamage {
|
|||||||
|
|
||||||
// Damage storage
|
// Damage storage
|
||||||
private final int totalDamageToAssign;
|
private final int totalDamageToAssign;
|
||||||
private int damageLeftToAssign;
|
|
||||||
private boolean deathtouch = false;
|
|
||||||
private boolean trample = false;
|
|
||||||
private int damageToOpponent = 0;
|
|
||||||
private final Card attacker;
|
private final Card attacker;
|
||||||
|
private boolean attackerHasDeathtouch = false;
|
||||||
|
private boolean attackerHasTrample = false;
|
||||||
|
private boolean attackerHasInfect = false;
|
||||||
|
|
||||||
private final GameEntity defender;
|
private final GameEntity defender;
|
||||||
private Integer activeIndex = 0;
|
|
||||||
|
|
||||||
private final JLabel lblTotalDamage = new FLabel.Builder().text("Available damage points: Unknown").build();
|
private final JLabel lblTotalDamage = new FLabel.Builder().text("Available damage points: Unknown").build();
|
||||||
|
|
||||||
@@ -76,50 +80,29 @@ public class VAssignDamage {
|
|||||||
private final FButton btnReset = new FButton("Reset");
|
private final FButton btnReset = new FButton("Reset");
|
||||||
private final FButton btnAuto = new FButton("Auto");
|
private final FButton btnAuto = new FButton("Auto");
|
||||||
|
|
||||||
|
|
||||||
|
private static class DamageTarget {
|
||||||
|
public final Card card;
|
||||||
|
public final JLabel label;
|
||||||
|
public int damage;
|
||||||
|
|
||||||
|
public DamageTarget(Card entity0, JLabel lbl) {
|
||||||
|
card = entity0;
|
||||||
|
label = lbl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Indexes of defenders correspond to their indexes in the damage list and labels.
|
// Indexes of defenders correspond to their indexes in the damage list and labels.
|
||||||
private final List<Card> lstDefenders = new ArrayList<Card>();
|
private final List<DamageTarget> defenders = new ArrayList<DamageTarget>(); // NULL in this map means defender
|
||||||
private final List<Integer> lstDamage = new ArrayList<Integer>();
|
private final Map<Card, DamageTarget> damage = new HashMap<Card, DamageTarget>(); // NULL in this map means defender
|
||||||
private final List<JLabel> lstDamageLabels = new ArrayList<JLabel>();
|
|
||||||
|
|
||||||
private boolean canAssignToIndex(Integer selectedIndex) {
|
private boolean canAssignTo(Card card) {
|
||||||
Integer active = this.activeIndex;
|
for(DamageTarget dt : defenders) {
|
||||||
|
if ( dt.card == card ) return true;
|
||||||
if (selectedIndex == null) {
|
if ( getDamageToKill(dt.card) > dt.damage )
|
||||||
// Trying to assign to the opponent
|
|
||||||
if (active == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active != this.lstDamage.size() - 1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
throw new RuntimeException("Asking to assign damage to object which is not present in defenders list");
|
||||||
int activeLethal = this.deathtouch ? 1 : lstDefenders.get(active).getLethalDamage();
|
|
||||||
int assignedToActive = lstDamage.get(active);
|
|
||||||
|
|
||||||
if (assignedToActive < activeLethal) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Trying to assign to a combatant
|
|
||||||
if (active == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active.equals(selectedIndex)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int activeLethal = this.deathtouch ? 1 : lstDefenders.get(active).getLethalDamage();
|
|
||||||
int assignedToActive = lstDamage.get(active);
|
|
||||||
|
|
||||||
if (active != selectedIndex - 1 || assignedToActive < activeLethal) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mouse actions
|
// Mouse actions
|
||||||
@@ -127,11 +110,10 @@ public class VAssignDamage {
|
|||||||
@Override
|
@Override
|
||||||
public void mouseEntered(final MouseEvent evt) {
|
public void mouseEntered(final MouseEvent evt) {
|
||||||
Card source = ((CardPanel) evt.getSource()).getCard();
|
Card source = ((CardPanel) evt.getSource()).getCard();
|
||||||
int index = lstDefenders.indexOf(source);
|
if (!damage.containsKey(source))
|
||||||
FSkin.Colors brdrColor = FSkin.Colors.CLR_INACTIVE;
|
source = null;
|
||||||
if (VAssignDamage.this.canAssignToIndex(index)) {
|
|
||||||
brdrColor = FSkin.Colors.CLR_ACTIVE;
|
FSkin.Colors brdrColor = VAssignDamage.this.canAssignTo(source) ? FSkin.Colors.CLR_ACTIVE : FSkin.Colors.CLR_INACTIVE;
|
||||||
}
|
|
||||||
((CardPanel) evt.getSource()).setBorder(new LineBorder(FSkin.getColor(brdrColor), 2));
|
((CardPanel) evt.getSource()).setBorder(new LineBorder(FSkin.getColor(brdrColor), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,106 +124,14 @@ public class VAssignDamage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(final MouseEvent evt) {
|
public void mousePressed(final MouseEvent evt) {
|
||||||
Card source = ((CardPanel) evt.getSource()).getCard();
|
Card source = ((CardPanel) evt.getSource()).getCard(); // will be NULL for player
|
||||||
int index = lstDefenders.indexOf(source);
|
|
||||||
|
|
||||||
// Allow click if this is active, or next to active and active has lethal
|
|
||||||
if (!VAssignDamage.this.canAssignToIndex(index)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean meta = evt.isControlDown();
|
boolean meta = evt.isControlDown();
|
||||||
int alreadyAssignDamage = lstDamage.get(index);
|
boolean isLMB = SwingUtilities.isLeftMouseButton(evt);
|
||||||
// If lethal damage has already been assigned just act like it's 0.
|
boolean isRMB = SwingUtilities.isRightMouseButton(evt);
|
||||||
int lethal = VAssignDamage.this.deathtouch ? 1 : Math.max(0, source.getLethalDamage());
|
|
||||||
int assignedDamage = 1;
|
|
||||||
|
|
||||||
// Add damage for left clicks, as much as we can for ctrl clicking
|
if ( isLMB || isRMB)
|
||||||
if (SwingUtilities.isLeftMouseButton(evt)) {
|
assignDamageTo(source, meta, isLMB);
|
||||||
if (meta) {
|
|
||||||
assignedDamage = VAssignDamage.this.damageLeftToAssign;
|
|
||||||
}
|
|
||||||
else if (alreadyAssignDamage == 0) {
|
|
||||||
assignedDamage = Math.min(lethal, VAssignDamage.this.damageLeftToAssign);
|
|
||||||
}
|
|
||||||
|
|
||||||
assignCombatantDamage(source, assignedDamage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove damage for right clicks, as much as we can for ctrl clicking
|
|
||||||
else if (SwingUtilities.isRightMouseButton(evt)) {
|
|
||||||
if (meta) {
|
|
||||||
if (index == 0) {
|
|
||||||
assignedDamage = lethal - alreadyAssignDamage;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assignedDamage = -alreadyAssignDamage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (alreadyAssignDamage == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (alreadyAssignDamage == lethal) {
|
|
||||||
if (index == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assignedDamage = -lethal;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assignedDamage = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assignCombatantDamage(source, assignedDamage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final MouseAdapter madOpponent = new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(final MouseEvent evt) {
|
|
||||||
FSkin.Colors brdrColor = FSkin.Colors.CLR_INACTIVE;
|
|
||||||
if (VAssignDamage.this.canAssignToIndex(null)) {
|
|
||||||
brdrColor = FSkin.Colors.CLR_ACTIVE;
|
|
||||||
}
|
|
||||||
((CardPanel) evt.getSource()).setBorder(new LineBorder(FSkin.getColor(brdrColor), 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(final MouseEvent evt) {
|
|
||||||
((CardPanel) evt.getSource()).setBorder(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mousePressed(final MouseEvent evt) {
|
|
||||||
if (!VAssignDamage.this.canAssignToIndex(null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int assignedDamage = 0;
|
|
||||||
boolean meta = evt.isControlDown();
|
|
||||||
if (SwingUtilities.isLeftMouseButton(evt)) {
|
|
||||||
if (meta) {
|
|
||||||
assignedDamage = VAssignDamage.this.damageLeftToAssign;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assignedDamage = 1;
|
|
||||||
}
|
|
||||||
assignOpponentDamage(assignedDamage);
|
|
||||||
}
|
|
||||||
else if (SwingUtilities.isRightMouseButton(evt)) {
|
|
||||||
int alreadyAssignDamage = VAssignDamage.this.damageToOpponent;
|
|
||||||
if (meta) {
|
|
||||||
assignedDamage = -alreadyAssignDamage;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (alreadyAssignDamage == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assignedDamage = -1;
|
|
||||||
}
|
|
||||||
assignOpponentDamage(assignedDamage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -252,21 +142,15 @@ public class VAssignDamage {
|
|||||||
* @param damage0 int
|
* @param damage0 int
|
||||||
* @param defender GameEntity that's bein attacked
|
* @param defender GameEntity that's bein attacked
|
||||||
*/
|
*/
|
||||||
public VAssignDamage(final Card attacker0, final List<Card> defenders0, final int damage0, final GameEntity defender) {
|
public VAssignDamage(final Card attacker0, final List<Card> defenderCards, final int damage0, final GameEntity defender) {
|
||||||
// Set damage storage vars
|
// Set damage storage vars
|
||||||
this.totalDamageToAssign = damage0;
|
this.totalDamageToAssign = damage0;
|
||||||
this.damageLeftToAssign = damage0;
|
|
||||||
this.defender = defender;
|
this.defender = defender;
|
||||||
this.deathtouch = attacker0.hasKeyword("Deathtouch");
|
this.attackerHasDeathtouch = attacker0.hasKeyword("Deathtouch");
|
||||||
this.trample = defender != null && attacker0.hasKeyword("Trample");
|
this.attackerHasInfect = attacker0.hasKeyword("Infect");
|
||||||
|
this.attackerHasTrample = defender != null && attacker0.hasKeyword("Trample");
|
||||||
this.attacker = attacker0;
|
this.attacker = attacker0;
|
||||||
|
|
||||||
for (final Card c : defenders0) {
|
|
||||||
this.lstDefenders.add(c);
|
|
||||||
this.lstDamage.add(0);
|
|
||||||
this.lstDamageLabels.add(new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-level UI stuff
|
// Top-level UI stuff
|
||||||
final JPanel overlay = SOverlayUtils.genericOverlay();
|
final JPanel overlay = SOverlayUtils.genericOverlay();
|
||||||
final JPanel pnlMain = new JPanel();
|
final JPanel pnlMain = new JPanel();
|
||||||
@@ -280,50 +164,46 @@ public class VAssignDamage {
|
|||||||
final JPanel pnlInfo = new JPanel(new MigLayout("insets 0, gap 0, wrap"));
|
final JPanel pnlInfo = new JPanel(new MigLayout("insets 0, gap 0, wrap"));
|
||||||
pnlInfo.setOpaque(false);
|
pnlInfo.setOpaque(false);
|
||||||
pnlInfo.add(lblTotalDamage, "gap 0 0 20px 5px");
|
pnlInfo.add(lblTotalDamage, "gap 0 0 20px 5px");
|
||||||
pnlInfo.add(new FLabel.Builder().text("Left click: Assign 1 damage. (Left Click + Control): Assign remaining damage").build(), "gap 0 0 0 5px");
|
pnlInfo.add(new FLabel.Builder().text("Left click: Assign 1 damage. (Left Click + Control): Assign remaining damage up to lethal").build(), "gap 0 0 0 5px");
|
||||||
pnlInfo.add(new FLabel.Builder().text("Right click: Unassign 1 damage. (Right Click + Control): Unassign all damage.").build(), "gap 0 0 0 5px");
|
pnlInfo.add(new FLabel.Builder().text("Right click: Unassign 1 damage. (Right Click + Control): Unassign all damage.").build(), "gap 0 0 0 5px");
|
||||||
|
|
||||||
// Defenders area
|
// Defenders area
|
||||||
final JPanel pnlDefenders = new JPanel();
|
final JPanel pnlDefenders = new JPanel();
|
||||||
pnlDefenders.setOpaque(false);
|
pnlDefenders.setOpaque(false);
|
||||||
final String wrap = (trample ? "wrap " + (lstDefenders.size() + 1) : "wrap " + lstDefenders.size());
|
final String wrap = "wrap " + (attackerHasTrample ? defenderCards.size() + 1 : defenderCards.size());
|
||||||
pnlDefenders.setLayout(new MigLayout("insets 0, gap 0, ax center, " + wrap));
|
pnlDefenders.setLayout(new MigLayout("insets 0, gap 0, ax center, " + wrap));
|
||||||
|
|
||||||
final FScrollPane scrDefenders = new FScrollPane(pnlDefenders);
|
final FScrollPane scrDefenders = new FScrollPane(pnlDefenders);
|
||||||
scrDefenders.setBorder(null);
|
scrDefenders.setBorder(null);
|
||||||
|
|
||||||
// Top row of cards...
|
// Top row of cards...
|
||||||
for (final Card c : lstDefenders) {
|
for (final Card c : defenderCards) {
|
||||||
final CardPanel cp = new CardPanel(c);
|
DamageTarget dt = new DamageTarget(c, new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build());
|
||||||
cp.setCardBounds(0, 0, 105, 150);
|
this.damage.put(c, dt);
|
||||||
cp.setOpaque(true);
|
this.defenders.add(dt);
|
||||||
pnlDefenders.add(cp, "w 145px!, h 170px!, gap 5px 5px 3px 3px, ax center");
|
addPanelForDefender(pnlDefenders, c);
|
||||||
cp.addMouseListener(madDefender);
|
}
|
||||||
|
|
||||||
|
if (attackerHasTrample) {
|
||||||
|
DamageTarget dt = new DamageTarget(null, new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build());
|
||||||
|
this.damage.put(null, dt);
|
||||||
|
this.defenders.add(dt);
|
||||||
|
Card fakeCard;
|
||||||
|
if( defender instanceof Card )
|
||||||
|
fakeCard = (Card)defender;
|
||||||
|
else {
|
||||||
|
fakeCard = new Card();
|
||||||
|
fakeCard.setName(this.defender.getName());
|
||||||
|
}
|
||||||
|
addPanelForDefender(pnlDefenders, fakeCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add "opponent placeholder" card if trample allowed
|
// Add "opponent placeholder" card if trample allowed
|
||||||
// If trample allowed, make card placeholder
|
// If trample allowed, make card placeholder
|
||||||
if (trample) {
|
|
||||||
CardPanel defPanel;
|
|
||||||
if (this.defender instanceof Card) {
|
|
||||||
defPanel = new CardPanel((Card) this.defender);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Card crdOpponentPlaceholder = new Card();
|
|
||||||
crdOpponentPlaceholder.setName(this.defender.getName());
|
|
||||||
defPanel = new CardPanel(crdOpponentPlaceholder);
|
|
||||||
}
|
|
||||||
|
|
||||||
defPanel.setCardBounds(0, 0, 105, 150);
|
|
||||||
defPanel.addMouseListener(madOpponent);
|
|
||||||
defPanel.setOpaque(true);
|
|
||||||
pnlDefenders.add(defPanel, "w 145px!, h 170px!, gap 5px 5px 3px 3px, ax center");
|
|
||||||
lstDamageLabels.add(new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... bottom row of labels.
|
// ... bottom row of labels.
|
||||||
for (int i = 0; i < lstDamageLabels.size(); i++) {
|
for (DamageTarget l : defenders) {
|
||||||
pnlDefenders.add(lstDamageLabels.get(i), "w 145px!, h 30px!, gap 5px 5px 0 5px");
|
pnlDefenders.add(l.label, "w 145px!, h 30px!, gap 5px 5px 0 5px");
|
||||||
}
|
}
|
||||||
|
|
||||||
btnOK.addActionListener(new ActionListener() {
|
btnOK.addActionListener(new ActionListener() {
|
||||||
@@ -331,7 +211,7 @@ public class VAssignDamage {
|
|||||||
btnReset.addActionListener(new ActionListener() {
|
btnReset.addActionListener(new ActionListener() {
|
||||||
@Override public void actionPerformed(ActionEvent arg0) { resetAssignDamage(); } });
|
@Override public void actionPerformed(ActionEvent arg0) { resetAssignDamage(); } });
|
||||||
btnAuto.addActionListener(new ActionListener() {
|
btnAuto.addActionListener(new ActionListener() {
|
||||||
@Override public void actionPerformed(ActionEvent arg0) { autoAssignDamage(); } });
|
@Override public void actionPerformed(ActionEvent arg0) { resetAssignDamage(); finish(); } });
|
||||||
|
|
||||||
// Final UI layout
|
// Final UI layout
|
||||||
pnlMain.setLayout(new MigLayout("insets 0, gap 0, wrap 2, ax center"));
|
pnlMain.setLayout(new MigLayout("insets 0, gap 0, wrap 2, ax center"));
|
||||||
@@ -367,153 +247,193 @@ public class VAssignDamage {
|
|||||||
this.dlg.setVisible(true);
|
this.dlg.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
|
* @param pnlDefenders
|
||||||
|
* @param defender
|
||||||
|
*/
|
||||||
|
private void addPanelForDefender(final JPanel pnlDefenders, final Card defender) {
|
||||||
|
final CardPanel cp = new CardPanel(defender);
|
||||||
|
cp.setCardBounds(0, 0, 105, 150);
|
||||||
|
cp.setOpaque(true);
|
||||||
|
pnlDefenders.add(cp, "w 145px!, h 170px!, gap 5px 5px 3px 3px, ax center");
|
||||||
|
cp.addMouseListener(madDefender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
|
* @param source
|
||||||
|
* @param meta
|
||||||
|
* @param isLMB
|
||||||
|
*/
|
||||||
|
private void assignDamageTo(Card source, boolean meta, boolean isAdding) {
|
||||||
|
if ( !damage.containsKey(source) )
|
||||||
|
source = null;
|
||||||
|
|
||||||
|
// Allow click if this is active, or next to active and active has lethal
|
||||||
|
if (isAdding && !VAssignDamage.this.canAssignTo(source)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If lethal damage has already been assigned just act like it's 0.
|
||||||
|
int lethalDamage = getDamageToKill(source);
|
||||||
|
int damageItHad = damage.get(source).damage;
|
||||||
|
int leftToKill = Math.max(0, lethalDamage - damageItHad);
|
||||||
|
|
||||||
|
int damageToAdd = isAdding ? 1 : -1;
|
||||||
|
|
||||||
|
int leftToAssign = getRemainingDamage();
|
||||||
|
// Left click adds damage, right click substracts damage.
|
||||||
|
// Hold Ctrl to assign lethal damage, Ctrl-click again on a creature with lethal damage to assign all available damage to it
|
||||||
|
if ( meta ) {
|
||||||
|
if (isAdding) {
|
||||||
|
damageToAdd = leftToKill > 0 ? leftToKill : leftToAssign;
|
||||||
|
} else {
|
||||||
|
damageToAdd = damageItHad > lethalDamage ? lethalDamage - damageItHad : -damageItHad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( damageToAdd > leftToAssign )
|
||||||
|
damageToAdd = leftToAssign;
|
||||||
|
|
||||||
|
if ( 0 == damageToAdd || damageToAdd + damageItHad < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
addDamage(source, damageToAdd);
|
||||||
|
checkDamageQueue();
|
||||||
|
updateLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
|
*/
|
||||||
|
private void checkDamageQueue() {
|
||||||
|
boolean hasAliveEnemy = false;
|
||||||
|
for(DamageTarget dt : defenders) {
|
||||||
|
int lethal = getDamageToKill(dt.card);
|
||||||
|
int damage = dt.damage;
|
||||||
|
if ( hasAliveEnemy )
|
||||||
|
dt.damage = 0;
|
||||||
|
else
|
||||||
|
hasAliveEnemy = damage < lethal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will assign all damage to defenders and rest to player, if present
|
||||||
private void initialAssignDamage() {
|
private void initialAssignDamage() {
|
||||||
// Assign "1" damage to first combatant (it will really assign lethal damage)
|
int dmgLeft = totalDamageToAssign;
|
||||||
int lethalDamage = this.deathtouch ? 1 : Math.max(0, lstDefenders.get(0).getLethalDamage());
|
for(DamageTarget dt : defenders) {
|
||||||
int damage = Math.min(lethalDamage, this.damageLeftToAssign);
|
int lethal = getDamageToKill(dt.card);
|
||||||
assignCombatantDamage(0, damage);
|
int damage = Math.min(lethal, dmgLeft);
|
||||||
|
addDamage(dt.card, damage);
|
||||||
|
dmgLeft -= damage;
|
||||||
|
if ( dmgLeft <= 0 ) break;
|
||||||
|
}
|
||||||
|
if ( dmgLeft < 0 )
|
||||||
|
throw new RuntimeException("initialAssignDamage managed to assign more damage than it could");
|
||||||
|
if ( dmgLeft > 0 ) { // flush the remaining damage into last defender
|
||||||
|
DamageTarget dt = defenders.get(defenders.size()-1);
|
||||||
|
addDamage(dt.card, dmgLeft );
|
||||||
|
}
|
||||||
|
updateLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reset Assign Damage back to how it was at the beginning. */
|
/** Reset Assign Damage back to how it was at the beginning. */
|
||||||
private void resetAssignDamage() {
|
private void resetAssignDamage() {
|
||||||
// Functions for two new buttons that I'll try to add to the Dialog soon
|
for(DamageTarget dt : defenders)
|
||||||
int size = lstDefenders.size();
|
dt.damage = 0;
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
lstDamage.set(i, 0);
|
|
||||||
}
|
|
||||||
this.damageToOpponent = 0;
|
|
||||||
this.damageLeftToAssign = this.totalDamageToAssign;
|
|
||||||
initialAssignDamage();
|
initialAssignDamage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Goes through defenders assigning lethal damage until exhausted,
|
private void addDamage(final Card card, int addedDamage) {
|
||||||
* then overflows extra onto opponent or last defender card. */
|
|
||||||
private void autoAssignDamage() {
|
|
||||||
// Assign lethal damage to each combatant
|
|
||||||
// The first defender should aleady have lethal damage assigned
|
|
||||||
int size = lstDefenders.size();
|
|
||||||
for (int i = 1; i < size; i++) {
|
|
||||||
int lethalDamage = this.deathtouch ? 1 : Math.max(0, lstDefenders.get(i).getLethalDamage());
|
|
||||||
int damage = Math.min(lethalDamage, this.damageLeftToAssign);
|
|
||||||
if (damage == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.trample && size - 1 == i) {
|
|
||||||
damage = this.damageLeftToAssign;
|
|
||||||
}
|
|
||||||
|
|
||||||
lstDamage.set(i, damage);
|
|
||||||
this.damageLeftToAssign -= damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.trample) {
|
|
||||||
damageToOpponent = this.damageLeftToAssign;
|
|
||||||
this.damageLeftToAssign = 0;
|
|
||||||
}
|
|
||||||
// Should we just finish, or update and then let them say ok?
|
|
||||||
//update(null);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assignCombatantDamage(final Card card, int damage) {
|
|
||||||
int index = lstDefenders.indexOf(card);
|
|
||||||
assignCombatantDamage(index, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assignCombatantDamage(int index, int damage) {
|
|
||||||
// If we don't have enough left or we're trying to unassign too much return
|
// If we don't have enough left or we're trying to unassign too much return
|
||||||
if (this.damageLeftToAssign < damage) {
|
int canAssign = getRemainingDamage();
|
||||||
return;
|
if (canAssign < addedDamage) {
|
||||||
|
addedDamage = canAssign;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.damageLeftToAssign - damage > this.totalDamageToAssign) {
|
DamageTarget dt = damage.get(card);
|
||||||
return;
|
dt.damage = Math.max(0, addedDamage + dt.damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
int newDamage = lstDamage.get(index) + damage;
|
|
||||||
lstDamage.set(index, newDamage);
|
|
||||||
|
|
||||||
this.damageLeftToAssign -= damage;
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
update(index);
|
* @return
|
||||||
|
*/
|
||||||
|
private int getRemainingDamage() {
|
||||||
|
int spent = 0;
|
||||||
|
for(DamageTarget dt : defenders) {
|
||||||
|
spent += dt.damage;
|
||||||
}
|
}
|
||||||
|
return totalDamageToAssign - spent;
|
||||||
private void assignOpponentDamage(int damage) {
|
|
||||||
damage = Math.min(damage, this.damageLeftToAssign);
|
|
||||||
if (damage == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
damageToOpponent += damage;
|
|
||||||
this.damageLeftToAssign -= damage;
|
|
||||||
update(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Updates labels and other UI elements.
|
/** Updates labels and other UI elements.
|
||||||
* @param index index of the last assigned damage*/
|
* @param index index of the last assigned damage*/
|
||||||
private void update(Integer index) {
|
private void updateLabels() {
|
||||||
StringBuilder damageLeft = new StringBuilder("Available damage points: ");
|
|
||||||
damageLeft.append(this.damageLeftToAssign);
|
|
||||||
damageLeft.append(" (of ");
|
|
||||||
damageLeft.append(this.totalDamageToAssign);
|
|
||||||
damageLeft.append(")");
|
|
||||||
|
|
||||||
this.lblTotalDamage.setText(damageLeft.toString());
|
int damageLeft = totalDamageToAssign;
|
||||||
|
for ( DamageTarget dt : defenders )
|
||||||
int dmg;
|
{
|
||||||
for (int i = 0; i < lstDefenders.size(); i++) {
|
int dmg = dt.damage;
|
||||||
dmg = lstDamage.get(i);
|
damageLeft -= dmg;
|
||||||
StringBuilder sb = new StringBuilder();
|
int lethal = getDamageToKill(dt.card);
|
||||||
sb.append(dmg);
|
String text = dmg >= lethal ? Integer.toString(dmg) + " (Lethal)" : Integer.toString(dmg);
|
||||||
|
dt.label.setText(text);
|
||||||
if ((this.deathtouch && dmg > 0) || (dmg >= lstDefenders.get(i).getLethalDamage())) {
|
|
||||||
sb.append(" (Lethal)");
|
|
||||||
}
|
|
||||||
this.lstDamageLabels.get(i).setText(sb.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's an opponent, update their label.
|
this.lblTotalDamage.setText(String.format("Available damage points: %d (of %d)", damageLeft, this.totalDamageToAssign));
|
||||||
if (trample) {
|
btnOK.setEnabled(damageLeft == 0);
|
||||||
this.lstDamageLabels.get(lstDefenders.size()).setText(String.valueOf(damageToOpponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index != null) {
|
|
||||||
int newDamage = lstDamage.get(index);
|
|
||||||
//int lethal = this.deathtouch ? 1 : lstDefenders.get(index).getLethalDamage();
|
|
||||||
|
|
||||||
// Update Listeners
|
|
||||||
if (newDamage == 0) {
|
|
||||||
this.activeIndex = Math.max(0, index - 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.activeIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int newDamage = this.damageToOpponent;
|
|
||||||
if (newDamage == 0) {
|
|
||||||
this.activeIndex = lstDamage.size() - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.activeIndex = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumps damage onto cards. Damage must be stored first, because if it is
|
// Dumps damage onto cards. Damage must be stored first, because if it is
|
||||||
// assigned dynamically, the cards die off and further damage to them can't
|
// assigned dynamically, the cards die off and further damage to them can't
|
||||||
// be modified.
|
// be modified.
|
||||||
private void finish() {
|
private void finish() {
|
||||||
if (trample) {
|
if ( getRemainingDamage() > 0 )
|
||||||
Singletons.getModel().getGame().getCombat().addDefendingDamage(this.damageToOpponent, this.attacker);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < lstDefenders.size(); i++) {
|
for (DamageTarget dt : defenders) {
|
||||||
lstDefenders.get(i).addAssignedDamage(lstDamage.get(i), this.attacker);
|
if( dt.card == null && attackerHasTrample ) {
|
||||||
lstDefenders.get(i).updateObservers();
|
Singletons.getModel().getGame().getCombat().addDefendingDamage(dt.damage, this.attacker);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dt.card.addAssignedDamage(dt.damage, this.attacker);
|
||||||
|
dt.card.updateObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg.dispose();
|
dlg.dispose();
|
||||||
SOverlayUtils.hideOverlay();
|
SOverlayUtils.hideOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this method.
|
||||||
|
* @param source
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int getDamageToKill(Card source) {
|
||||||
|
int lethalDamage = 0;
|
||||||
|
if ( source == null ) {
|
||||||
|
if ( defender instanceof Player ) {
|
||||||
|
Player p = (Player)defender;
|
||||||
|
lethalDamage = attackerHasInfect ? MatchController.getPoisonCountersAmountToLose() - p.getPoisonCounters() : p.getLife();
|
||||||
|
} else if ( defender instanceof Card ) { // planeswalker
|
||||||
|
Card pw = (Card)defender;
|
||||||
|
lethalDamage = pw.getCounters(CounterType.LOYALTY);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lethalDamage = VAssignDamage.this.attackerHasDeathtouch ? 1 : Math.max(0, source.getLethalDamage());
|
||||||
|
}
|
||||||
|
return lethalDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Card, Integer> getDamageMap() {
|
||||||
|
Map<Card, Integer> result = new HashMap<Card, Integer>();
|
||||||
|
for(DamageTarget dt : defenders)
|
||||||
|
result.put(dt.card, dt.damage);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user