home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-08-14 | 14.4 KB | 507 lines |
- /*
- * @(#)ClientLookArcade.java
- */
-
- package games.Battle.client.ClientApplet;
-
- import java.awt.Image;
- import java.awt.Graphics;
- import java.awt.Color;
- import java.awt.Component;
- import java.util.Random;
-
- import games.Battle.shared.sys.Symbols;
- import games.Battle.shared.sys.Rules;
- import games.Battle.shared.sys.Board;
- import games.Battle.shared.sys.Cell;
- import games.Battle.shared.sys.Common;
-
- /**
- * ClientLookArcade is a client look that uses a variety of images
- * loaded from the client URL to simulate the contours of the landscape
- * with shadows and hilites, assuming the light source is hitting the
- * land from the upper left hand side of the game board.
- *
- * Hills look like they rise out of the landscape and valleys actually
- * look like they sink into the landscape.
- *
- * ClientLookArcade implements ClientLook's abstract methods update()
- * and updateTerrain() and adds several supporting methods.
- *
- * @author Alex Nicolaou
- * @author Jay Steele
- */
- public class ClientLookArcade extends ClientLook {
-
- static Random rand = new Random();
-
- /**
- * Set to true and recompiled to get visual debugging features.
- */
- static final boolean DEBUG = false;
-
- /**
- * Cached width and height;
- */
- int width, height;
-
- /**
- * Counts the number of updates which have occurred.
- */
- int count = 0;
-
- /**
- * The background terrain image.
- */
- Image terrainImage = null;
-
- /**
- * Construct a ClientLookArcade with the given ClientBoardComponent.
- * @param ClientLookArcade
- */
- public ClientLookArcade(ClientBoardComponent c) {
- super(c);
- terrainImage = component.createImage(Symbols.BOARD_W, Symbols.BOARD_H);
- }
-
- /**
- * North bitmask for getSurroundingWaterMask()
- */
- static final int NORTH = 0x01;
-
- /**
- * South bitmask for getSurroundingWaterMask()
- */
- static final int SOUTH = 0x02;
-
- /**
- * East bitmask for getSurroundingWaterMask()
- */
- static final int EAST = 0x04;
-
- /**
- * West bitmask for getSurroundingWaterMask()
- */
- static final int WEST = 0x08;
-
- /**
- * Return a mask of 4 bits which give information about the water
- * surrounding the given cell. This method says: you have water
- * to your north, south, east or west.
- * @param board the board containing the cells
- * @param the cell row
- * @param the cell column
- */
- public int getSurroundingWaterMask(Board board, int r, int c) {
- int result = 0;
- if (r > 0 && board.getCell(r-1,c).getTerrain() == 0)
- result |= NORTH;
- if (r < 15 && board.getCell(r+1,c).getTerrain() == 0)
- result |= SOUTH;
- if (c > 0 && board.getCell(r,c-1).getTerrain() == 0)
- result |= WEST;
- if (c < 15 && board.getCell(r,c+1).getTerrain() == 0)
- result |= EAST;
- return result;
- }
-
- /**
- * Return a certain water image based on a mask. The mask
- * represents a value returned from getSurroundingWaterMask().
- * @param mask the mask on which to switch to select the image
- */
- public Image waterImage(int mask) {
- Image result = null;
- switch (mask) {
- case 0: // No surrounding water
- int num = Math.abs(rand.nextInt()) % 4;
- result = ClientImages.water_single[num];
- break;
- case 1: // N
- result = ClientImages.water_end[0];
- break;
- case 2: // S
- result = ClientImages.water_end[2];
- break;
- case 3: // NS
- result = ClientImages.water_straight[0];
- break;
- case 4: // E
- result = ClientImages.water_end[1];
- break;
- case 5: // NE
- result = ClientImages.water_elbow[0];
- break;
- case 6: // SE
- result = ClientImages.water_elbow[1];
- break;
- case 7: // NSE
- result = ClientImages.water_t[0];
- break;
- case 8: // W
- result = ClientImages.water_end[3];
- break;
- case 9: // NW
- result = ClientImages.water_elbow[3];
- break;
- case 10: // SW
- result = ClientImages.water_elbow[2];
- break;
- case 11: // NSW
- result = ClientImages.water_t[2];
- break;
- case 12: // EW
- result = ClientImages.water_straight[1];
- break;
- case 13: // NEW
- result = ClientImages.water_t[3];
- break;
- case 14: // SEW
- result = ClientImages.water_t[1];
- break;
- case 15: // NSEW
- result = ClientImages.water_cross;
- break;
- default:
- result = null;
- }
- return result;
- }
-
- /**
- * Update the background terrain image for board b.
- * @param b the board to update the terrain image for
- */
- public void updateTerrain(ClientBoard b) {
- Graphics g = terrainImage.getGraphics();
- for (int i=0; i<4; i++) {
- for (int j=0; j<4; j++) {
- if (ClientImages.earth != null)
- g.drawImage(ClientImages.earth, i*128, j*128,
- ClientImages.applet);
- }
- }
-
- for (int r=0; r< Rules.rows; r++) {
- for (int c=0; c< Rules.cols; c++) {
- int terrain = b.getCell(r, c).getTerrain();
- if (terrain == 0) {
- int mask = getSurroundingWaterMask(b, r, c);
- g.drawImage(waterImage(mask), c*32, r*32,
- ClientImages.applet);
- if (DEBUG) {
- g.setColor(Color.darkGray);
- g.fillRect(c*32+6, r*32+6, 20, 20);
- }
-
- // fill in the center of black of 4 water
- if (r > 0 && c > 0) {
- int t_nw = b.getCell(r-1, c-1).getTerrain();
- int t_n = b.getCell(r-1, c).getTerrain();
- int t_w = b.getCell(r, c-1).getTerrain();
- if (t_nw == 0 && t_n == 0 && t_w == 0) {
- g.drawImage(ClientImages.water_single[0],
- c*32-16, r*32-16, ClientImages.applet);
- }
- }
- }
- if (r > 0) {
- int terrainAbove = b.getCell(r-1, c).getTerrain();
- int diff = terrain - terrainAbove;
- if (diff != 0) {
- if (terrain == 0) {
- diff = diff + 1;
- } else if (terrainAbove == 0) {
- diff = diff - 1;
- }
- }
- if (diff != 0) {
- Image div = null;
- int index = 4-Math.abs(diff);
- if (index < 0) index = 0;
- if (diff > 0) {
- div = ClientImages.hilite_h[index];
- } else {
- div = ClientImages.shadow_h[index];
- }
- g.drawImage(div, c*32, r*32-4+index, ClientImages.applet);
- }
- }
- if (c > 0) {
- int terrainLeft = b.getCell(r, c-1).getTerrain();
- int diff = terrain - terrainLeft;
- if (diff != 0) {
- if (terrain == 0) {
- diff = diff + 1;
- } else if (terrainLeft == 0) {
- diff = diff - 1;
- }
- }
- if (diff != 0)
- {
- Image div = null;
- int index = 4-Math.abs(diff);
- if (index < 0) index = 0;
- if (diff > 0) {
- div = ClientImages.hilite_v[index];
- } else {
- div = ClientImages.shadow_v[index];
- }
- g.drawImage(div, c*32-4+index, r*32, ClientImages.applet);
- }
- }
- if (DEBUG) {
- // This draws the integer representing the level of the
- // terrain on the cell. for debugging
- Integer tt = new Integer(terrain);
- g.setColor(Color.black);
- g.drawString(tt.toString(), c*32+10, r*32+20);
- }
- }
- }
- }
-
- /**
- * Return true if there is a conflict occuring at the (r,c)-th
- * cell. This method is used in update() to indicate that two
- * (or more) players are fighting over a cell and that
- * some special fighting graphics and/or sounds should be
- * employed.
- * @param b the board in question
- * @param r the row to check
- * @param c the column to check
- * @param occ the "friendly" occupancy value
- */
- public boolean isConflict(ClientBoard b, int r, int c, int occ) {
-
- if (!Common.isPlayer(occ))
- return false;
-
- Cell cell = null;
- if (r > 0) {
- cell = b.getCell(r-1, c);
- int occ2 = cell.getOccupancy();
- if (cell.getPipe(Symbols.SOUTH) && Common.isPlayer(occ2)
- && occ != occ2 && cell.getTroops() > 0)
- {
- return true;
- }
- }
- if (c > 0) {
- cell = b.getCell(r, c-1);
- int occ2 = cell.getOccupancy();
- if (cell.getPipe(Symbols.EAST) && Common.isPlayer(occ2)
- && occ != occ2 && cell.getTroops() > 0)
- {
- return true;
- }
- }
- if (r < Rules.rows-1) {
- cell = b.getCell(r+1, c);
- int occ2 = cell.getOccupancy();
- if (cell.getPipe(Symbols.NORTH) && Common.isPlayer(occ2)
- && occ != occ2 && cell.getTroops() > 0)
- {
- return true;
- }
- }
- if (c < Rules.cols-1) {
- cell = b.getCell(r, c+1);
- int occ2 = cell.getOccupancy();
- if (cell.getPipe(Symbols.WEST) && Common.isPlayer(occ2)
- && occ != occ2 && cell.getTroops() > 0)
- {
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Update the client graphics for a single turn. Basically goes
- * through each cell on the board and draws troops, cities, and
- * pipes.
- * @param b the board being drawn
- */
- public void update(ClientBoard b) {
- if (count < 10 && count % 3 == 0)
- updateTerrain(b);
- count++;
-
- if (terrainImage == null) {
- if (DEBUG) {
- System.out.println("updating terrain");
- }
- updateTerrain(b);
- }
-
- // Clear the board with the terrain
- offGC.drawImage(terrainImage, 0, 0, ClientImages.applet);
-
- float w = (float)Symbols.BOARD_W / (float)Rules.cols;
- float h = (float)Symbols.BOARD_H / (float)Rules.rows;
- width = (int)w;
- height = (int)h;
-
- // Iterate over all the cells and update
- for (int r=0; r<Rules.rows; r++) {
- for (int c=0; c<Rules.cols; c++) {
- int xorg = (int)(w * (float)c);
- int yorg = (int)(h * (float)r);
- ClientCell cell = (ClientCell)b.getCell(r, c);
- int occ = cell.getOccupancy();
-
- if (occ == Symbols.INVISIBLE) {
- paintInvisible(xorg, yorg);
- } else {
- if (occ != Symbols.UNOCCUPIED) {
- paintTroops(xorg, yorg, occ, cell.getTroops());
- paintPipes(xorg, yorg, cell.getPipeMask(), occ);
- }
- int city = cell.getCity();
- if (city > 0) {
- paintCity(xorg, yorg, city);
- }
- }
- if (isConflict(b, r, c, occ)) {
-
- // possibly play a conflict sound
- if (Math.abs(rand.nextInt()) % 2 == 0)
- ClientSounds.playRandomFight();
-
- int x = c*32 + Math.abs(rand.nextInt()) % 22;
- int y = r*32 + Math.abs(rand.nextInt()) % 22;
- int sof = Math.abs(rand.nextInt()) % 2;
- ClientArcadeAnimator anim = null;
- Image images[] = ClientImages.smoke;
- if (sof == 0)
- images = ClientImages.fire;
- anim = new ClientArcadeAnimator(onGC, x, y, images, 5, 5);
- Thread t = new Thread(anim);
- t.start();
- // I let the thread go and lose all my references
- // to it--which may mean it gets gc'ed. But we don't
- // really care since we really only want it to exist
- // for a second or two.
-
- // possibly draw conflict smudges on the terrain
- // makes the terrain look well fought over
- if (Math.abs(rand.nextInt()) % 4 == 0) {
- Graphics g = terrainImage.getGraphics();
- int idx = Math.abs(rand.nextInt()) % 4;
- g.drawImage(ClientImages.smudge[idx], x, y,
- ClientImages.applet);
- }
-
- }
- }
- }
- }
-
- /**
- * Paint an invisible square in the give location.
- * @param xorg the x location to draw an invisible square
- * @param yorg the y location to draw an invisible square
- */
- void paintInvisible(int xorg, int yorg) {
- if (!DEBUG) {
- offGC.setColor(Color.black);
- offGC.fillRect(xorg, yorg, 32, 32);
- }
- }
-
- /**
- * The standard list of player colors.
- */
- static private final Color playerColor[] = {
- new Color(200, 0, 0),
- new Color(0, 200, 0),
- new Color(0, 0, 100),
- new Color(0, 200, 200),
- new Color(200, 0, 200),
- new Color(200, 200, 0),
- };
-
- /**
- * Paint the given number of troops for the player in the supplied
- * location.
- * @param xorg the x location to draw the troops
- * @param yorg the y location to draw the troops
- * @param player the player occupancy to draw
- * @param troops the number of troops (a percentage from 0-31) to draw.
- */
- void paintTroops(int xorg, int yorg, int player, int troops) {
- float percent = (float)(troops+1) / (float)32.0;
- // float w = (float)width * percent;
- // float h = (float)height * percent;
- float w = (float)24.0 * percent;
- float h = (float)24.0 * percent;
- offGC.setColor(playerColor[player]);
- float x = (float)(width) / (float)2.0 - w/(float)2.0;
- float y = (float)(height) / (float)2.0 - h/(float)2.0;
- offGC.fillRect((int)x+xorg, (int)y+yorg, (int)w, (int)h);
- }
-
- /**
- * Paint a city graphic in the given location.
- * @param xorg the x location to draw the city
- * @param yorg the y location to draw the city
- */
- void paintCity(int xorg, int yorg, int city) {
- // float angle = (float)360 * (float)city/(float)Symbols.MAX_CLIENT_TROOPS;
- if (city == Symbols.MAX_CLIENT_TROOPS) {
- offGC.drawImage(ClientImages.city, xorg, yorg, ClientImages.applet);
- }
- }
-
- /**
- * Paint pipes on a particular cell.
- * @param xorg the x cell origin to paint the pipe
- * @param yorg the y cell origin to paint the pipe
- * @param pipes the flags indicating which pipes are on and off
- * @param player the player (to draw in the correct color)
- */
- void paintPipes(int xorg, int yorg, int pipes, int player) {
- int wh = (int)((float)width / (float)2.0);
- int hh = (int)((float)height / (float)2.0);
- int wa = (int)((float)width / (float)3.0);
- int ha = (int)((float)height / (float)3.0);
- int wb = (int)((float)width * (float)2.0 / (float)3.0);
- int hb = (int)((float)height * (float)2.0 / (float)3.0);
-
- if ((pipes & Symbols.PIPE_MASK[Symbols.NORTH]) != 0) {
- offGC.setColor(Color.black);
- offGC.drawLine(xorg+wh-1, yorg+1, xorg+wh-1, yorg+ha);
- offGC.drawLine(xorg+wh+1, yorg+1, xorg+wh+1, yorg+ha);
- offGC.setColor(playerColor[player]);
- offGC.drawLine(xorg+wh, yorg+1, xorg+wh, yorg+ha);
- }
-
- if ((pipes & Symbols.PIPE_MASK[Symbols.SOUTH]) != 0) {
- offGC.setColor(Color.black);
- offGC.drawLine(xorg+wh-1, yorg+hb, xorg+wh-1, yorg+height-1);
- offGC.drawLine(xorg+wh+1, yorg+hb, xorg+wh+1, yorg+height-1);
- offGC.setColor(playerColor[player]);
- offGC.drawLine(xorg+wh, yorg+hb, xorg+wh, yorg+height-1);
- }
-
- if ((pipes & Symbols.PIPE_MASK[Symbols.EAST]) != 0) {
- offGC.setColor(Color.black);
- offGC.drawLine(xorg+wb, yorg+hh-1, xorg+width, yorg+hh-1);
- offGC.drawLine(xorg+wb, yorg+hh+1, xorg+width, yorg+hh+1);
- offGC.setColor(playerColor[player]);
- offGC.drawLine(xorg+wb, yorg+hh, xorg+width, yorg+hh);
- }
-
- if ((pipes & Symbols.PIPE_MASK[Symbols.WEST]) != 0) {
- offGC.setColor(Color.black);
- offGC.drawLine(xorg+1, yorg+hh-1, xorg+wa, yorg+hh-1);
- offGC.drawLine(xorg+1, yorg+hh+1, xorg+wa, yorg+hh+1);
- offGC.setColor(playerColor[player]);
- offGC.drawLine(xorg+1, yorg+hh, xorg+wa, yorg+hh);
- }
- }
-
- }
-