Update combat display code in GUI refactoring branch

This commit is contained in:
elcnesh
2014-09-03 12:21:24 +00:00
parent 608cae2572
commit 1a9b54cdd4
9 changed files with 166 additions and 124 deletions

View File

@@ -33,7 +33,6 @@ import forge.error.BugReportDialog;
import forge.events.UiEvent;
import forge.game.GameType;
import forge.game.Match;
import forge.game.combat.Combat;
import forge.game.phase.PhaseType;
import forge.game.player.IHasIcon;
import forge.game.player.RegisteredPlayer;
@@ -76,6 +75,7 @@ import forge.toolbox.special.PhaseLabel;
import forge.util.BuildInfo;
import forge.util.ITriggerEvent;
import forge.view.CardView;
import forge.view.CombatView;
import forge.view.GameEntityView;
import forge.view.IGameView;
import forge.view.PlayerView;
@@ -378,7 +378,7 @@ public class GuiDesktop implements IGuiBase {
}
@Override
public void showCombat(Combat combat) {
public void showCombat(final CombatView combat) {
CMatchUI.SINGLETON_INSTANCE.showCombat(combat);
}

View File

@@ -501,7 +501,7 @@ public enum FControl implements KeyEventDispatcher {
final LobbyPlayer humanLobbyPlayer = getGuiPlayer();
// The UI controls should use these game data as models
final List<PlayerView> players = game0.getPlayers();
CMatchUI.SINGLETON_INSTANCE.initMatch(players, humanLobbyPlayer);
CMatchUI.SINGLETON_INSTANCE.initMatch(game0, players, humanLobbyPlayer);
localPlayer = null;
gameHasHumanPlayer = false;

View File

@@ -22,7 +22,7 @@ import forge.view.CardView;
/**
* The class CardContainer. A card container is an object that references a
* card.
* {@link CardView}.
*
* @author Clemens Koza
* @version V0.0 17.02.2010
@@ -34,7 +34,7 @@ public interface CardContainer {
* </p>
*
* @param card
* a {@link forge.game.card.Card} object.
* a {@link CardView} object.
*/
void setCard(CardView card);
@@ -43,7 +43,7 @@ public interface CardContainer {
* getCard.
* </p>
*
* @return a {@link forge.game.card.Card} object.
* @return a {@link CardView} object.
*/
CardView getCard();

View File

@@ -25,7 +25,6 @@ import javax.swing.JPanel;
import forge.ImageCache;
import forge.ImageKeys;
import forge.game.card.Card;
import forge.item.InventoryItem;
import forge.model.FModel;
import forge.properties.ForgePreferences.FPref;
@@ -61,12 +60,6 @@ public final class CardPicturePanel extends JPanel {
this.setImage();
}
@Deprecated
public void setCard(final Card c) {
this.displayed = c;
this.setImage();
}
public void setCard(final CardStateView c) {
this.displayed = c;
this.setImage();

View File

@@ -42,7 +42,6 @@ import forge.events.IUiEventVisitor;
import forge.events.UiEvent;
import forge.events.UiEventAttackerDeclared;
import forge.events.UiEventBlockerAssigned;
import forge.game.combat.Combat;
import forge.game.phase.PhaseType;
import forge.game.zone.ZoneType;
import forge.gui.framework.EDocID;
@@ -71,7 +70,9 @@ import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinImage;
import forge.toolbox.special.PhaseLabel;
import forge.view.CardView;
import forge.view.CombatView;
import forge.view.GameEntityView;
import forge.view.IGameView;
import forge.view.PlayerView;
import forge.view.arcane.CardPanel;
import forge.view.arcane.PlayArea;
@@ -87,6 +88,7 @@ import forge.view.arcane.PlayArea;
public enum CMatchUI implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
private IGameView game;
private List<PlayerView> sortedPlayers;
private VMatchUI view;
@@ -122,7 +124,8 @@ public enum CMatchUI implements ICDoc, IMenuProvider {
* @param numFieldPanels int
* @param numHandPanels int
*/
public void initMatch(final List<PlayerView> players, LobbyPlayer localPlayer) {
public void initMatch(final IGameView game, final List<PlayerView> players, LobbyPlayer localPlayer) {
this.game = game;
view = VMatchUI.SINGLETON_INSTANCE;
// TODO fix for use with multiplayer
@@ -291,33 +294,33 @@ public enum CMatchUI implements ICDoc, IMenuProvider {
CDetail.SINGLETON_INSTANCE.showCard(c);
CPicture.SINGLETON_INSTANCE.showImage(c);
}
private int getPlayerIndex(PlayerView player) {
return sortedPlayers.indexOf(player);
}
public void showCombat(Combat combat) {
if (combat != null && combat.getAttackers().size() > 0 && combat.getAttackingPlayer().getGame().getStack().isEmpty()) {
if (selectedDocBeforeCombat == null) {
IVDoc<? extends ICDoc> combatDoc = EDocID.REPORT_COMBAT.getDoc();
if (combatDoc.getParentCell() != null) {
selectedDocBeforeCombat = combatDoc.getParentCell().getSelected();
if (selectedDocBeforeCombat != combatDoc) {
SDisplayUtil.showTab(combatDoc);
}
else {
selectedDocBeforeCombat = null; //don't need to cache combat doc this way
}
}
}
public void showCombat(final CombatView combat) {
if (combat != null && combat.getNumAttackers() > 0 && game.peekStack() == null) {
if (selectedDocBeforeCombat == null) {
IVDoc<? extends ICDoc> combatDoc = EDocID.REPORT_COMBAT.getDoc();
if (combatDoc.getParentCell() != null) {
selectedDocBeforeCombat = combatDoc.getParentCell().getSelected();
if (selectedDocBeforeCombat != combatDoc) {
SDisplayUtil.showTab(combatDoc);
}
else {
selectedDocBeforeCombat = null; //don't need to cache combat doc this way
}
}
}
}
else if (selectedDocBeforeCombat != null) { //re-select doc that was selected before once combat finished
SDisplayUtil.showTab(selectedDocBeforeCombat);
selectedDocBeforeCombat = null;
SDisplayUtil.showTab(selectedDocBeforeCombat);
selectedDocBeforeCombat = null;
}
CCombat.SINGLETON_INSTANCE.setModel(combat);
CCombat.SINGLETON_INSTANCE.update();
} // showBlockers()
} // showCombat(CombatView)
final Set<PlayerView> highlightedPlayers = Sets.newHashSet();
public void setHighlighted(PlayerView ge, boolean b) {

View File

@@ -1,16 +1,18 @@
package forge.screens.match.controllers;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Iterables;
import forge.UiCommand;
import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.combat.AttackingBand;
import forge.game.combat.Combat;
import forge.game.player.Player;
import forge.gui.framework.ICDoc;
import forge.screens.match.views.VCombat;
import forge.util.Lang;
import java.util.List;
import forge.view.CardView;
import forge.view.CardView.CardStateView;
import forge.view.CombatView;
import forge.view.GameEntityView;
import forge.view.PlayerView;
/**
* Controls the combat panel in the match UI.
@@ -22,7 +24,7 @@ public enum CCombat implements ICDoc {
/** */
SINGLETON_INSTANCE;
private Combat combat;
private CombatView combat;
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
@@ -44,84 +46,90 @@ public enum CCombat implements ICDoc {
*/
@Override
public void update() {
Combat localCombat = this.combat; // noone will re-assign this from other thread.
final CombatView localCombat = this.combat; // noone will re-assign this from other thread.
if (localCombat != null) {
VCombat.SINGLETON_INSTANCE.updateCombat(localCombat.getAttackers().size(), getCombatDescription(localCombat));
}
else {
VCombat.SINGLETON_INSTANCE.updateCombat(localCombat.getNumAttackers(), getCombatDescription(localCombat));
} else {
VCombat.SINGLETON_INSTANCE.updateCombat(0, "");
}
}
public void setModel(Combat combat) {
public void setModel(final CombatView combat) {
this.combat = combat;
}
private static String getCombatDescription(Combat combat) {
private static String getCombatDescription(final CombatView localCombat) {
final StringBuilder display = new StringBuilder();
// Not a big fan of the triple nested loop here
for (GameEntity defender : combat.getDefenders()) {
List<AttackingBand> bands = combat.getAttackingBandsOf(defender);
if (bands == null || bands.isEmpty()) {
continue;
}
if (display.length() > 0) {
display.append("\n");
}
if (defender instanceof Card) {
Player controller = ((Card) defender).getController();
display.append(Lang.getPossesive(controller.getName())).append(" ");
}
display.append(defender.getName()).append(" is attacked by:\n");
// Associate Bands, Attackers Blockers
boolean previousBand = false;
for(AttackingBand band : bands) {
if (band.isEmpty())
continue;
// Space out band blocks from non-band blocks
if (previousBand) {
display.append("\n");
}
Boolean blocked = band.isBlocked();
boolean isBand = band.getAttackers().size() > 1;
if (isBand) {
// Only print Band data if it's actually a band
display.append(" > BAND");
if( blocked != null )
display.append(blocked.booleanValue() ? " (blocked)" : " >>>");
display.append("\n");
}
for (final Card c : band.getAttackers()) {
display.append(" > ");
display.append(combatantToString(c)).append("\n");
}
List<Card> blockers = combat.getBlockers(band);
if (!isBand && blockers.isEmpty()) {
// if single creature is blocked, but no longer has blockers, tell the user!
if (blocked != null)
display.append(blocked.booleanValue() ? " (blocked)\n" : " >>>\n");
}
for (final Card element : blockers) {
display.append(" < ").append(combatantToString(element)).append("\n");
}
previousBand = isBand;
}
for (final GameEntityView defender : localCombat.getDefenders()) {
display.append(getCombatDescription(localCombat, defender));
}
return display.toString().trim();
}
private static String getCombatDescription(final CombatView localCombat, final GameEntityView defender) {
final StringBuilder display = new StringBuilder();
Iterable<Iterable<CardView>> bands = localCombat.getAttackingBandsOf(defender);
if (bands == null || Iterables.isEmpty(bands)) {
return StringUtils.EMPTY;
}
display.append("\n");
if (defender instanceof CardView) {
final PlayerView controller = ((CardView) defender).getController();
display.append(Lang.getPossesive(controller.getName())).append(" ");
}
display.append(defender).append(" is attacked by:\n");
// Associate Bands, Attackers Blockers
boolean previousBand = false;
for (final Iterable<CardView> band : bands) {
final int bandSize = Iterables.size(band);
if (bandSize == 0) {
continue;
}
// Space out band blocks from non-band blocks
if (previousBand) {
display.append("\n");
}
final Iterable<CardView> blockers = localCombat.getBlockers(band);
boolean blocked = (blockers == null);
boolean isBand = bandSize > 1;
if (isBand) {
// Only print Band data if it's actually a band
display.append(" > BAND");
display.append(blocked ? " (blocked)" : " >>>");
display.append("\n");
}
for (final CardView attacker : band) {
display.append(" > ");
display.append(combatantToString(attacker)).append("\n");
}
if (!isBand) {
if (blockers != null && Iterables.isEmpty(blockers)) {
// if single creature is blocked, but no longer has blockers, tell the user!
display.append(" (blocked)\n");
} else {
display.append(" >>>\n");
}
}
for (final CardView blocker : blockers) {
display.append(" < ").append(combatantToString(blocker)).append("\n");
}
previousBand = isBand;
}
return display.toString();
}
/**
* <p>
* combatantToString.
@@ -131,15 +139,15 @@ public enum CCombat implements ICDoc {
* a {@link forge.game.card.Card} object.
* @return a {@link java.lang.String} object.
*/
private static String combatantToString(final Card c) {
private static String combatantToString(final CardView c) {
final StringBuilder sb = new StringBuilder();
final CardStateView state = c.getState();
final String name = (c.isFaceDown()) ? "Morph" : c.getName();
sb.append("( ").append(c.getNetAttack()).append(" / ").append(c.getNetDefense()).append(" ) ... ");
final String name = state.getName();
sb.append("( ").append(state.getPower()).append(" / ").append(state.getToughness()).append(" ) ... ");
sb.append(name);
sb.append(" [").append(c.getUniqueNumber()).append("] ");
sb.append(" [").append(c.getId()).append("] ");
return sb.toString();
}

View File

@@ -17,7 +17,6 @@ import forge.deck.CardPool;
import forge.events.UiEvent;
import forge.game.GameType;
import forge.game.Match;
import forge.game.combat.Combat;
import forge.game.phase.PhaseType;
import forge.game.player.IHasIcon;
import forge.game.player.RegisteredPlayer;
@@ -29,6 +28,7 @@ import forge.sound.IAudioClip;
import forge.sound.IAudioMusic;
import forge.util.ITriggerEvent;
import forge.view.CardView;
import forge.view.CombatView;
import forge.view.GameEntityView;
import forge.view.IGameView;
import forge.view.PlayerView;
@@ -57,7 +57,7 @@ public interface IGuiBase {
boolean showBoxedProduct(final String title, final String message, final List<PaperCard> list);
void fireEvent(UiEvent e);
void setCard(CardView card);
void showCombat(Combat combat);
void showCombat(CombatView combat);
void setUsedToPay(CardView card, boolean b);
void setHighlighted(PlayerView player, boolean b);
void showPromptMessage(String message);

View File

@@ -47,6 +47,7 @@ import forge.game.card.Card;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardShields;
import forge.game.card.CounterType;
import forge.game.combat.AttackingBand;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -1355,10 +1356,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameView
}
private final void updateCombatView(final Combat combat) {
for (final Card c : combat.getAttackers()) {
final GameEntity defender = combat.getDefenderByAttacker(c);
final List<Card> blockers = combat.getBlockers(c);
combatView.addAttacker(getCardView(c), getGameEntityView(defender), getCardViews(blockers));
combatView.reset();
for (final AttackingBand b : combat.getAttackingBands()) {
final GameEntity defender = combat.getDefenderByAttacker(b);
final List<Card> blockers = b.isBlocked() ? combat.getBlockers(b) : null;
combatView.addAttackingBand(getCardViews(b.getAttackers()), getGameEntityView(defender), getCardViews(blockers));
}
}

View File

@@ -4,19 +4,30 @@ import java.util.Map;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class CombatView {
private Map<CardView, GameEntityView> attackersWithDefenders;
private Map<CardView, Iterable<CardView>> attackersWithBlockers;
private Map<Iterable<CardView>, GameEntityView> bandsWithDefenders;
private Map<Iterable<CardView>, Iterable<CardView>> bandsWithBlockers;
public CombatView() {
}
public int getNumAttackers() {
return attackersWithDefenders.size();
}
public Iterable<CardView> getAttackers() {
return attackersWithDefenders.keySet();
}
public Iterable<GameEntityView> getDefenders() {
return Sets.newHashSet(attackersWithDefenders.values());
}
public GameEntityView getDefender(final CardView attacker) {
return attackersWithDefenders.get(attacker);
}
@@ -25,13 +36,38 @@ public class CombatView {
return attackersWithBlockers.get(attacker);
}
/**
* Get an {@link Iterable} of the blockers of the specified band, or
* {@code null} if that band is unblocked.
*
* @param attackingBand
* an {@link Iterable} representing an attacking band.
* @return an {@link Iterable} of {@link CardView} objects, or {@code null}.
*/
public Iterable<CardView> getBlockers(final Iterable<CardView> attackingBand) {
return bandsWithBlockers.get(attackingBand);
}
public Iterable<CardView> getAttackersOf(final GameEntityView defender) {
return Maps.filterValues(attackersWithDefenders, Predicates.equalTo(defender)).keySet();
}
public void addAttacker(final CardView attacker, final GameEntityView defender, final Iterable<CardView> blockers) {
this.attackersWithDefenders.put(attacker, defender);
this.attackersWithBlockers.put(attacker, blockers);
public Iterable<Iterable<CardView>> getAttackingBandsOf(final GameEntityView defender) {
return Maps.filterValues(bandsWithDefenders, Predicates.equalTo(defender)).keySet();
}
public void addAttackingBand(final Iterable<CardView> attackingBand, final GameEntityView defender, final Iterable<CardView> blockers) {
for (final CardView attacker : attackingBand) {
this.attackersWithDefenders.put(attacker, defender);
this.attackersWithBlockers.put(attacker, blockers);
}
this.bandsWithDefenders.put(attackingBand, defender);
this.bandsWithBlockers.put(attackingBand, blockers);
}
public void reset() {
this.attackersWithDefenders = Maps.newHashMap();
this.attackersWithBlockers = Maps.newHashMap();
this.bandsWithDefenders = Maps.newHashMap();
this.bandsWithBlockers = Maps.newHashMap();
}
}