diff --git a/src/Graphwar/GameScreen.java b/src/Graphwar/GameScreen.java index f6e3a01..f473384 100644 --- a/src/Graphwar/GameScreen.java +++ b/src/Graphwar/GameScreen.java @@ -19,6 +19,7 @@ import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; @@ -29,12 +30,21 @@ import java.awt.event.MouseListener; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Locale; import java.util.Stack; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.KeyStroke; import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; import GraphServer.Constants; @@ -57,6 +67,16 @@ public class GameScreen extends JPanel implements ActionListener, StartStopPanel private GraphPlane plane; private GraphTimer timer; private GraphAngleDisplay angleDisplay; + private JDialog functionHelperWindow; + private JTextField targetXField; + private JTextField targetYField; + private JButton targetGenerateButton; + private JButton targetUndoButton; + private JButton targetResetButton; + private JLabel targetStatusLabel; + private JLabel targetCountLabel; + private ArrayList targetXs; + private ArrayList targetYs; private JLabel[] backgroundsQuit; private GraphButton yesQuit; @@ -110,6 +130,10 @@ public GameScreen(Graphwar graphwar, String confFile) throws Exception angleDisplay = new GraphAngleDisplay(graphwar); angleDisplay.setBounds(10, 475, 200, 113); + + targetXs = new ArrayList(); + targetYs = new ArrayList(); + functionHelperWindow = makeFunctionHelperWindow(); components.push(yImg); components.push(dyImg); @@ -129,6 +153,11 @@ public GameScreen(Graphwar graphwar, String confFile) throws Exception this.global.addActionListener(this); this.funcField.addActionListener(this); this.chatField.addActionListener(this); + this.targetGenerateButton.addActionListener(this); + this.targetUndoButton.addActionListener(this); + this.targetResetButton.addActionListener(this); + this.targetXField.addActionListener(this); + this.targetYField.addActionListener(this); this.dyImg.setVisible(false); this.ddyImg.setVisible(false); @@ -195,10 +224,81 @@ public GameScreen(Graphwar graphwar, String confFile) throws Exception this.setFocusable(true); this.addKeyListener(this); - + this.addComponentsReversed(this, components); this.revalidate(); } + + private JDialog makeFunctionHelperWindow() + { + JPanel panel = new JPanel(null); + panel.setPreferredSize(new Dimension(260, 112)); + panel.setBackground(new Color(238, 245, 238)); + panel.setBorder(BorderFactory.createLineBorder(new Color(65, 100, 65))); + + JLabel title = new JLabel("Aim helper"); + title.setFont(new Font("Sans", Font.BOLD, 12)); + title.setBounds(8, 4, 90, 18); + panel.add(title); + + targetCountLabel = new JLabel("0 points"); + targetCountLabel.setFont(new Font("Sans", Font.PLAIN, 11)); + targetCountLabel.setBounds(150, 4, 100, 18); + panel.add(targetCountLabel); + + JLabel xLabel = new JLabel("x"); + xLabel.setBounds(8, 27, 12, 20); + panel.add(xLabel); + + targetXField = new JTextField(); + targetXField.setBounds(22, 27, 70, 22); + panel.add(targetXField); + + JLabel yLabel = new JLabel("y"); + yLabel.setBounds(102, 27, 12, 20); + panel.add(yLabel); + + targetYField = new JTextField(); + targetYField.setBounds(116, 27, 70, 22); + panel.add(targetYField); + + targetGenerateButton = new JButton("Generate"); + targetGenerateButton.setBounds(8, 53, 94, 24); + panel.add(targetGenerateButton); + + targetUndoButton = new JButton("Undo"); + targetUndoButton.setBounds(108, 53, 70, 24); + panel.add(targetUndoButton); + + targetResetButton = new JButton("Reset"); + targetResetButton.setBounds(184, 53, 68, 24); + panel.add(targetResetButton); + + targetStatusLabel = new JLabel("Click map"); + targetStatusLabel.setFont(new Font("Sans", Font.PLAIN, 11)); + targetStatusLabel.setBounds(8, 82, 244, 22); + panel.add(targetStatusLabel); + + panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK), "undoTargetPoint"); + panel.getActionMap().put("undoTargetPoint", + new AbstractAction() + { + public void actionPerformed(ActionEvent e) + { + undoTargetPoint(); + } + } + ); + + JDialog dialog = new JDialog(graphwar, "Aim Helper", false); + dialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + dialog.setContentPane(panel); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocation(graphwar.getX()+Constants.WIDTH+10, graphwar.getY()+60); + + return dialog; + } private void addComponentsReversed(JPanel panel, Stack components) { @@ -357,6 +457,326 @@ public void run() } ); } + + refreshFunctionHelper(); + } + + private void refreshFunctionHelper() + { + boolean enabled = false; + String status = "Normal only"; + + if(graphwar.getGameData().getGameMode() == Constants.NORMAL_FUNC) + { + Player player = graphwar.getGameData().getCurrentTurnPlayer(); + enabled = player.isLocalPlayer() && !(player instanceof ComputerPlayer) && graphwar.getGameData().isDrawingFunction() == false; + status = "Click map"; + } + + final boolean helperEnabled = enabled; + final String helperStatus = status; + + SwingUtilities.invokeLater( + new Runnable() + { + public void run() + { + targetXField.setEnabled(helperEnabled); + targetYField.setEnabled(helperEnabled); + targetGenerateButton.setEnabled(helperEnabled); + targetUndoButton.setEnabled(helperEnabled && targetXs.size() > 0); + targetResetButton.setEnabled(helperEnabled && targetXs.size() > 0); + targetCountLabel.setText(targetXs.size()+" points"); + if(targetXs.size() == 0) + { + targetStatusLabel.setText(helperStatus); + } + } + } + ); + } + + private double getGameXFromBoardPixel(int x) + { + return ((double)x - (double)Constants.PLANE_LENGTH/2.0) + * (double)Constants.PLANE_GAME_LENGTH/(double)Constants.PLANE_LENGTH; + } + + private double getGameYFromBoardPixel(int y) + { + return ((double)Constants.PLANE_HEIGHT/2.0 - (double)y) + * (double)Constants.PLANE_GAME_LENGTH/(double)Constants.PLANE_LENGTH; + } + + private int getBoardPixelXFromGame(double x) + { + return (int)Math.round(Constants.PLANE_LENGTH*x/Constants.PLANE_GAME_LENGTH + Constants.PLANE_LENGTH/2.0); + } + + private int getBoardPixelYFromGame(double y) + { + return (int)Math.round(-Constants.PLANE_LENGTH*y/Constants.PLANE_GAME_LENGTH + Constants.PLANE_HEIGHT/2.0); + } + + private void selectTargetFromPlane(int displayX, int displayY) + { + if(graphwar.getGameData().getGameMode() != Constants.NORMAL_FUNC) + { + targetStatusLabel.setText("Normal only"); + return; + } + + int boardX = displayX; + if(graphwar.getGameData().isTerrainReversed()) + { + boardX = Constants.PLANE_LENGTH - boardX; + } + + int boardY = displayY; + + double x = getGameXFromBoardPixel(boardX); + double y = getGameYFromBoardPixel(boardY); + + addTargetPoint(x, y); + } + + private void addTargetPointFromFields() + { + double x; + double y; + + try + { + x = Double.parseDouble(targetXField.getText().trim().replace(',', '.')); + y = Double.parseDouble(targetYField.getText().trim().replace(',', '.')); + } + catch(NumberFormatException e) + { + targetStatusLabel.setText("Bad point"); + return; + } + + addTargetPoint(x, y); + } + + private void addTargetPoint(double x, double y) + { + targetXField.setText(formatNumber(x)); + targetYField.setText(formatNumber(y)); + targetXs.add(new Double(x)); + targetYs.add(new Double(y)); + targetStatusLabel.setText("Point added"); + refreshTargetMarkers(); + refreshFunctionHelper(); + } + + private String formatNumber(double value) + { + if(Math.abs(value) < 0.00005) + { + value = 0; + } + + String text = String.format(Locale.US, "%.4f", value); + + while(text.indexOf('.') >= 0 && text.endsWith("0")) + { + text = text.substring(0, text.length()-1); + } + + if(text.endsWith(".")) + { + text = text.substring(0, text.length()-1); + } + + return text; + } + + private String formatSignedNumber(double value) + { + String number = formatNumber(Math.abs(value)); + if(value < 0) + { + return "-"+number; + } + + return "+"+number; + } + + private double getFunctionX(Player player, double worldX) + { + if(player.getTeam() == Constants.TEAM2) + { + return -worldX; + } + + return worldX; + } + + private void refreshTargetMarkers() + { + int[] markerXs = new int[targetXs.size()]; + int[] markerYs = new int[targetYs.size()]; + + for(int i=0; i 0) + { + targetXField.setText(formatNumber(targetXs.get(targetXs.size()-1).doubleValue())); + targetYField.setText(formatNumber(targetYs.get(targetYs.size()-1).doubleValue())); + } + else + { + targetXField.setText(""); + targetYField.setText(""); + } + + refreshTargetMarkers(); + refreshFunctionHelper(); + } + + private void resetTargetPoints() + { + targetXs.clear(); + targetYs.clear(); + targetXField.setText(""); + targetYField.setText(""); + targetStatusLabel.setText("Cleared"); + refreshTargetMarkers(); + refreshFunctionHelper(); + } + + private String makePolylineFunction(Player player) + { + Soldier soldier = player.getCurrentTurnSoldier(); + double soldierX = getGameXFromBoardPixel(soldier.getX()); + double soldierY = getGameYFromBoardPixel(soldier.getY()); + + int numPoints = targetXs.size()+1; + double[] xs = new double[numPoints]; + double[] ys = new double[numPoints]; + + xs[0] = getFunctionX(player, soldierX); + ys[0] = 0; + + for(int i=0; i= 0.00005) + { + function.append(formatSignedNumber(intercept)); + } + + for(int i=1; i xs.length) + { + count = xs.length; + } + + if(count > ys.length) + { + count = ys.length; + } + + targetMarkerXs = new int[count]; + targetMarkerYs = new int[count]; + numTargetMarkers = count; + + for(int i=0; i= Constants.PLANE_LENGTH) + { + return Constants.PLANE_LENGTH - 1; + } + + return x; + } + + private int clampPlaneY(int y) + { + if(y < 0) + { + return 0; + } + else if(y >= Constants.PLANE_HEIGHT) + { + return Constants.PLANE_HEIGHT - 1; + } + + return y; + } + + private void drawTargetMarker(Graphics g, boolean reversed) + { + if(numTargetMarkers == 0) + { + return; + } + + Player currentPlayer = graphwar.getGameData().getCurrentTurnPlayer(); + Soldier currentSoldier = currentPlayer.getCurrentTurnSoldier(); + int lastX = currentSoldier.getX(); + if(reversed) + { + lastX = Constants.PLANE_LENGTH - lastX; + } + int lastY = currentSoldier.getY(); + + for(int i=0; i Constants.PLANE_HEIGHT) + { + borderY = y-30-2*Constants.SOLDIER_RADIUS; + textY = y-17-2*Constants.SOLDIER_RADIUS; + } + + if(borderY < 0) + { + borderY = y+2+2*Constants.SOLDIER_RADIUS; + textY = y+15+2*Constants.SOLDIER_RADIUS; + } + + if(borderX < 0) + { + textX = textX - borderX; + borderX = 0; + } + + if(borderX + textLength+2*border > Constants.PLANE_LENGTH) + { + textX = (textX - borderX) + Constants.PLANE_LENGTH - textLength-2*border; + borderX = Constants.PLANE_LENGTH - textLength-2*border; + } + + g.setColor(transparentWhite); + g.fillRoundRect(borderX, borderY, textLength+2*border, 15, 7, 7); + + g.setColor(player.getColor()); + g.drawRoundRect(borderX, borderY, textLength+2*border, 15, 7, 7); + + g.setColor(Color.BLACK); + g.drawString(coordinates, textX, textY); + } private void drawPlayersNames(Graphics g, boolean reversed) { @@ -726,6 +918,7 @@ private void drawPlayersNames(Graphics g, boolean reversed) if(soldiers[j].isAlive()) { paintPlayerName(g2d, drawX, drawY, player); + paintPlayerCoordinates(g2d, drawX, drawY, player, soldiers[j]); } else if(soldiers[j].isExploding()) { @@ -739,6 +932,7 @@ else if(soldiers[j].isExploding()) g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); paintPlayerName(g2d, drawX, drawY, player); + paintPlayerCoordinates(g2d, drawX, drawY, player, soldiers[j]); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); }