package net.sf.colossus.gui; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.util.ConcurrentModificationException; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.sf.colossus.client.Client; import net.sf.colossus.client.HexMap; import net.sf.colossus.game.Legion; import net.sf.colossus.util.InstanceTracker; import net.sf.colossus.variant.BattleHex; import net.sf.colossus.variant.MasterHex; /** * Class BattleMap implements the GUI for a Titan battlemap. * * TODO there is still model code in here, thus we still have dependencies * from the AI and server packages into this class. * * @author David Ripton */ @SuppressWarnings("serial") public final class BattleMap extends HexMap { private static final Logger LOGGER = Logger.getLogger(BattleMap.class .getName()); private static int count = 1; private final Client client; private final ClientGUI gui; private final Marker attackerMarker; private final Marker defenderMarker; public BattleMap(Client client, MasterHex masterHex, Legion attacker, Legion defender, ClientGUI gui) { super(masterHex); this.client = client; this.gui = gui; attackerMarker = new Marker(attacker, 3 * Scale.get(), attacker.getLongMarkerId(), false, client); defenderMarker = new Marker(defender, 3 * Scale.get(), defender.getLongMarkerId(), true, client); attackerMarker.setOpaque(false); defenderMarker.setOpaque(false); attackerMarker.setToolTipText("Attacking Legion"); defenderMarker.setToolTipText("Defending Legion"); this.add(attackerMarker); this.add(defenderMarker); String instanceId = client.getOwningPlayer().getName() + ": " + attacker.getMarkerId() + "/" + defender.getMarkerId() + " (" + count + ")"; count++; InstanceTracker.setId(this, instanceId); } public void setBattleMarkerLocation(boolean isDefender, BattleHex battleHex) { GUIBattleHex hex = getGUIHexByModelHex(battleHex); Rectangle rect = hex.getBounds(); Point point; if ("X1".equals(battleHex.getLabel()) || "X4".equals(battleHex.getLabel())) { point = new Point(rect.x, rect.height + rect.y); } else { point = new Point(rect.x + rect.width, rect.y); } if (isDefender) { defenderMarker.setLocation(point, battleHex.getLabel()); } else { attackerMarker.setLocation(point, battleHex.getLabel()); } } // Following four override to make them public because they are needed // by MasterBoard. Is there a better way? @Override public void setupHexes() { super.setupHexes(); } @Override public void selectHexes(Set<BattleHex> set) { super.selectHexes(set); } @Override public void unselectHex(BattleHex hex) { super.unselectHex(hex); } @Override public void unselectAllHexes() { super.unselectAllHexes(); } @Override public Set<BattleHex> getAllHexes() { return super.getAllHexes(); } @Override public MasterHex getMasterHex() { return super.getMasterHex(); } @Override public GUIBattleHex getGUIHexByModelHex(BattleHex battleHex) { return super.getGUIHexByModelHex(battleHex); } @Override public GUIBattleHex getHexContainingPoint(Point point) { return super.getHexContainingPoint(point); } /** Select all hexes containing critters eligible to move. */ public void highlightMobileCritters() { Set<BattleHex> set = client.findMobileCritterHexes(); unselectAllHexes(); unselectEntranceHexes(); selectHexes(set); selectEntranceHexes(set); } /** Select hexes containing critters that have valid strike targets. */ public void highlightCrittersWithTargets() { Set<BattleHex> set = client.findCrittersWithTargets(); unselectAllHexes(); selectHexes(set); // XXX Needed? repaint(); } public void selectEntranceHexes(Set<BattleHex> modelHexes) { for (BattleHex battleHex : modelHexes) { String hexLabel = battleHex.getLabel(); if (hexLabel.startsWith("X")) { if (hexLabel.equals(defenderMarker.hexLabel)) { defenderMarker.highlightMarker(); } if (hexLabel.equals(attackerMarker.hexLabel)) { attackerMarker.highlightMarker(); } } } } public void unselectEntranceHexes() { defenderMarker.resetMarkerHighlight(); attackerMarker.resetMarkerHighlight(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Rectangle rectClip = g.getClipBounds(); // Abort if called too early. if (rectClip == null) { return; } try { for (GUIBattleChit battleChit : gui.getGUIBattleChits()) { if (rectClip.intersects(battleChit.getBounds())) { battleChit.paintComponent(g); } } if (attackerMarker.getLocation().x > 0) // don't paint till placed { attackerMarker.paintComponent(g); } if (defenderMarker.getLocation().x > 0) // don't paint till placed { defenderMarker.paintComponent(g); } } catch (ConcurrentModificationException ex) { // Let the next repaint clean up. LOGGER.log(Level.FINEST, "harmless " + ex.toString()); } } }