/** * @(#)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; } }