/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package gui;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import rts.Game;
import rts.PhysicalGameState;
import rts.units.Unit;
import rts.units.UnitAction;
/**
* \package gui
* \brief A graphical display of the game
*/
/**
* \brief A graphical display of the game
* @author santi
*/
public class PhysicalGameStatePanel extends JPanel {
private static final int HUD_W = 150;
/**
*
*/
private static final long serialVersionUID = 1L;
public Game game = null;
private boolean fog;
private int team;
private int WIDTH;
// colors for the players
private static final Color RESOURCE_COLORS[] = {new Color(212, 175, 55), new Color(192, 192, 192)};
private static final Color PLAYER_COLORS[] = {Color.cyan, Color.red, Color.green, Color.yellow, Color.blue,
Color.pink, Color.magenta, Color.orange, Color.darkGray, Color.lightGray
};
public PhysicalGameStatePanel(Game _game) {
game = _game;
setBackground(Color.darkGray);
}
public static JFrame newVisualizer(Game _game, int dy, boolean show_fog, int follow_team) {
/*PhysicalGameStatePanel w = *///new PhysicalGameStatePanel(_game);
PhysicalGameStatePanel ad = new PhysicalGameStatePanel(_game);
JFrame frame = new JFrame("Game State Visuakizer");
frame.getContentPane().add(ad);
frame.pack();
frame.setResizable(false);
ad.WIDTH = dy;
ad.fog = show_fog;
ad.team = follow_team;
frame.setSize(dy+HUD_W*2,dy);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
return frame;
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
int grid = WIDTH/game.pgs.width-1;
int sizex = grid*game.pgs.width;
int sizey = grid*game.pgs.height;
g2d.translate(getWidth()/2 - sizex/2, getHeight()/2 - sizey/2);
Color playerColor = null;
boolean[] visibility = new boolean[game.pgs.width*game.pgs.height];
// draw grid:
g.setColor(Color.GRAY);
for(int i = 0;i<=game.pgs.width;i++)
g.drawLine(i*grid, 0, i*grid, game.pgs.height*grid);
for(int i = 0;i<=game.pgs.height;i++)
g.drawLine(0, i*grid, game.pgs.width*grid, i*grid);
// draw the units:
synchronized(this) {
// this list copy is to prevent a concurrent modification exception
List<Unit> l = new LinkedList<Unit>();
for (int i = 0; i < game.pgs.armies.size(); i++) {
l.addAll(game.pgs.armies.get(i));
}
for (int i = 0; i < visibility.length; i++) {
visibility[i] = !fog|!game.pgs.fog;
}
for (Unit u:l) {
if (u.getPlayer() != -1 && (team == -1 || game.pgs.teams.get(team).contains(u.getPlayer()))) {
for (int i = u.getY()-u.getVision(); i <= u.getY()+u.getVision(); i++) {
if (i >= 0 && i < game.pgs.height) {
for (int j = u.getX()-u.getVision(); j <= u.getX()+u.getVision(); j++) {
if (j >= 0 && j < game.pgs.width) {
if ((u.getY()-i)*(u.getY()-i)+(u.getX()-j)*(u.getX()-j) <= u.getVision()*u.getVision()) {
visibility[j+i*game.pgs.width] = true;
}
}
}
}
}
}
}
for(int j = 0;j<game.pgs.width;j++) {
for(int i = 0;i<game.pgs.height;i++) {
if (visibility[j+i*game.pgs.width] && game.pgs.terrain[j+i*game.pgs.width]==PhysicalGameState.TERRAIN_WALL) {
g.setColor(Color.lightGray);
g.fillRect(j*grid, i*grid, grid, grid);
} else if (!visibility[j+i*game.pgs.width]) {
g.setColor(Color.black);
g.fillRect(j*grid, i*grid, grid, grid);
}
}
}
//l.addAll(pgs.getUnits());
for(Unit u:l) {
if ((u.getPlayer() == -1 || (u.getPlayer() != -1 && team != -1 && !game.pgs.teams.get(team).contains(u.getPlayer()))) && !visibility[u.getX()+u.getY()*game.pgs.width]) {
continue;
}
if (u.getHP() > 0 || u.isResources()) {
int reduction = 0;
playerColor = PLAYER_COLORS[u.getPlayer()+1];
if (u.isBuilding() || u.isResources()) {
if (u.isStockpile()) {
g.setColor(Color.yellow);
g.fillRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid-reduction*2, grid-reduction*2);
} else if (u.isResources()) {
g.setColor(RESOURCE_COLORS[u.getResourcesType()]);
g.fillRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid-reduction*2, grid-reduction*2);
} else {
g.setColor(new Color(100,125,255));
g.fillRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid-reduction*2, grid-reduction*2);
}
g.setColor(playerColor);
g.drawRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid-reduction*2, grid-reduction*2);
//g.drawRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid-reduction*2, grid-reduction*2);
if (u.hasAction() && (u.getAction().getType() == UnitAction.ATTACK || u.getAction().getType() == UnitAction.BUILD)) {
g.setColor(Color.white);
g.drawOval(u.getAction().getTargetX()*grid+3*grid/8, u.getAction().getTargetY()*grid+3*grid/8, grid/4, grid/4);
g.drawLine(u.getX()*grid+grid/2, u.getY()*grid+grid/2, u.getAction().getTargetX()*grid+grid/2, u.getAction().getTargetY()*grid+grid/2);
}
} else {
g.setColor(Color.decode("#AAAAAA"));
/// TODO: set a different color based on some kind of unit attributes??
if (u.isFlying()) {
g.fillPolygon(new int[]{u.getX()*grid, u.getX()*grid+grid/2, u.getX()*grid+grid}, new int[]{u.getY()*grid+grid/2, u.getY()*grid, u.getY()*grid+grid/2}, 3);
}
if (u.getAttackRange() > 1) {
g.fillRect(u.getX()*grid, u.getY()*grid+3*grid/4, grid, grid/8);
}
if (u.isWorker()) {
g.fillRoundRect(u.getX()*grid+grid/4, u.getY()*grid, grid/2, grid, 1, 1);
g.setColor(playerColor);
g.drawRoundRect(u.getX()*grid+grid/4, u.getY()*grid, grid/2, grid, 1, 1);
} else {
g.fillOval(u.getX()*grid+grid/4, u.getY()*grid, grid/2, grid);
g.setColor(playerColor);
g.drawOval(u.getX()*grid+grid/4, u.getY()*grid, grid/2, grid);
}
if (u.hasAction() && (u.getAction().getType() == UnitAction.ATTACK || u.getAction().getType() == UnitAction.BUILD)) {
g.setColor(Color.white);
g.drawOval(u.getAction().getTargetX()*grid+3*grid/8, u.getAction().getTargetY()*grid+3*grid/8, grid/4, grid/4);
if (u != null && u.getAction() != null) { // huh?
g.drawLine(u.getX()*grid+grid/2, u.getY()*grid+grid/2, u.getAction().getTargetX()*grid+grid/2, u.getAction().getTargetY()*grid+grid/2);
}
}
}
if (u.getResources()!=0) {
String txt = "" + u.getResources();
g.setColor(Color.black);
FontMetrics fm = getFontMetrics( g.getFont() );
int width = fm.stringWidth(txt);
g2d.drawString(txt, u.getX()*grid + grid/2 - width/2, u.getY()*grid + grid/2);
} else {
g.setColor(Color.black);
FontMetrics fm = getFontMetrics( g.getFont() );
int width = fm.stringWidth(""+u.getLabel().charAt(0));
g2d.drawString(""+u.getLabel().charAt(0), u.getX()*grid + grid/2 - width/2, u.getY()*grid + grid/2);
//USEFUL DEBUG: draws unit IDs
// g.setColor(Color.white);
// fm = getFontMetrics( g.getFont() );
// width = fm.stringWidth(""+u.getID());
// g2d.drawString(""+u.getID(), u.getX()*grid + grid/2 - width/2, u.getY()*grid + grid/2);
}
if (u.getHP()<u.getMaxHP()) {
g.setColor(Color.RED);
g.fillRect(u.getX()*grid+reduction, u.getY()*grid+reduction, grid, 2);
g.setColor(Color.GREEN);
g.fillRect(u.getX()*grid+reduction, u.getY()*grid+reduction, (int)(grid*(((float)u.getHP())/u.getMaxHP())), 2);
}
}
g.setColor(Color.WHITE);
g.drawString(game.cycle + "", 0, 0);
int offset = 0;
for (int i = 0; i < game.pgs.numberOfPlayers(); i+=2) { // left side
offset = draw_stats(g, i, -HUD_W, offset);
}
offset = 0;
for (int i = 1; i < game.pgs.numberOfPlayers(); i+=2) { // right side
offset = draw_stats(g, i, getWidth()-HUD_W*2, offset);
}
}
}
}
private int draw_stats(Graphics g, int i, int w, int offset) {
g.setColor(PLAYER_COLORS[(i+1)%PLAYER_COLORS.length]);
offset += 10;
g.drawString("Player "+i+": "+game.getAgent(i).getLabel(), w, offset);
int team = 0;
for (int j = 0; j < game.pgs.teams.size(); j++) {
if (game.pgs.teams.get(j).contains(i)) {
team = j;
break;
}
}
offset += 20;
g.setColor(PLAYER_COLORS[(1+team)%PLAYER_COLORS.length]);
g.drawString("Team: "+team, w, offset);
g.setColor(Color.white);
offset += 20;
g.drawString("Score: "+game.pgs.scores.get(i), w, offset);
offset += 20;
g.drawString("Resources: "+game.pgs.resources.get(i), w, offset);
offset += 20;
g.drawString("Kills: "+game.pgs.kills.get(i), w, offset);
offset += 20;
g.drawString("Deaths: "+game.pgs.deaths.get(i), w, offset);
offset += 20;
g.drawString("Units:", w, offset);
ArrayList<Integer> units = new ArrayList<Integer>();
ArrayList<Integer> buildings = new ArrayList<Integer>();
for (int j = 0; j < game.pgs.unitDefinitions.building_defs.get(i).size(); j++) {
buildings.add(0);
}
for (int j = 0; j < game.pgs.unitDefinitions.unit_defs.get(i).size(); j++) {
units.add(0);
}
for (int j = 0; j < game.pgs.armies.get(i).size(); j++) {
if (game.pgs.armies.get(i).get(j).isBuilding()) {
buildings.set(game.pgs.armies.get(i).get(j).getType(), buildings.get(game.pgs.armies.get(i).get(j).getType())+1);
} else {
units.set(game.pgs.armies.get(i).get(j).getType(), units.get(game.pgs.armies.get(i).get(j).getType())+1);
}
}
for (int j = 0; j < units.size(); j++) {
offset += 20;
g.drawString(" "+game.pgs.unitDefinitions.unit_defs.get(i).get(j).label+": "+units.get(j), w, offset);
}
offset += 20;
g.drawString("Buildings:", w, offset);
for (int j = 0; j < buildings.size(); j++) {
offset += 20;
g.drawString(" "+game.pgs.unitDefinitions.building_defs.get(i).get(j).label+": "+buildings.get(j), w, offset);
}
return offset+10;
}
}