/* Copyright (C) 2003 Ben McIlwain 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. 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., or visit the website http://www.gnu.org/copyleft/gpl.html . */ //Import statements import java.awt.*; import java.*; import java.math.*; import java.awt.event.*; import java.awt.BorderLayout; import java.awt.Dimension; import java.util.Vector; //Main class declaration public class axnal extends java.applet.Applet implements Runnable { //Interface declarations protected Label unitHelp, numHelp, battleHelp; protected TextField numUnit, numBattles; protected Button addUnitsA, addUnitsD, clearUnits, doBattle; protected Choice speed; protected Choice unitType; protected Dimension d; protected Thread animator; protected Graphics offGraphics; protected Image offImage; protected Dimension offDimension; public class UnitStats { protected String name; protected int defend, attack, pointCost; public UnitStats(String newName, int newDefense, int newAttack, int newPoint) { name = newName; defend = newDefense; attack = newAttack; pointCost = newPoint; } public String getName() { return name; } } protected Vector allUnits; protected int attacker[]; protected int defender[]; protected Vector dieNum; protected int attackSum, defendSum, attackPts, defendPts, turnNum; protected boolean battle; //Init function ... declares all of the interface items. public void init() { int count; dieNum = new Vector(); battle = true; attackSum = 0; defendSum = 0; attackPts = 0; defendPts = 0; turnNum = 0; allUnits = new Vector(); allUnits.addElement(new UnitStats("Infantry", 2, 1, 3)); allUnits.addElement(new UnitStats("Armor", 2, 3, 5)); allUnits.addElement(new UnitStats("Fighter", 4, 3, 12)); allUnits.addElement(new UnitStats("Bomber", 1, 4, 15)); allUnits.addElement(new UnitStats("Transport", 1, 0, 8)); allUnits.addElement(new UnitStats("Submarine", 2, 2, 8)); allUnits.addElement(new UnitStats("Carrier", 3, 1, 18)); allUnits.addElement(new UnitStats("Battleship", 4, 4, 24)); allUnits.addElement(new UnitStats("Anti-Air", -1, 0, 5)); attacker = new int[9]; defender = new int[9]; for (count = 0; count < 9; count++) { attacker[count] = 0; defender[count] = 0; } setBackground(Color.white); unitHelp = new Label("Choose unit"); add(unitHelp); unitType = new Choice(); unitType.add("Infantry"); unitType.add("Armor"); unitType.add("Fighter"); unitType.add("Bomber"); unitType.add("Transport"); unitType.add("Submarine"); unitType.add("Carrier"); unitType.add("Battleship"); unitType.add("Anti-Air"); add(unitType); numHelp = new Label("Num units"); add(numHelp); numUnit = new TextField("1", 4); add(numUnit); addUnitsA = new Button("Add to Attacker"); addUnitsA.addActionListener(new AddUnits()); add(addUnitsA); addUnitsD = new Button("Add to Defender"); addUnitsD.addActionListener(new AddUnits()); add(addUnitsD); clearUnits = new Button("Clear Units"); clearUnits.addActionListener(new AddUnits()); add(clearUnits); battleHelp = new Label("Num battles"); add(battleHelp); numBattles = new TextField("1", 4); add(numBattles); //Selectable speed menu. speed = new Choice(); speed.add("Crawl"); speed.add("Slow"); speed.add("Moderate"); speed.add("Fast"); speed.add("Faster"); speed.add("Warp 10"); speed.add("Instant"); speed.select(2); add(speed); doBattle = new Button("Battle!"); add(doBattle); doBattle.addActionListener(new RunBattle()); //Adds the mouse listener for user-enabled placement of blockades. //addMouseListener(new mouseHandler()); start(); } //The mouse listener. /* public class mouseHandler extends MouseAdapter { int mouseX, mouseY; public void mousePressed(MouseEvent e) { mouseX = e.getX(); mouseY = e.getY(); } }*/ //Upon thread start ... public void start() { animator = new Thread(this); animator.start(); //animator.suspend(); } //Upon thread stop ... public void stop() { animator = null; } //What to do while the thread is running ... public void run() { //Initializations. int randomNum, counter; int delay = 100, count; d = size(); //While the thread is running. while (Thread.currentThread() == animator) { switch (speed.getSelectedIndex()) { case 0: delay = 10000; break; case 1: delay = 5000; break; case 2: delay = 2500; break; case 3: delay = 1000; break; case 4: delay = 500; break; case 5: delay = 250; break; case 6: delay = 100; break; } if (battle) { turnNum = 1; do { conductBattle(); turnNum++; attackSum = 0; attackPts = 0; for (count = 0; count < 9; count++) { attackSum += attacker[count]; attackPts += attacker[count] * ((UnitStats)allUnits.elementAt(count)).pointCost; } defendSum = 0; defendPts = 0; for (count = 0; count < 9; count++) { defendSum += defender[count]; defendPts += defender[count] * ((UnitStats)allUnits.elementAt(count)).pointCost; } if (delay != 0) { repaint(); try { Thread.sleep(delay); } catch(InterruptedException e) { break; } } } while (attackSum > 0 && defendSum > 0 && battle); battle = false; turnNum = 0; } if (delay != 0) { repaint(); try { Thread.sleep(10); } catch(InterruptedException e) { break; } } } } //Updates the screen, uses double-buffering to prevent annoying flickering. public void update(Graphics g) { Dimension d = size(); if ((offGraphics == null) || (d.width != offDimension.width) || (d.height != offDimension.height)) { offDimension = d; offImage = createImage(d.width, d.height); offGraphics = offImage.getGraphics(); } setBackground(Color.white); offGraphics.setColor(Color.white); offGraphics.fillRect(0, 0, d.width, d.height); paintFrame(offGraphics); g.drawImage(offImage, 0, 0, null); } public void refreshPts() { int count; defendPts = 0; attackPts = 0; for (count = 0; count < 9; count++) { defendPts += defender[count] * ((UnitStats)allUnits.elementAt(count)).pointCost; attackPts += attacker[count] * ((UnitStats)allUnits.elementAt(count)).pointCost; } } private class AddUnits implements ActionListener { public void actionPerformed(ActionEvent e) { int unit = unitType.getSelectedIndex(); int count; Integer intObj; intObj = new Integer(numUnit.getText()); if (e.getActionCommand().equals("Add to Defender")) { defender[unit] += intObj.intValue(); if (unit == 8 && defender[unit] > 1) { defender[unit] = 1; } } else if (e.getActionCommand().equals("Add to Attacker") && unit != 8) { attacker[unit] += intObj.intValue(); } else if (e.getActionCommand().equals("Clear Units")) { for (count = 0; count < 9; count++) { attacker[count] = 0; defender[count] = 0; } } refreshPts(); } } private class RunBattle implements ActionListener { public void actionPerformed(ActionEvent e) { //CONDUCT THE BATTLE; int attackSum = 0, defendSum = 0; battle = !battle; } } private void conductBattle() { int count, count2, roll; //Index 0: ground and air casualties //Index 1: ship casualties //Index 2: air casualties //Index 3: air and ship casualties //Index 4: air, ship, and ground casualties int defendCasualties[] = new int[5]; int attackCasualties[] = new int[5]; for (count = 0; count < 5; count++) { defendCasualties[count] = 0; attackCasualties[count] = 0; } int attackSum = 0, defendSum = 0; if (dieNum.size() > 0) { dieNum = new Vector(); } for (count = 0; count < 9; count++) { attackSum += attacker[count]; } for (count = 0; count < 9; count++) { defendSum += defender[count]; } for (count = 0; count < 8; count++) { for (count2 = 0; count2 < attacker[count]; count2++) { if (dieRoll(((UnitStats)allUnits.elementAt(count)).attack, count, true, false)) { if (count >= 0 && count <= 1) { defendCasualties[0]++; } else if (count >= 2 && count <= 3) { defendCasualties[4]++; } else if (count == 4 || count == 6 || count == 7) { defendCasualties[3]++; } else if (count == 5) { defendCasualties[1]++; } } } } for (count = 0; count < 8; count++) { for (count2 = 0; count2 < defender[count]; count2++) { if (dieRoll(((UnitStats)allUnits.elementAt(count)).defend, count, false, false)) { if (count >= 0 && count <= 1) { attackCasualties[0]++; } else if (count >= 2 && count <= 3) { attackCasualties[4]++; } else if (count == 4 || count == 6 || count == 7) { attackCasualties[3]++; } else if (count == 5) { attackCasualties[1]++; } } } } if (defender[8] > 0 && turnNum == 1) { for (count2 = 0; count2 < attacker[2] + attacker[3]; count2++) { if (dieRoll(1, 8, false, true)) { attackCasualties[2]++; } } } //Index 0: ground and air casualties //Index 1: ship casualties //Index 2: air casualties //Index 3: air and ship casualties //Index 4: air, ship, and ground casualties while (attackCasualties[2] > 0 && (attacker[2] > 0 || attacker[3] > 0)) { if (attacker[2] > 0 && attacker[3] > 0) { attacker[(int)(Math.random()) + 2]--; attackCasualties[2]--; attackSum--; } else if (attacker[2] > 0 && attacker[3] == 0) { attacker[2]--; attackCasualties[2]--; attackSum--; } else if (attacker[2] == 0 && attacker[3] > 0) { attacker[3]--; attackCasualties[3]--; attackSum--; } } while (attackCasualties[0] > 0 && (attacker[0] > 0 || attacker[1] > 0 || attacker[2] > 0 || attacker[3] > 0)) { count = (int)(Math.random() * 4); if (attacker[count] > 0) { attacker[count]--; attackCasualties[0]--; attackSum--; } } while (attackCasualties[1] > 0 && (attacker[4] > 0 || attacker[5] > 0 || attacker[6] > 0 || attacker[7] > 0)) { count = (int)(Math.random() * 4) + 4; if (attacker[count] > 0) { attacker[count]--; attackCasualties[1]--; attackSum--; } } while (attackCasualties[3] > 0 && (attacker[2] > 0 || attacker[3] > 0 || attacker[4] > 0 || attacker[5] > 0 || attacker[6] > 0 || attacker[7] > 0)) { count = (int)(Math.random() * 6) + 2; if (attacker[count] > 0) { attacker[count]--; attackCasualties[3]--; attackSum--; } } while (attackCasualties[4] > 0 && attackSum > 0) { count = (int)(Math.random() * 8); if (attacker[count] > 0) { attacker[count]--; attackCasualties[4]--; attackSum--; } } while (defendCasualties[0] > 0 && (defender[0] > 0 || defender[1] > 0 || defender[2] > 0 || defender[3] > 0)) { count = (int)(Math.random() * 4); if (defender[count] > 0) { defender[count]--; defendCasualties[0]--; defendSum--; } } while (defendCasualties[1] > 0 && (defender[4] > 0 || defender[5] > 0 || defender[6] > 0 || defender[7] > 0)) { count = (int)(Math.random() * 4) + 4; if (defender[count] > 0) { defender[count]--; defendCasualties[1]--; defendSum--; } } while (defendCasualties[3] > 0 && (defender[2] > 0 || defender[3] > 0 || defender[4] > 0 || defender[5] > 0 || defender[6] > 0 || defender[7] > 0)) { count = (int)(Math.random() * 6) + 2; if (defender[count] > 0) { defender[count]--; defendCasualties[3]--; defendSum--; } } while (defendCasualties[4] > 0 && defendSum > 0) { count = (int)(Math.random() * 8); if (defender[count] > 0) { defender[count]--; defendCasualties[4]--; defendSum--; } } } private class OneDie { protected int roll, whatUnit; protected boolean hitMiss, attackerUnit; public OneDie(int newRoll, int unit, boolean hit, boolean attack) { roll = newRoll; whatUnit = unit; hitMiss = hit; attackerUnit = attack; } public String toString() { return (new Integer(roll)).toString(); } public void writeMe(int space, Graphics g) { int x = 0, y = 100 + 20 * whatUnit; if (attackerUnit == true) { x = 120 + space * 10; } else { x = 440 + space * 10; } if (hitMiss) { g.setColor(Color.green); } else { g.setColor(Color.red); } if (!(attackerUnit && x >= 320)) { g.drawString(this.toString(), x, y); } } } private boolean dieRoll(int numNeeded, int unit, boolean attackerUnit, boolean AA) { int roll = (int)(Math.random() * 6) + 1; if (!AA) { if (roll <= numNeeded) { dieNum.addElement(new OneDie(roll, unit, true, attackerUnit)); return true; } else { dieNum.addElement(new OneDie(roll, unit, false, attackerUnit)); return false; } } else { if (roll == 6) { dieNum.addElement(new OneDie(roll, 8, true, false)); return true; } else { dieNum.addElement(new OneDie(roll, 8, false, false)); return false; } } } public void paint(Graphics g) { update(g); } private void paintFrame(Graphics g) { int count; int textFormat[][] = new int[9][2]; for (count = 0; count < 9; count++) { textFormat[count][0] = 0; textFormat[count][1] = 0; } g.setColor(Color.blue); g.setFont(new Font("Dialog", Font.BOLD, 16)); g.drawString("Attacker", 0, 80); g.drawString("Defender", 320, 80); g.setColor(Color.black); g.setFont(new Font("Dialog", Font.PLAIN, 14)); for (count = 0; count < 9; count++) { if (count != 8) { g.drawString(((UnitStats)allUnits.elementAt(count)).getName() + " (" + ((UnitStats)allUnits.elementAt(count)).attack + "): " + attacker[count], 0, 100 + 20 * count); g.drawString(((UnitStats)allUnits.elementAt(count)).getName() + " (" + ((UnitStats)allUnits.elementAt(count)).defend + "): " + defender[count], 320, 100 + 20 * count); } else { g.drawString(((UnitStats)allUnits.elementAt(count)).getName() + " (1d6): " + defender[count], 320, 100 + 20 * count); } } g.drawString("Points: " + attackPts, 0, 280); g.drawString("Points: " + defendPts, 320, 280); if (battle) { for (count = 0; count < dieNum.size(); count++) { if (((OneDie)dieNum.elementAt(count)).attackerUnit) { textFormat[((OneDie)dieNum.elementAt(count)).whatUnit][0]++; ((OneDie)dieNum.elementAt(count)).writeMe(textFormat[((OneDie)dieNum.elementAt(count)).whatUnit][0], g); } else { textFormat[((OneDie)dieNum.elementAt(count)).whatUnit][1]++; ((OneDie)dieNum.elementAt(count)).writeMe(textFormat[((OneDie)dieNum.elementAt(count)).whatUnit][1], g); } } } d = size(); } }