/** * @(#)EnemyShips.java 1.0.1 98/12/04 *
* Copyright (C) 1998 David E. Wexler *
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. See * license.txt for a full copy of the GNU GPL. *
* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. *
* To Contact the author send e-mail to vagabond@netdragon.com or send * snailmail to: 511 Bobcat Ct, Punta Gorda, FL 3398. */ import java.awt.*; import java.io.*; import java.lang.*; import java.net.*; import java.util.*; import Nelzan; /** * EnemyShips - controls enemy actions, movement, and painting. *
* This class downloads, stores, handles, and draws all information * dealing with enemy ships that fly around. *
* @author David Wexler (vagabond@netdragons.com)
* @version 1.0.3
* @since Nelzan1.0.1
*/
public class EnemyShips {
private int[] type;
private int[] width;
private int[] height;
private int[] shields;
private int[] damage;
private int[] x;
private int[] y;
private String[] move;
private String[] fire;
private int[] imgNorm;
private int[] imgFire;
private int[] imgUp;
private int[] imgDown;
private int[] step;
private int[] subStep;
private int[] fireX;
private int[] fireY;
private int[] fireHeight;
private Image[] myImages;
private Nelzan comp;
private URL dataFile;
private int length;
private int dir;
private boolean shipWrap = false;
/**
* For Generating Random Numbers
*/
Random r = new Random(); // For Random Numbers
/**
* Defines a new class of EnemyShips to be manipulated. Will download
* information from the correct level and store it into private arrays.
*
* @param img Images of the ships
* @param level The current player's Level
* @param c Instance of Nelzan, for callbacks.
*/
EnemyShips(Image[] img, int level, Nelzan c) {
myImages = img;
comp = c;
getFile(level);
}
/**
* Updates enemy location, fire location, and handles collision logic.
* This function is the brains of all Enemy ships. This updates their
* location and causes them to move, updates their fire location, and
* it makes sure the ship or it's weapon is not in contact with the player.
*/
public void update() {
for (int i = 0; i < length; i++) {
if (type[i] != 0) {
if (comp.level%4 != 0)
x[i] -= 3;
else if (x[length-1] > 420)
x[i] -= 2;
if (x[i] < 620 && x[i]+width[i] > 0) {
move(i);
if (type[i] != -10)
checkDamage(i);
}
if (x[i] < -300) {
if (shipWrap)
x[i] = 900;
else
type[i] = 0;
}
if (fireX[i] != -100) {
fireX[i] -= type[i]%20;
if (type[i] > 20)
fireY[i] += comp.me.getYMovement(fireY[i]);
if (fireX[i] < -10-fireHeight[i])
fireX[i] = -100;
}
}
}
}
/**
* Sets if enemies will wrap around. When set to true
* enemies will continually move from one end of the screen to the
* other. When set to false they will vanish after
* exiting screen right.
*
* @param set Do you wish to have wrapping on?
*/
public void setWrap(boolean set) {
shipWrap = set;
}
/**
* A Quick Check to see if the level is over.
*
* @return true if all members are destoryed,
* fasle otherwise.
*/
public boolean levelOver() {
for (int i = 0; i < length; i++)
if (type[i] != 0)
return false;
return true;
}
/**
* Paints all the enemies on the screen. There is no Z-ordering done in
* this function, ships are drawn in the order they presented in the
* array.
*
* @param g The Graphics to draw to.
*/
public void paint(Graphics g) {
for (int i = 0; i < length; i++) {
if (x[i] < 620 && type[i] != 0) {
if (type[i] != -10) {
g.drawImage(myImages[getImage(i)], x[i], y[i], comp);
if (fireX[i] != -100)
g.drawImage(myImages[imgFire[i]], fireX[i], fireY[i], comp);
} else {
g.drawImage(myImages[getImage(i)], x[i]+width[i]/(2*subStep[i]),
y[i]+height[i]/(2*subStep[i]), width[i]/subStep[i],
height[i]/subStep[i], comp);
}
}
}
}
/**
* This function checks to see if a ship or its fired weapon are in
* contact with the player. It also check to see if the players weapon
* is hitting the ship via a callback. If the ship shiels are less than
* or equal to zero the ship is destoryed.
*
* @param i Array index to check at.
*/
private void checkDamage(int i) {
if (fireX[i] != -100 && comp.me.checkAttack(fireX[i], fireY[i],
width[i]/3, fireHeight[i], damage[i]))
fireX[i] = -100;
shields[i] -= comp.me.damage(x[i], y[i], width[i], height[i], type[i],
shields[i]);
if (shields[i] <= 0 && type[i] != 0 && type[i] != -10) {
type[i] = -10;
subStep[i] = 1;
comp.me.score += (damage[i] * 100);
}
}
/**
* This function determins if the ship's normal, up, or down image should
* be shown.
*
* @param i Array index to get Image at.
* @return int with the location of the image
* to be shown.
*/
private int getImage(int i) {
dir = toInt(move[i].substring(step[i], step[i]+1));
if (dir == 1)
return imgUp[i];
else if (dir == 3)
return imgDown[i];
else
return imgNorm[i];
}
/**
* Moves the player based on it's movement string.
*
* @param i Array index to move.
*/
private void move(int i) {
dir = toInt(move[i].substring(step[i], step[i]+1));
switch (dir) {
case 1: y[i] -= 4;
break;
case 2: x[i] += 5;
break;
case 3: y[i] += 4;
break;
case 4: x[i] -= 3;
if (comp.level%4 == 0)
x[i] -= 2;
break;
}
if (subStep[i]++ > 6) {
step[i] += 1;
subStep[i] = 0;
if (step[i] < move[i].length() && fire[i].charAt(step[i]) == '1' &&
fireX[i] == -100) {
fireX[i] = x[i] - 10;
if (type[i] < 20)
fireY[i] = y[i];
else
fireY[i] = y[i] + ((2*height[i])/5);
}
if (type[i] == -10)
type[i] = 0;
}
if (step[i] >= move[i].length())
step[i] = 0;
}
/**
* Download the level file and loads it into Arrays.
*
* @param i Level to be loaded
*/
private void getFile(int i) {
String url = comp.getCodeBase().toString() + "levels/" + i + ".level";
try {
this.dataFile = new URL(url);
} catch ( MalformedURLException e) {
System.out.println("Bad URL: " + url);
}
String line; // Line Buffer
int c = -1;
try {
URLConnection conn = this.dataFile.openConnection();
conn.connect();
DataInputStream data = new DataInputStream(new BufferedInputStream(conn.getInputStream()));
while((line = data.readLine()) != null) {
if (c == -1) {
buildNew(toInt(line));
c = 0;
} else {
StringTokenizer Token = new StringTokenizer(line, ":", false);
type[c] = toInt(Token.nextToken());
width[c] = toInt(Token.nextToken());
height[c] = toInt(Token.nextToken());
shields[c] = toInt(Token.nextToken());
damage[c] = toInt(Token.nextToken());
x[c] = toInt(Token.nextToken());
y[c] = toInt(Token.nextToken());
move[c] = Token.nextToken();
fire[c] = Token.nextToken();
imgNorm[c] = toInt(Token.nextToken());
imgFire[c] = toInt(Token.nextToken());
imgUp[c] = toInt(Token.nextToken());
imgDown[c] = toInt(Token.nextToken());
step[c] = 0;
subStep[c] = 0;
fireX[c] = -100;
fireY[c] = 0;
fireHeight[c] = toInt(Token.nextToken());
if (move[c].length() != fire[c].length())
System.err.println("Error: MoveString and FireString size Missmatch @ line " + c);
else
c += 1;
}
}
} catch (IOException e) {
System.out.println("IO Error:" + e.getMessage());
}
if (c != length)
System.err.println("Error: Size Missmatch, Number of Elements is wrong!");
}
/**
* Build arrays of the correct length so data can be placed inside them.
*
* @param i Length arrays need to be.
*/
private void buildNew(int i) {
length = i;
type = new int[i];
width = new int[i];
height = new int[i];
shields = new int[i];
damage = new int[i];
x = new int[i];
y = new int[i];
move = new String[i];
fire = new String[i];
imgNorm = new int[i];
imgFire = new int[i];
imgUp = new int[i];
imgDown = new int[i];
step = new int[i];
subStep = new int[i];
fireX = new int[i];
fireY = new int[i];
fireHeight = new int[i];
}
/**
* Converts a String to an int;
*
* @param s The String to be converted
* @return an int value from s
*/
private int toInt(String s) {
Integer cToI = new Integer(s);
return cToI.intValue();
}
/**
* Returns the distance from zero.
*
* @param i The number to check.
* @returns an int of the distance from zero.
*/
private int abs(int i) {
if (i > 0)
return i;
return -i;
}
}