home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1997 October / PCO1097.ISO / FilesBBS / FREI / MCII.EXE / MissileCommando.java < prev    next >
Encoding:
Java Source  |  1996-10-03  |  15.7 KB  |  838 lines

  1. /* MissileCommando.java - based on the arcade game Missile Command. */
  2.  
  3. /* 
  4.  * Copyright (C) 1996 Mark Boyns <boyns@sdsu.edu>
  5.  *
  6.  * Missile Commando II
  7.  * <URL:http://www.sdsu.edu/~boyns/java/mcii/>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. import java.applet.Applet;
  25. import java.applet.AudioClip;
  26. import java.util.*;
  27. import java.awt.*;
  28.  
  29. public
  30. class MissileCommando extends java.applet.Applet implements Runnable
  31. {
  32.     final String version = "MCII 1.1";
  33.     final int worldWidth = 500;
  34.     final int worldHeight = 300;
  35.     final int scoreHeight = 25;
  36.     final int controlsHeight = 50;
  37.     final int screenWidth = worldWidth;
  38.     final int screenHeight = worldHeight + scoreHeight + controlsHeight;
  39.     
  40.     final int baseWidth = 64;
  41.     final int baseHeight = 32;
  42.     final int baseGap = 30;
  43.     final int maxBases = 5;
  44.  
  45.     final int missilePoints = 75;
  46.     final int mrvPoints = 150;
  47.     final int bombPoints = 0;
  48.     final int extraShotPoints = 10;
  49.     final int extraBasePoints = 50;
  50.     final int rebuildBasePoints = 10000;
  51.  
  52.     AudioClip missileSound = null;
  53.     AudioClip missileExplosionSound = null;
  54.     AudioClip mrvExplosionSound = null;
  55.     AudioClip baseExplosionSound = null;
  56.     AudioClip bombSound = null;
  57.  
  58.     boolean playing = false;
  59.     boolean readyToPlay = false;
  60.     boolean clearScreen = false;
  61.     boolean paused = false;
  62.     boolean soundEnabled = true;
  63.     
  64.     Thread thread = null;
  65.     GameObjectMover mover = null;
  66.  
  67.     Controls controls;
  68.  
  69.     Vector bases;
  70.     Vector missiles;
  71.     Vector shots;
  72.     Vector mrvs;
  73.     Vector explosions;
  74.     Vector bombs;
  75.     Vector bombDebris;
  76.  
  77.     int score = 0;
  78.     int extraBaseScore = 0;
  79.     int level = 0;
  80.     
  81.     int shotCount = 0;
  82.     int missileCount = 0;
  83.     int missileSpeed = 0;
  84.     int missileDelay = 0;
  85.     int mrvSpeed = 0;
  86.     int bombSpeed = 0;
  87.  
  88.     Color skyColor = new Color (148, 198, 231);
  89.     Graphics world = null;
  90.  
  91.     MediaTracker tracker;
  92.     Image baseImage;
  93.     Image mrvImage;
  94.     Image bombImage;
  95.  
  96.     Font font;
  97.     FontMetrics fontMetrics;
  98.  
  99.     String screenMessage;
  100.  
  101.     public
  102.     void init ()
  103.     {
  104.     int i, x;
  105.  
  106.     font = new Font ("TimesRoman", Font.BOLD, 20);
  107.     fontMetrics = getFontMetrics (font);
  108.     setFont (font);
  109.  
  110.     tracker = new MediaTracker (this);
  111.     baseImage = getImage (getDocumentBase (), "images/base.gif");
  112.     tracker.addImage (baseImage, 1);
  113.     mrvImage = getImage (getDocumentBase (), "images/mrv.gif");
  114.     tracker.addImage (mrvImage, 1);
  115.     bombImage = getImage (getDocumentBase (), "images/bomb.gif");
  116.     tracker.addImage (bombImage, 1);
  117.  
  118.     /* Load all the sounds. */
  119.     missileSound = getAudioClip (getDocumentBase (), "sounds/Rocket.au");
  120.     missileExplosionSound = getAudioClip (getDocumentBase (), "sounds/Oomph.au");
  121.     mrvExplosionSound = getAudioClip (getDocumentBase (), "sounds/Oomph.au");
  122.     baseExplosionSound = getAudioClip (getDocumentBase (), "sounds/Explosion-2.au");
  123.     bombSound = getAudioClip (getDocumentBase (), "sounds/ship_alarm.au");
  124.  
  125.     setBackground (Color.white);
  126.  
  127.     setLayout (new BorderLayout ());
  128.     controls = new Controls (this);
  129.     add ("South", controls);
  130.  
  131.     resize (screenWidth, screenHeight);
  132.  
  133.     /* Start the game! */
  134.     thread = new Thread (this);
  135.     thread.start ();
  136.     }
  137.  
  138.     public
  139.     void start ()
  140.     {
  141.     if (thread == null)
  142.     {
  143.         thread = new Thread (this);
  144.         thread.start ();
  145.     }
  146.     }
  147.  
  148.     public
  149.     void stop ()
  150.     {
  151.     if (thread != null && thread.isAlive ())
  152.     {
  153.         thread.stop ();
  154.         thread = null;
  155.     }
  156.     if (mover != null && mover.isAlive ())
  157.     {
  158.         mover.stop ();
  159.         mover = null;
  160.     }
  161.     }
  162.     
  163.     public
  164.     boolean mouseDown (Event e, int x, int y)
  165.     {
  166.     if (playing)
  167.     {
  168.         createShot (x, y - scoreHeight);
  169.     }
  170.     return true;
  171.     }
  172.  
  173.     void startGame ()
  174.     {
  175.     readyToPlay = true;
  176.     }
  177.  
  178.     void quitGame ()
  179.     {
  180.     playing = false;
  181.     }
  182.     
  183.     void resetScore ()
  184.     {
  185.     clearScreen = true;
  186.     
  187.     score = 0;
  188.     extraBaseScore = 0;
  189.     level = 0;
  190.  
  191.     message (null);
  192.     }
  193.     
  194.     void resetGame ()
  195.     {
  196.     clearScreen = true;
  197.     
  198.     missiles = new Vector (100);
  199.     shots = new Vector (100);
  200.     mrvs = new Vector (100);
  201.     explosions = new Vector (100);
  202.     bombs = new Vector (100);
  203.     bombDebris = new Vector (100);
  204.  
  205.     //controls.playButton.setLabel ("Start");
  206.     //controls.suspendButton.setLabel ("Suspend");
  207.     //controls.soundButton.setLabel ("Sound Off");
  208.         
  209.     createBases ();
  210.     message (null);
  211.     }
  212.  
  213.     void suspendGame ()
  214.     {
  215.     if (thread != null && playing)
  216.     {
  217.         thread.suspend ();
  218.         if (mover != null && mover.isAlive ())
  219.         {
  220.         mover.suspend ();
  221.         }
  222.         paused = true;
  223.         clearScreen = true;
  224.         repaint ();
  225.     }
  226.     }
  227.  
  228.     void resumeGame ()
  229.     {
  230.     if (thread != null && playing)
  231.     {
  232.         thread.resume ();
  233.         if (mover != null && mover.isAlive ())
  234.         {
  235.         mover.resume ();
  236.         }
  237.         paused = false;
  238.         clearScreen = true;
  239.     }
  240.     }
  241.  
  242.     void enableSound ()
  243.     {
  244.     soundEnabled = true;
  245.     }
  246.     
  247.     void disableSound ()
  248.     {
  249.     soundEnabled = false;
  250.     }
  251.     
  252.     public
  253.     void run ()
  254.     {
  255.     showStatus ("Loading images...");
  256.      tracker.checkAll (true);
  257.      try
  258.      {
  259.          tracker.waitForAll ();
  260.      }
  261.      catch (Exception e)
  262.      {
  263.          return;
  264.      }
  265.     showStatus ("");
  266.  
  267.     resetGame ();
  268.     resetScore ();
  269.  
  270.     for (;;)
  271.     {
  272.         if (!playing && readyToPlay)
  273.         {
  274.         resetGame ();
  275.         resetScore ();
  276.         playing = true;
  277.         readyToPlay = false;
  278.         }
  279.  
  280.         if (playing)
  281.         {
  282.         level++;
  283.         }
  284.         else if (level == 0)
  285.         {
  286.         level = 1;
  287.         }
  288.         
  289.         /* Set the delay between missiles. */
  290.         if (playing)
  291.         {
  292.         missileDelay = 2000 - ((level-1)*200);
  293.         if (missileDelay < 500)
  294.         {
  295.             missileDelay = 500;
  296.         }
  297.         }
  298.         else
  299.         {
  300.         missileDelay = 500;
  301.         }
  302.  
  303.         /* Set the missile speed. */
  304.         missileSpeed = 5;
  305.  
  306.         /* Set the MRV speed. */
  307.         mrvSpeed = 6;
  308.  
  309.         /* Set the bomb speed. */
  310.         bombSpeed = 4;
  311.  
  312.         /* Set the number of missiles to be fired. */
  313.         missileCount = 5 + ((level-1) * 5);
  314.  
  315.         /* Set the maximum number of shots. */
  316.         shotCount = missileCount * 2; // + missileCount/2;
  317.  
  318.         /* Display the new level message. */
  319.         message ("Level " + level);
  320.         try
  321.         {
  322.         Thread.sleep (3000);
  323.         }
  324.         catch (Exception e)
  325.         {
  326.         }
  327.         message (null);
  328.  
  329.         /* Start the object mover thread to move all the
  330.            game objects. */
  331.         mover = new GameObjectMover (100, this);
  332.         mover.start ();
  333.  
  334.         while (missileCount > 0)
  335.         {
  336.         /* Fire a missile. */
  337.         int speed = missileSpeed;
  338.         if (level > 1 && Math.random () > 0.75)
  339.         {
  340.             speed += (int) (Math.random () * missileSpeed);
  341.         }
  342.         createMissile (speed);
  343.         missileCount--;
  344.  
  345.         /* Maybe create a mrv. */
  346.         if (mrvs.size () < level)
  347.         {
  348.             double chance = Math.random ();
  349.             if (chance > 0.70)
  350.             {
  351.             createMRV (mrvSpeed);
  352.             }
  353.         }
  354.  
  355.         /* Maybe drop a bomb. */
  356.         if (level > 1 && bombs.size () < 2)
  357.         {
  358.             double chance = Math.random ();
  359.             if (chance > 0.85)
  360.             {
  361.             createBomb (bombSpeed);
  362.             }
  363.         }
  364.  
  365.         if (!playing)
  366.         {
  367.             starWars ();
  368.         }
  369.  
  370.         if (!playing && readyToPlay)
  371.         {
  372.             break;
  373.         }
  374.         
  375.         try
  376.         {
  377.             Thread.sleep (missileDelay);
  378.         }
  379.         catch (Exception e)
  380.         {
  381.         }
  382.         }
  383.  
  384.         if (!playing && readyToPlay)
  385.         {
  386.         mover.stop ();
  387.         continue;
  388.         }
  389.         
  390.         /* Wait for everything to disappear. */
  391.         while (missiles.size () > 0
  392.            || mrvs.size () > 0
  393.            || explosions.size () > 0
  394.            || bombs.size () > 0
  395.            || bombDebris.size () > 0
  396.            || shots.size () > 0)
  397.         {
  398.         if (!playing && readyToPlay)
  399.         {
  400.             break;
  401.         }
  402.         if (!playing && (missiles.size () > 0 || mrvs.size () > 0 || bombs.size () > 0))
  403.         {
  404.             starWars ();
  405.         }
  406.         try
  407.         {
  408.             Thread.sleep (500);
  409.         }
  410.         catch (Exception e)
  411.         {
  412.         }
  413.         }
  414.  
  415.         /* Stop the object mover thread. */
  416.         mover.stop ();
  417.  
  418.         /* Calculate bonus points. */
  419.         int bonus = shotCount * extraShotPoints;
  420.         bonus += countAliveBases () * extraBasePoints;
  421.         incrementScore (bonus);
  422.  
  423.         if (playing)
  424.         {
  425.         /* Display the bonus points message. */
  426.         message ("Bonus: " + bonus);
  427.         try
  428.         {
  429.             Thread.sleep (2000);
  430.         }
  431.         catch (Exception e)
  432.         {
  433.         }
  434.         message (null);
  435.         }
  436.  
  437.         /* Possibly rebuild any destroyed bases. */
  438.         rebuildBases ();
  439.  
  440.         /* The game is over when no bases are left. */
  441.         if (countAliveBases () == 0)
  442.         {
  443.         playing = false;
  444.  
  445.         /* Destroy the world. */
  446.         mover = new GameObjectMover (400, this);
  447.         mover.start ();
  448.         destroyWorld ();
  449.         while (explosions.size () > 0)
  450.         {
  451.             try
  452.             {
  453.             Thread.sleep (500);
  454.             }
  455.             catch (Exception e)
  456.             {
  457.             }
  458.         }
  459.         mover.stop ();
  460.  
  461.         resetGame ();
  462.         }
  463.     }
  464.     }
  465.  
  466.     void starWarsFireAt (Vector v)
  467.     {
  468.     int x, y;
  469.     Enumeration objs = v.elements ();
  470.     while (objs.hasMoreElements ())
  471.     {
  472.         GameObject o = (GameObject) objs.nextElement ();
  473.         if (o instanceof Missile)
  474.         {
  475.         Missile m = (Missile) o;
  476.         x = (int) m.x;
  477.         y = (int) m.y;
  478.         }
  479.         else if (o instanceof MRV)
  480.         {
  481.         MRV m = (MRV) o;
  482.         x = m.x;
  483.         y = m.y;
  484.         }
  485.         else if (o instanceof Bomb)
  486.         {
  487.         Bomb b = (Bomb) o;
  488.         x = b.x;
  489.         y = b.y;
  490.         }
  491.         else
  492.         {
  493.         x = worldWidth/2;
  494.         y = worldHeight/2;
  495.         }
  496.         
  497.         if (y > worldHeight/5)
  498.         {
  499.         int d;
  500.         if (Math.random () > 0.5)
  501.         {
  502.             d = 1;
  503.         }
  504.         else
  505.         {
  506.             d = -1;
  507.         }
  508.         shots.addElement (new Shot (x+d*(int)(Math.random ()*40),
  509.                         y+d*(int)(Math.random ()*40),
  510.                         60));
  511.         }
  512.     }
  513.  
  514.     }
  515.     
  516.     void starWars ()
  517.     {
  518.     starWarsFireAt (missiles);
  519.     starWarsFireAt (mrvs);
  520.     starWarsFireAt (bombs);
  521.     }
  522.     
  523.     void createShot (int x, int y)
  524.     {
  525.     if (shotCount > 0)
  526.     {
  527.         shots.addElement (new Shot (x, y, 60));
  528.         shotCount--;
  529.     }
  530.     }
  531.  
  532.     void createMissile (int x1, int y1, int speed)
  533.     {
  534.     int x2 = baseGap + (int) (Math.random () * (worldWidth - baseGap));
  535.     int y2 = worldHeight - 1;
  536.     
  537.     if (soundEnabled && missileSound != null && playing)
  538.     {
  539.         missileSound.play ();
  540.     }
  541.     
  542.     missiles.addElement (new Missile (x1, y1, x2, y2, speed));
  543.     }
  544.  
  545.     void createMissile (int speed)
  546.     {
  547.     int x1 = (int) (Math.random () * worldWidth);
  548.     int y1 = 1;
  549.     createMissile (x1, y1, speed);
  550.     }
  551.  
  552.     void destroyMissile (Missile m)
  553.     {
  554.     if (soundEnabled && missileExplosionSound != null && playing)
  555.     {
  556.         missileExplosionSound.play ();
  557.     }
  558.     m.explode ();
  559.     createExplosion ((int)m.x, (int)m.y, 20);
  560.     incrementScore (missilePoints);
  561.     }
  562.  
  563.     void createMRV (int speed)
  564.     {
  565.     int x1 = (int) (Math.random () * worldWidth);
  566.     int y1 = 1;
  567.     int y2 = worldHeight - 1;
  568.  
  569.     mrvs.addElement (new MRV (x1, y1, y2, speed, mrvImage, this));
  570.     }
  571.  
  572.     void destroyMRV (MRV m)
  573.     {
  574.     if (soundEnabled && mrvExplosionSound != null && playing)
  575.     {
  576.         mrvExplosionSound.play ();
  577.     }
  578.     m.explode ();
  579.     createExplosion (m.x, m.y, 10);
  580.     incrementScore (mrvPoints);
  581.     }
  582.  
  583.     void createBomb (int speed)
  584.     {
  585.     if (soundEnabled && bombSound != null && playing)
  586.     {
  587.         bombSound.play ();
  588.     }
  589.     
  590.     int x1 = (int) (Math.random () * worldWidth);
  591.     int y1 = 1;
  592.     int y2 = worldHeight - 1;
  593.  
  594.     bombs.addElement (new Bomb (x1, y1, x1, y2, speed, bombImage, this));
  595.     }
  596.  
  597.     void destroyBomb (Bomb b)
  598.     {
  599.     b.explode ();
  600.     createBombDebris (b.x, b.y);
  601.     }
  602.  
  603.     void createBombDebris (int x, int y)
  604.     {
  605.     bombDebris.addElement (new BombDebris (x, y, 200));
  606.     }
  607.  
  608.     void createBases ()
  609.     {
  610.     bases = new Vector (maxBases);
  611.     for (int i = 0, x = baseGap; i < maxBases; i++)
  612.     {
  613.         bases.addElement (new Base (x, worldHeight - baseHeight,
  614.                     baseWidth, baseHeight, baseImage, this));
  615.         x += baseWidth + baseGap;
  616.     }
  617.     }
  618.  
  619.     int countAliveBases ()
  620.     {
  621.     int count = 0;
  622.     for (int i = 0; i < maxBases; i++)
  623.     {
  624.         Base b = (Base) bases.elementAt (i);
  625.         if (b.alive ())
  626.         {
  627.         count++;
  628.         }
  629.     }
  630.     return count;
  631.     }
  632.  
  633.     void destroyBase (Base b, Missile m)
  634.     {
  635.     if (soundEnabled && baseExplosionSound != null && playing)
  636.     {
  637.         baseExplosionSound.play ();
  638.     }
  639.     m.explode ();
  640.     b.explode ();
  641.     createExplosion ((int)m.x, (int)m.y, 100);
  642.     }
  643.     
  644.     void destroyBase (Base b, MRV m)
  645.     {
  646.     if (soundEnabled && baseExplosionSound != null && playing)
  647.     {
  648.         baseExplosionSound.play ();
  649.     }
  650.     m.explode ();
  651.     b.explode ();
  652.     createExplosion (m.x, m.y, 100);
  653.     }
  654.  
  655.     void destroyBase (Base b, BombDebris debris)
  656.     {
  657.     if (soundEnabled && baseExplosionSound != null && playing)
  658.     {
  659.         baseExplosionSound.play ();
  660.     }
  661.     b.explode ();
  662.     createExplosion (b.x + b.w/2,
  663.              b.y + b.h/2, 100);
  664.     }
  665.  
  666.     void rebuildBases ()
  667.     {
  668.     int order[] = new int[maxBases];
  669.     int i;
  670.  
  671.     for (i = 0; i < order.length; i++)
  672.     {
  673.         order[i] = -1;
  674.     }
  675.     
  676.     for (i = 0; i < maxBases; i++)
  677.     {
  678.         int n = (int) (Math.random () * maxBases);
  679.         while (order[n] != -1)
  680.         {
  681.         n++;
  682.         if (n == maxBases)
  683.         {
  684.             n = 0;
  685.         }
  686.         }
  687.         order[n] = i;
  688.     }
  689.  
  690.     for (i = 0; i < maxBases; i++)
  691.     {
  692.         Base b = (Base) bases.elementAt (order[i]);
  693.         if (! b.alive ())
  694.         {
  695.         if (extraBaseScore >= rebuildBasePoints)
  696.         {
  697.             extraBaseScore -= rebuildBasePoints;
  698.             b.rebuild ();
  699.         }
  700.         }
  701.     }
  702.     }
  703.     
  704.     void createExplosion (int x, int y, int size)
  705.     {
  706.     explosions.addElement (new Explosion (x, y, size));
  707.     }
  708.  
  709.     void incrementScore (int points)
  710.     {
  711.     if (playing)
  712.     {
  713.         score += points;
  714.         extraBaseScore += points;
  715.     }
  716.     }
  717.  
  718.     void destroyWorld ()
  719.     {
  720.     for (int i = 0; i < 10; i++)
  721.     {
  722.         int x = (int)(Math.random () * worldWidth);
  723.         int y = (int)(Math.random () * worldHeight);
  724.         createExplosion (x, y, 100);
  725.     }
  726.     }
  727.     
  728.     public
  729.     void update (Graphics g)
  730.     {
  731.     paint (g);
  732.     }
  733.  
  734.     void paintGameObjects (Vector objs, Graphics g)
  735.     {
  736.     if (objs == null)
  737.     {
  738.         return;
  739.     }
  740.     
  741.     Enumeration e = objs.elements ();
  742.     while (e.hasMoreElements ())
  743.     {
  744.         GameObject o = (GameObject) e.nextElement ();
  745.         o.paint (g);
  746.     }
  747.     }
  748.  
  749.     void message (String message)
  750.     {
  751.     if (message != null)
  752.     {
  753.         screenMessage = message;
  754.     }
  755.     else
  756.     {
  757.         screenMessage = null;
  758.         clearScreen = true;
  759.     }
  760.     repaint ();
  761.     }
  762.     
  763.     void paintMessage (String message, Graphics g)
  764.     {
  765.     int h = fontMetrics.getHeight ();
  766.     int w = fontMetrics.stringWidth (message);
  767.     g.setColor (Color.black);
  768.     g.drawString (message, worldWidth/2 - w/2, worldHeight/2);
  769.     }
  770.     
  771.     void paintStatus (Graphics g)
  772.     {
  773.     StringBuffer s = new StringBuffer ();
  774.     s.append ("Score: ");
  775.     s.append (score);
  776.     s.append (" Level: ");
  777.     s.append (level);
  778.     s.append (" Shots: ");
  779.     s.append (shotCount);
  780.  
  781.     int h = fontMetrics.getHeight ();
  782.     int w = fontMetrics.stringWidth (s.toString ());
  783.     int n = screenWidth/2 - w/2;
  784.  
  785.     g.setColor (Color.white);
  786.     g.fillRect (0, 0, screenWidth, scoreHeight);
  787.     
  788.     g.setColor (Color.black);
  789.     g.drawString (s.toString (), n, h);
  790.  
  791.     w = fontMetrics.stringWidth (version);
  792.     g.drawString (version, screenWidth - w, h);
  793.     }
  794.     
  795.     public
  796.     void paint (Graphics g)
  797.     {
  798.     if (world == null)
  799.     {
  800.         world = g.create (0, scoreHeight, worldWidth, worldHeight);
  801.     }
  802.     
  803.     if (clearScreen)
  804.     {
  805.         g.setColor (Color.white);
  806.         g.fillRect (0, 0, worldWidth, worldHeight);
  807.         
  808.         world.setColor (skyColor);
  809.         world.fillRect (0, 0, worldWidth, worldHeight);
  810.         clearScreen = false;
  811.     }
  812.  
  813.     if (paused)
  814.     {
  815.         paintMessage ("PAUSED", world);
  816.         return;
  817.     }
  818.  
  819.     paintStatus (g);
  820.     paintGameObjects (mrvs, world);
  821.     paintGameObjects (missiles, world);
  822.     paintGameObjects (bombs, world);
  823.     paintGameObjects (bases, world);
  824.     paintGameObjects (shots, world);
  825.     paintGameObjects (explosions, world);
  826.     paintGameObjects (bombDebris, world);
  827.  
  828.     if (!playing)
  829.     {
  830.         paintMessage ("GAME OVER", world);
  831.     }
  832.     else if (screenMessage != null)
  833.     {
  834.         paintMessage (screenMessage, world);
  835.     }
  836.     }
  837. }
  838.