home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / enxle1f6 / src / games / battle / client / clientapplet / clientlookarcade.java < prev    next >
Encoding:
Java Source  |  1996-08-14  |  14.4 KB  |  507 lines

  1. /*
  2.  * @(#)ClientLookArcade.java
  3.  */
  4.  
  5. package games.Battle.client.ClientApplet;
  6.  
  7. import java.awt.Image;
  8. import java.awt.Graphics;
  9. import java.awt.Color;
  10. import java.awt.Component;
  11. import java.util.Random;
  12.  
  13. import games.Battle.shared.sys.Symbols;
  14. import games.Battle.shared.sys.Rules;
  15. import games.Battle.shared.sys.Board;
  16. import games.Battle.shared.sys.Cell;
  17. import games.Battle.shared.sys.Common;
  18.  
  19. /**
  20.  * ClientLookArcade is a client look that uses a variety of images
  21.  * loaded from the client URL to simulate the contours of the landscape
  22.  * with shadows and hilites, assuming the light source is hitting the
  23.  * land from the upper left hand side of the game board.
  24.  *
  25.  * Hills look like they rise out of the landscape and valleys actually
  26.  * look like they sink into the landscape. 
  27.  *
  28.  * ClientLookArcade implements ClientLook's abstract methods update()
  29.  * and updateTerrain() and adds several supporting methods.
  30.  *
  31.  * @author Alex Nicolaou
  32.  * @author Jay Steele
  33.  */
  34. public class ClientLookArcade extends ClientLook {
  35.  
  36.     static Random rand = new Random();
  37.  
  38.     /**
  39.      * Set to true and recompiled to get visual debugging features.
  40.      */
  41.     static final boolean DEBUG = false;
  42.  
  43.     /**
  44.      * Cached width and height;
  45.      */
  46.     int width, height;
  47.  
  48.     /**
  49.      * Counts the number of updates which have occurred.
  50.      */
  51.     int count = 0;
  52.  
  53.     /**
  54.      * The background terrain image.
  55.      */
  56.     Image terrainImage = null;
  57.  
  58.     /**
  59.      * Construct a ClientLookArcade with the given ClientBoardComponent.
  60.      * @param ClientLookArcade
  61.      */
  62.     public ClientLookArcade(ClientBoardComponent c) {
  63.         super(c);
  64.         terrainImage = component.createImage(Symbols.BOARD_W, Symbols.BOARD_H);
  65.     }
  66.  
  67.     /**
  68.      * North bitmask for getSurroundingWaterMask()
  69.      */
  70.     static final int NORTH = 0x01;
  71.  
  72.     /**
  73.      * South bitmask for getSurroundingWaterMask()
  74.      */
  75.     static final int SOUTH = 0x02;
  76.  
  77.     /**
  78.      * East bitmask for getSurroundingWaterMask()
  79.      */
  80.     static final int EAST = 0x04;
  81.  
  82.     /**
  83.      * West bitmask for getSurroundingWaterMask()
  84.      */
  85.     static final int WEST = 0x08;
  86.  
  87.     /**
  88.      * Return a mask of 4 bits which give information about the water
  89.      * surrounding the given cell. This method says: you have water
  90.      * to your north, south, east or west. 
  91.      * @param board the board containing the cells
  92.      * @param the cell row
  93.      * @param the cell column
  94.      */
  95.     public int getSurroundingWaterMask(Board board, int r, int c) {
  96.         int result = 0;
  97.         if (r > 0 && board.getCell(r-1,c).getTerrain() == 0)
  98.             result |= NORTH;
  99.         if (r < 15 && board.getCell(r+1,c).getTerrain() == 0)
  100.             result |= SOUTH;
  101.         if (c > 0 && board.getCell(r,c-1).getTerrain() == 0)
  102.             result |= WEST;
  103.         if (c < 15 && board.getCell(r,c+1).getTerrain() == 0)
  104.             result |= EAST;
  105.         return result;
  106.     }
  107.  
  108.     /**
  109.      * Return a certain water image based on a mask. The mask
  110.      * represents a value returned from getSurroundingWaterMask().
  111.      * @param mask the mask on which to switch to select the image
  112.      */
  113.     public Image waterImage(int mask) {
  114.         Image result = null;
  115.         switch (mask) {
  116.             case 0:    // No surrounding water
  117.                 int num = Math.abs(rand.nextInt()) % 4;
  118.                 result = ClientImages.water_single[num];
  119.                 break;
  120.             case 1: // N
  121.                 result = ClientImages.water_end[0];
  122.                 break;
  123.             case 2: // S
  124.                 result = ClientImages.water_end[2];
  125.                 break;
  126.             case 3: // NS
  127.                 result = ClientImages.water_straight[0];
  128.                 break;
  129.             case 4: // E
  130.                 result = ClientImages.water_end[1];
  131.                 break;
  132.             case 5: // NE
  133.                 result = ClientImages.water_elbow[0];
  134.                 break;
  135.             case 6: // SE
  136.                 result = ClientImages.water_elbow[1];
  137.                 break;
  138.             case 7: // NSE
  139.                 result = ClientImages.water_t[0];
  140.                 break;
  141.             case 8: // W
  142.                 result = ClientImages.water_end[3];
  143.                 break;
  144.             case 9: // NW
  145.                 result = ClientImages.water_elbow[3];
  146.                 break;
  147.             case 10: // SW
  148.                 result = ClientImages.water_elbow[2];
  149.                 break;
  150.             case 11: // NSW
  151.                 result = ClientImages.water_t[2];
  152.                 break;
  153.             case 12: // EW
  154.                 result = ClientImages.water_straight[1];
  155.                 break;
  156.             case 13: // NEW
  157.                 result = ClientImages.water_t[3];
  158.                 break;
  159.             case 14: // SEW
  160.                 result = ClientImages.water_t[1];
  161.                 break;
  162.             case 15: // NSEW
  163.                 result = ClientImages.water_cross;
  164.                 break;
  165.             default:
  166.                 result = null;
  167.         }
  168.         return result;
  169.     }
  170.  
  171.     /**
  172.      * Update the background terrain image for board b.
  173.      * @param b the board to update the terrain image for
  174.      */
  175.     public void updateTerrain(ClientBoard b) {
  176.         Graphics g = terrainImage.getGraphics();
  177.         for (int i=0; i<4; i++) {
  178.             for (int j=0; j<4; j++) {
  179.                 if (ClientImages.earth != null)
  180.                     g.drawImage(ClientImages.earth, i*128, j*128, 
  181.                                 ClientImages.applet);
  182.             }
  183.         }
  184.  
  185.         for (int r=0; r< Rules.rows; r++) {
  186.             for (int c=0; c< Rules.cols; c++) {
  187.                 int terrain = b.getCell(r, c).getTerrain();
  188.                 if (terrain == 0) {
  189.                     int mask = getSurroundingWaterMask(b, r, c);
  190.                     g.drawImage(waterImage(mask), c*32, r*32, 
  191.                                 ClientImages.applet);
  192.                     if (DEBUG) {
  193.                         g.setColor(Color.darkGray);
  194.                         g.fillRect(c*32+6, r*32+6, 20, 20);
  195.                     }
  196.  
  197.                     // fill in the center of black of 4 water
  198.                     if (r > 0 && c > 0) {
  199.                         int t_nw = b.getCell(r-1, c-1).getTerrain();
  200.                         int t_n  = b.getCell(r-1, c).getTerrain();
  201.                         int t_w  = b.getCell(r, c-1).getTerrain();
  202.                         if (t_nw == 0 && t_n == 0 && t_w == 0) {
  203.                             g.drawImage(ClientImages.water_single[0],
  204.                                         c*32-16, r*32-16, ClientImages.applet);
  205.                         }
  206.                     }
  207.                 }
  208.                 if (r > 0) {
  209.                     int terrainAbove = b.getCell(r-1, c).getTerrain();
  210.                     int diff = terrain - terrainAbove;
  211.                     if (diff != 0) {
  212.                         if (terrain == 0) {
  213.                             diff = diff + 1;
  214.                         } else if (terrainAbove == 0) {
  215.                             diff = diff - 1;
  216.                         }
  217.                     }
  218.                     if (diff != 0) {
  219.                         Image div = null;
  220.                         int index = 4-Math.abs(diff);
  221.                         if (index < 0) index = 0;
  222.                         if (diff > 0) {
  223.                             div = ClientImages.hilite_h[index];
  224.                         } else {
  225.                             div = ClientImages.shadow_h[index];
  226.                         }
  227.                         g.drawImage(div, c*32, r*32-4+index, ClientImages.applet);
  228.                     }
  229.                 }
  230.                 if (c > 0) {
  231.                     int terrainLeft = b.getCell(r, c-1).getTerrain();
  232.                     int diff = terrain - terrainLeft;
  233.                     if (diff != 0) {
  234.                         if (terrain == 0) {
  235.                             diff = diff + 1;
  236.                         } else if (terrainLeft == 0) {
  237.                             diff = diff - 1;
  238.                         }
  239.                     }
  240.                     if (diff != 0)
  241.                     {
  242.                         Image div = null;
  243.                         int index = 4-Math.abs(diff);
  244.                         if (index < 0) index = 0;
  245.                         if (diff > 0) {
  246.                             div = ClientImages.hilite_v[index];
  247.                         } else {
  248.                             div = ClientImages.shadow_v[index];
  249.                         }
  250.                         g.drawImage(div, c*32-4+index, r*32, ClientImages.applet);
  251.                     }
  252.                 }
  253.                 if (DEBUG) {
  254.                     // This draws the integer representing the level of the
  255.                     // terrain on the cell. for debugging
  256.                     Integer tt = new Integer(terrain);
  257.                     g.setColor(Color.black);
  258.                     g.drawString(tt.toString(), c*32+10, r*32+20);
  259.                 }
  260.             }
  261.         }
  262.     }
  263.  
  264.     /**
  265.      * Return true if there is a conflict occuring at the (r,c)-th
  266.      * cell. This method is used in update() to indicate that two
  267.      * (or more) players are fighting over a cell and that 
  268.      * some special fighting graphics and/or sounds should be 
  269.      * employed.
  270.      * @param b the board in question
  271.      * @param r the row to check
  272.      * @param c the column to check
  273.      * @param occ the "friendly" occupancy value
  274.      */
  275.     public boolean isConflict(ClientBoard b, int r, int c, int occ) {
  276.  
  277.         if (!Common.isPlayer(occ))
  278.             return false;
  279.  
  280.         Cell cell = null;
  281.         if (r > 0) {
  282.             cell = b.getCell(r-1, c);
  283.             int occ2 = cell.getOccupancy();
  284.             if (cell.getPipe(Symbols.SOUTH) && Common.isPlayer(occ2)
  285.                 && occ != occ2 && cell.getTroops() > 0)
  286.             {
  287.                 return true;
  288.             }
  289.         }
  290.         if (c > 0) {
  291.             cell = b.getCell(r, c-1);
  292.             int occ2 = cell.getOccupancy();
  293.             if (cell.getPipe(Symbols.EAST) && Common.isPlayer(occ2)
  294.                 && occ != occ2 && cell.getTroops() > 0)
  295.             {
  296.                 return true;
  297.             }
  298.         }
  299.         if (r < Rules.rows-1) {
  300.             cell = b.getCell(r+1, c);
  301.             int occ2 = cell.getOccupancy();
  302.             if (cell.getPipe(Symbols.NORTH) && Common.isPlayer(occ2)
  303.                 && occ != occ2 && cell.getTroops() > 0)
  304.             {
  305.                 return true;
  306.             }
  307.         }
  308.         if (c < Rules.cols-1) {
  309.             cell = b.getCell(r, c+1);
  310.             int occ2 = cell.getOccupancy();
  311.             if (cell.getPipe(Symbols.WEST) && Common.isPlayer(occ2)
  312.                 && occ != occ2 && cell.getTroops() > 0)
  313.             {
  314.                 return true;
  315.             }
  316.         }
  317.         return false;
  318.     }
  319.  
  320.  
  321.     /**
  322.      * Update the client graphics for a single turn. Basically goes
  323.      * through each cell on the board and draws troops, cities, and
  324.      * pipes.
  325.      * @param b the board being drawn
  326.      */
  327.     public void update(ClientBoard b) {
  328.         if (count < 10 && count % 3 == 0)
  329.             updateTerrain(b);
  330.         count++;
  331.  
  332.         if (terrainImage == null) {
  333.             if (DEBUG) {
  334.                 System.out.println("updating terrain");
  335.             }
  336.             updateTerrain(b);
  337.         }
  338.  
  339.         // Clear the board with the terrain
  340.         offGC.drawImage(terrainImage, 0, 0, ClientImages.applet);
  341.  
  342.         float w = (float)Symbols.BOARD_W / (float)Rules.cols;
  343.         float h = (float)Symbols.BOARD_H / (float)Rules.rows;
  344.         width = (int)w;
  345.         height = (int)h;
  346.  
  347.         // Iterate over all the cells and update
  348.         for (int r=0; r<Rules.rows; r++) {
  349.             for (int c=0; c<Rules.cols; c++) {
  350.                 int xorg = (int)(w * (float)c);
  351.                 int yorg = (int)(h * (float)r);
  352.                 ClientCell cell = (ClientCell)b.getCell(r, c);
  353.                 int occ = cell.getOccupancy();
  354.  
  355.                 if (occ == Symbols.INVISIBLE) {
  356.                     paintInvisible(xorg, yorg);
  357.                 } else {
  358.                     if (occ != Symbols.UNOCCUPIED) {
  359.                         paintTroops(xorg, yorg, occ, cell.getTroops());
  360.                         paintPipes(xorg, yorg, cell.getPipeMask(), occ);
  361.                     }
  362.                     int city = cell.getCity();
  363.                     if (city > 0) {
  364.                         paintCity(xorg, yorg, city);
  365.                     }
  366.                 }
  367.                 if (isConflict(b, r, c, occ)) {
  368.  
  369.                     // possibly play a conflict sound
  370.                     if (Math.abs(rand.nextInt()) % 2 == 0)
  371.                         ClientSounds.playRandomFight();
  372.  
  373.                     int x = c*32 + Math.abs(rand.nextInt()) % 22;
  374.                     int y = r*32 + Math.abs(rand.nextInt()) % 22;
  375.                     int sof = Math.abs(rand.nextInt()) % 2;
  376.                     ClientArcadeAnimator anim = null;
  377.                     Image images[] = ClientImages.smoke;
  378.                     if (sof == 0)
  379.                         images = ClientImages.fire;
  380.                     anim = new ClientArcadeAnimator(onGC, x, y, images, 5, 5);
  381.                     Thread t = new Thread(anim);
  382.                     t.start();
  383.                     // I let the thread go and lose all my references
  384.                     // to it--which may mean it gets gc'ed. But we don't
  385.                     // really care since we really only want it to exist
  386.                     // for a second or two.
  387.  
  388.                     // possibly draw conflict smudges on the terrain
  389.                     // makes the terrain look well fought over
  390.                     if (Math.abs(rand.nextInt()) % 4 == 0) {
  391.                         Graphics g = terrainImage.getGraphics();
  392.                         int idx = Math.abs(rand.nextInt()) % 4;
  393.                         g.drawImage(ClientImages.smudge[idx], x, y, 
  394.                                     ClientImages.applet);
  395.                     }
  396.  
  397.                 }
  398.             }
  399.         }
  400.     }
  401.  
  402.     /**
  403.      * Paint an invisible square in the give location.
  404.      * @param xorg the x location to draw an invisible square
  405.      * @param yorg the y location to draw an invisible square
  406.      */
  407.     void paintInvisible(int xorg, int yorg) {
  408.         if (!DEBUG) {
  409.             offGC.setColor(Color.black);
  410.             offGC.fillRect(xorg, yorg, 32, 32);
  411.         }
  412.     }
  413.  
  414.     /**
  415.      * The standard list of player colors.
  416.      */
  417.     static private final Color playerColor[] = {
  418.         new Color(200, 0, 0),
  419.         new Color(0, 200, 0),
  420.         new Color(0, 0, 100),
  421.         new Color(0, 200, 200),
  422.         new Color(200, 0, 200),
  423.         new Color(200, 200, 0),
  424.     };
  425.  
  426.     /**
  427.      * Paint the given number of troops for the player in the supplied
  428.      * location.
  429.      * @param xorg the x location to draw the troops
  430.      * @param yorg the y location to draw the troops
  431.      * @param player the player occupancy to draw
  432.      * @param troops the number of troops (a percentage from 0-31) to draw.
  433.      */
  434.     void paintTroops(int xorg, int yorg, int player, int troops) {
  435.         float percent = (float)(troops+1) / (float)32.0;
  436.         // float w = (float)width * percent;
  437.         // float h = (float)height * percent;
  438.         float w = (float)24.0 * percent;
  439.         float h = (float)24.0 * percent;
  440.         offGC.setColor(playerColor[player]);
  441.         float x = (float)(width) / (float)2.0 - w/(float)2.0;
  442.         float y = (float)(height) / (float)2.0 - h/(float)2.0;
  443.         offGC.fillRect((int)x+xorg, (int)y+yorg, (int)w, (int)h);
  444.     }
  445.  
  446.     /**
  447.      * Paint a city graphic in the given location.
  448.      * @param xorg the x location to draw the city
  449.      * @param yorg the y location to draw the city
  450.      */
  451.     void paintCity(int xorg, int yorg, int city) {
  452.         // float angle = (float)360 * (float)city/(float)Symbols.MAX_CLIENT_TROOPS;
  453.         if (city == Symbols.MAX_CLIENT_TROOPS) {
  454.             offGC.drawImage(ClientImages.city, xorg, yorg, ClientImages.applet);
  455.         }
  456.     }
  457.  
  458.     /**
  459.      * Paint pipes on a particular cell.
  460.      * @param xorg the x cell origin to paint the pipe
  461.      * @param yorg the y cell origin to paint the pipe
  462.      * @param pipes the flags indicating which pipes are on and off
  463.      * @param player the player (to draw in the correct color)
  464.      */
  465.     void paintPipes(int xorg, int yorg, int pipes, int player) {
  466.         int wh = (int)((float)width / (float)2.0);
  467.         int hh = (int)((float)height / (float)2.0);
  468.         int wa = (int)((float)width / (float)3.0);
  469.         int ha = (int)((float)height / (float)3.0);
  470.         int wb = (int)((float)width * (float)2.0 / (float)3.0);
  471.         int hb = (int)((float)height * (float)2.0 / (float)3.0);
  472.  
  473.         if ((pipes & Symbols.PIPE_MASK[Symbols.NORTH]) != 0) {
  474.             offGC.setColor(Color.black);
  475.             offGC.drawLine(xorg+wh-1, yorg+1, xorg+wh-1, yorg+ha);
  476.             offGC.drawLine(xorg+wh+1, yorg+1, xorg+wh+1, yorg+ha);
  477.             offGC.setColor(playerColor[player]);
  478.             offGC.drawLine(xorg+wh, yorg+1, xorg+wh, yorg+ha);
  479.         }
  480.  
  481.         if ((pipes & Symbols.PIPE_MASK[Symbols.SOUTH]) != 0) {
  482.             offGC.setColor(Color.black);
  483.             offGC.drawLine(xorg+wh-1, yorg+hb, xorg+wh-1, yorg+height-1);
  484.             offGC.drawLine(xorg+wh+1, yorg+hb, xorg+wh+1, yorg+height-1);
  485.             offGC.setColor(playerColor[player]);
  486.             offGC.drawLine(xorg+wh, yorg+hb, xorg+wh, yorg+height-1);
  487.         }
  488.  
  489.         if ((pipes & Symbols.PIPE_MASK[Symbols.EAST]) != 0) {
  490.             offGC.setColor(Color.black);
  491.             offGC.drawLine(xorg+wb, yorg+hh-1, xorg+width, yorg+hh-1);
  492.             offGC.drawLine(xorg+wb, yorg+hh+1, xorg+width, yorg+hh+1);
  493.             offGC.setColor(playerColor[player]);
  494.             offGC.drawLine(xorg+wb, yorg+hh, xorg+width, yorg+hh);
  495.         }
  496.  
  497.         if ((pipes & Symbols.PIPE_MASK[Symbols.WEST]) != 0) {
  498.             offGC.setColor(Color.black);
  499.             offGC.drawLine(xorg+1, yorg+hh-1, xorg+wa, yorg+hh-1);
  500.             offGC.drawLine(xorg+1, yorg+hh+1, xorg+wa, yorg+hh+1);
  501.             offGC.setColor(playerColor[player]);
  502.             offGC.drawLine(xorg+1, yorg+hh, xorg+wa, yorg+hh);
  503.         }
  504.     }
  505.  
  506. }
  507.