Java tutorial
/* * * Copyright (c) 2010 by George Hayward * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package net.cantab.hayward.george.OCS; import javax.swing.JToolBar; import VASSAL.build.AbstractConfigurable; import VASSAL.build.AutoConfigurable; import VASSAL.build.Buildable; import VASSAL.build.GameModule; import VASSAL.build.module.GameComponent; import VASSAL.build.module.Map; import VASSAL.build.module.PlayerRoster; import VASSAL.build.module.documentation.HelpFile; import VASSAL.build.module.gamepieceimage.StringEnumConfigurer; import VASSAL.build.module.map.BoardPicker; import VASSAL.build.module.map.boardPicker.Board; import VASSAL.build.module.map.boardPicker.board.HexGrid; import VASSAL.build.widget.PieceSlot; import VASSAL.command.Command; import VASSAL.command.CommandEncoder; import VASSAL.command.NullCommand; import VASSAL.configure.BooleanConfigurer; import VASSAL.configure.Configurer; import VASSAL.configure.ConfigurerFactory; import VASSAL.configure.IntConfigurer; import VASSAL.counters.BasicPiece; import VASSAL.counters.Decorator; import VASSAL.counters.Embellishment; import VASSAL.counters.GamePiece; import VASSAL.counters.PieceCloner; import VASSAL.counters.PieceDefiner; import VASSAL.i18n.Resources; import VASSAL.tools.SequenceEncoder; import VASSAL.tools.ToolBarComponent; import VASSAL.tools.filechooser.FileChooser; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.WindowConstants; import net.cantab.hayward.george.OCS.Counters.Airbase; import net.cantab.hayward.george.OCS.Counters.Aircraft; import net.cantab.hayward.george.OCS.Counters.Artillery; import net.cantab.hayward.george.OCS.Counters.AttackCapable; import net.cantab.hayward.george.OCS.Counters.AttackMarker; import net.cantab.hayward.george.OCS.Counters.Defensive; import net.cantab.hayward.george.OCS.Counters.Division; import net.cantab.hayward.george.OCS.Counters.Fighter; import net.cantab.hayward.george.OCS.Counters.GameMarker; import net.cantab.hayward.george.OCS.Counters.HeadQuarters; import net.cantab.hayward.george.OCS.Counters.Hedgehog; import net.cantab.hayward.george.OCS.Counters.Leader; import net.cantab.hayward.george.OCS.Counters.OOS; import net.cantab.hayward.george.OCS.Counters.Over; import net.cantab.hayward.george.OCS.Counters.ReplaceCard; import net.cantab.hayward.george.OCS.Counters.Replacement; import net.cantab.hayward.george.OCS.Counters.Reserve; import net.cantab.hayward.george.OCS.Counters.Ship; import net.cantab.hayward.george.OCS.Counters.SupplyMarker; import net.cantab.hayward.george.OCS.Counters.Transport; import net.cantab.hayward.george.OCS.Counters.Under; import net.cantab.hayward.george.OCS.Parsing.ParsePieces; import net.cantab.hayward.george.OCS.Parsing.ParseText; import org.apache.commons.io.filefilter.FalseFileFilter; /** * This defines all the static data needed by the module * * @author George Hayward */ public class Statics extends AbstractConfigurable implements CommandEncoder, GameComponent { /** * The structure of a piece pointer */ static class PiecePtr { String name; String image; OcsCounter piece; } /** * Which module */ int module; final static int BalticGap = 1; final static int CaseBlue = 2; final static int DAK = 3; final static int Korea = 4; final static int Tunisia = 5; final static int Hubes = 6; final static int Sicily = 7; final static int Burma = 8; final static int TBL = 9; final static int HR = 10; final static int RE = 11; final static int BTR = 12; final static int Italy = 13; /** * Returns true if game is Baltic Gap */ public boolean isBalticGap() { return module == BalticGap; } /** * True if this game is DAK */ public boolean isDAK() { return module == DAK; } /** * True if this game is Case Blue */ public boolean isCaseBlue() { return module == CaseBlue; } /** * True if this game is Korea */ public boolean isKorea() { return module == Korea; } /** * True if this game is Tunisia */ public boolean isTunisia() { return module == Tunisia; } /** * True if this game is Hubes */ public boolean isHubes() { return module == Hubes; } /** * True if this game is Sicily */ public boolean isSicily() { return module == Sicily; } /** * True if this game is Burma */ public boolean isBurma() { return module == Burma; } /** * True if this game is The Blitzkrieg Legend */ public boolean isBlitzkriegLegend() { return module == TBL; } /** * True if this game is Hungarian Rhapsody */ public boolean isHungarianRhapsody() { return module == HR; } /** * True if this game is Reluctant Enemies */ public boolean isReluctantEnemies() { return module == RE; } /** * True if this game is Beyond the Rhine */ public boolean isBeyondTheRhine() { return module == BTR; } /** * True if this game is OCS Italy */ public boolean isItaly() { return module == Italy; } /** * An array of all the piece definitions used in the module */ static PiecePtr[] thePieces = null; /** * An array with the two sides in the game. */ static public Side[] theSides = new Side[2]; /** * An array with the current commanders in the game */ static Commander[] theCommanders = new Commander[0]; /** * The current user's Commander object */ static Commander curCommander = null; /** * Pointer to the current object */ public static Statics theStatics; /** * Whether to display PZs for a side */ public static boolean[] showPZs = { false, false }; /** * Whether to show ZOCs for a side */ public static boolean[] showZOCs = { false, false }; /** * Whether to show HQs for a side */ public static boolean[] showHQs = { false, false }; /** * A value which is updated whenever a piece is moved. It is used to * determine whether the security states of pieces within a stack need to be * recalculated */ static int check = 1; /** * True if reading scenario text file */ static public boolean readingTextFile = false; /* * The following are preferences set by the user. Some can only be set at the * start of a scenario or when loading a save file earlier than version 3. */ /** * True if all forms of hidden movement are disabled */ public static boolean hiddenMovementOff = false; /** * True if the range to a friendly piece affects the display of a stack */ static boolean rangeInUse = false; /** * True if nearest AEP to be used for flight distance calculations rather * then one which gives minimal distance */ static boolean useNearest = false; /** * Security to be applied to a hostile stack in a zone */ static int zoneSecurity = OcsCounter.VISIBLE; /** * Range at which opposing stacks including aircraft become invisible in * pixels */ static int rangeAirHidden = 0; /** * Same range in hexes */ static int hexRangeAirHidden = 0; /** * Range at which opposing stacks become invisble */ static int rangeHidden = 0; /** * Same range in hexes */ static int hexRangeHidden = 0; /** * Range at which opposing stackes become concealed */ static int rangeConcealed = 0; /** * Same range in hexes */ static int hexRangeConcealed = 0; /** * Range at which opposing stacks become flattened */ static int rangeFlattened = 0; /** * Same range in hexes */ static int hexRangeFlattened = 0; /** * True if Formation Markers are to be implemented as in 13.7 */ static boolean useFormations = false; /** * True if ranges are to be done in hexagaonal fashion */ static boolean hexRanges = false; /** * The main map for this module st.nextInt(0); */ public static Map theMap; /** * The hex size for the main map */ static double hexSize; /** * The instructions for the current scenario */ static String[] scenarioInstructions; /** * The toolbar for module menus */ JToolBar toolbar; /** * The command button */ JButton commandLaunch; /** * The process pieces button */ JButton piecesLaunch; /** * The piece processing window */ JDialog piecesWindow; /** * The read text file & create scenario button */ JButton textLaunch; /** * Display the scenario instructions */ JButton instructions; /** * Check the mask/layers decorators in the right order */ JButton checkOrder; /** * The button to read piece definitions and create pieces */ JButton createPieces; /** * Create an object and thus initialise all the static data. */ @SuppressWarnings("LeakingThisInConstructor") public Statics() { theSides[0] = new Side("Axis"); theSides[1] = new Side("Soviet"); theStatics = this; PieceDefiner.addDefinition(new Airbase()); PieceDefiner.addDefinition(new Aircraft()); PieceDefiner.addDefinition(new Artillery()); PieceDefiner.addDefinition(new AttackCapable()); PieceDefiner.addDefinition(new AttackMarker()); PieceDefiner.addDefinition(new Defensive()); PieceDefiner.addDefinition(new Division()); PieceDefiner.addDefinition(new GameMarker()); PieceDefiner.addDefinition(new HeadQuarters()); PieceDefiner.addDefinition(new Hedgehog()); PieceDefiner.addDefinition(new Over()); PieceDefiner.addDefinition(new OOS()); PieceDefiner.addDefinition(new Replacement()); PieceDefiner.addDefinition(new Reserve()); PieceDefiner.addDefinition(new Ship()); PieceDefiner.addDefinition(new SupplyMarker()); PieceDefiner.addDefinition(new Transport()); PieceDefiner.addDefinition(new Under()); PieceDefiner.addDefinition(new ReplaceCard()); PieceDefiner.addDefinition(new Leader()); PieceDefiner.addDefinition(new Fighter()); } /** * Update the scenario information */ static public void addToScenarioInformation(String s) { if (scenarioInstructions == null) { scenarioInstructions = new String[1]; scenarioInstructions[0] = s; } else { String[] t = new String[scenarioInstructions.length + 1]; System.arraycopy(scenarioInstructions, 0, t, 0, scenarioInstructions.length); t[scenarioInstructions.length] = s; scenarioInstructions = t; } GameModule.getGameModule().getChatter().show(s); } /** * Build the Piece Ptr data st.nextInt(0); */ static void buildPiecePtrs() { if (thePieces != null) { return; } List<PieceSlot> t = GameModule.getGameModule().getAllDescendantComponentsOf(PieceSlot.class); if (t.isEmpty()) { thePieces = new PiecePtr[0]; return; } thePieces = new PiecePtr[t.size()]; int i = 0; for (PieceSlot q : t) { GamePiece p = PieceCloner.getInstance().clonePiece(q.getPiece()); GamePiece g = p; GamePiece h = p; for (;;) { if (!(g instanceof Decorator)) { break; } h = g; g = ((Decorator) g).getInner(); } String s = g.getType(); final SequenceEncoder.Decoder sty = new SequenceEncoder.Decoder(s, ';'); sty.nextToken(); sty.nextChar('\0'); sty.nextChar('\0'); String front = sty.nextToken(); String pname = sty.nextToken(); if (theStatics.isCaseBlue() && h instanceof Embellishment) { s = h.getType(); SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';'); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextKeyStroke('r'); st.nextToken(); st.nextBoolean(false); st.nextInt(0); st.nextInt(0); String[] imageName = st.nextStringArray(0); front = imageName[0]; } thePieces[i] = new PiecePtr(); thePieces[i].name = pname; thePieces[i].image = front; if (!(p instanceof OcsCounter)) { GameModule.getGameModule().getChatter() .show("*** Not an OCS Counter " + pname + " - image = " + front); thePieces[i].piece = null; } else { thePieces[i].piece = (OcsCounter) p; } i++; } } static OcsCounter lastConverted = null; /** * Find a piece which matches the given name and image name. Return the * correct type of BasicCounter pointing at this piece */ static OcsCounter findMatching(String name, String imageName, GamePiece p) { int j; int imageCount = 0; for (j = 0; j < 2; j++) { buildPiecePtrs(); if (thePieces == null) { return null; } int i; for (i = 0; i < thePieces.length; i++) { if (thePieces[i] == null) { continue; } if (!imageName.equals(thePieces[i].image)) { continue; } imageCount++; if (name.equals(thePieces[i].name)) { lastConverted = thePieces[i].piece; BasicCommandEncoderOverride b = new BasicCommandEncoderOverride(); return (OcsCounter) b.createDecorator(thePieces[i].piece.myGetType(), p); } } if (imageCount == 1) { for (i = 0; i < thePieces.length; i++) { if (thePieces[i] == null) { continue; } if (!imageName.equals(thePieces[i].image)) { continue; } lastConverted = thePieces[i].piece; BasicCommandEncoderOverride b = new BasicCommandEncoderOverride(); return (OcsCounter) b.createDecorator(thePieces[i].piece.myGetType(), p); } } if (j == 0) { thePieces = null; } } return null; } /** * Convert a pre 3.0 version piece to the current version */ static OcsCounter convertOldPiece(GamePiece p) { if (theStatics == null) { return null; } GamePiece g = p; GamePiece h = p; for (;;) { if (!(g instanceof Decorator)) { break; } h = g; g = ((Decorator) g).getInner(); } if (!(g instanceof BasicPiece)) { return null; } String s = g.getType(); final SequenceEncoder.Decoder sty = new SequenceEncoder.Decoder(s, ';'); sty.nextToken(); sty.nextChar('\0'); sty.nextChar('\0'); String front = sty.nextToken(); String pname = sty.nextToken(); if (theStatics.isCaseBlue() && h instanceof Embellishment) { s = h.getType(); SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';'); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextInt(0); st.nextToken(); st.nextToken(); st.nextKeyStroke('r'); st.nextToken(); st.nextBoolean(false); st.nextInt(0); st.nextInt(0); String[] imageName = st.nextStringArray(0); front = imageName[0]; } if (front.equals("") && pname.equals("")) { return null; } OcsCounter b = findMatching(pname, front, p); if (thePieces == null) { return null; } if (b == null) { GameModule.getGameModule().getChatter().show("*** Unable to convert " + pname + " - image = " + front); b = new AttackCapable(AttackCapable.ID + "1;;", p); } return b; } /** * Convert a range in hexes to pixels */ static int convertHexesToPixels(int hexes) { return (int) (hexes * hexSize + hexSize * 0.5); } /** * Convert a range in pixels to hexes */ static int convertPixelsToHexes(int pixels) { return (int) (pixels / hexSize); } /** * Create the debug Toolbar entry. This is a null method which is overriden * in * * @class Debug which is a subclass of this one. When testing the system the * debug classes are used and for release the buildfile is editted to * replace the debug classes with the normal classes. The debug classes are * always subclasses of the classes they debug. */ void createDebugEntries() { } /** * Create the normal toolbar entries */ void createNormalEntries() { commandLaunch = new JButton("Command..."); commandLaunch.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { launchCommandMenu(); } }); commandLaunch.setFocusable(false); commandLaunch.setToolTipText("Take/Resign command of a side"); toolbar.add(commandLaunch); instructions = new JButton("Scenario Notes"); instructions.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayInstructions(); } }); instructions.setFocusable(false); toolbar.add(instructions); /* * If in edit mode add option to process pieces to OCS module form quickly */ if (GameModule.getGameModule().getArchiveWriter() != null) { piecesLaunch = new JButton("Piece Definitions"); piecesLaunch.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { piecesProcess(); } }); piecesLaunch.setFocusable(false); toolbar.add(piecesLaunch); piecesWindow = new JDialog(GameModule.getGameModule().getFrame()); piecesWindow.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); piecesWindow.setTitle("Piece definitions"); piecesWindow.setSize(700, 500); piecesWindow.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { piecesWindow.setVisible(false); } }); piecesWindow.add(new PieceProcessor()); textLaunch = new JButton("Read Scenario from Text File"); textLaunch.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { readTextFile(); } }); textLaunch.setFocusable(false); textLaunch.setEnabled(false); toolbar.add(textLaunch); createPieces = new JButton("Create Pieces from file"); createPieces.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { createPiecesFromFile(); } }); createPieces.setFocusable(false); createPieces.setEnabled(true); toolbar.add(createPieces); checkOrder = new JButton("Check Layers/Mask Order"); checkOrder.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { checkLayerOrders(); } }); checkOrder.setFocusable(false); checkOrder.setEnabled(true); toolbar.add(checkOrder); } } /** * Check decorator order in all pieces */ public void checkLayerOrders() { List<PieceSlot> t = GameModule.getGameModule().getAllDescendantComponentsOf(PieceSlot.class); for (PieceSlot q : t) { GamePiece p = q.getPiece(); GamePiece r = p; for (;;) { p = ((Decorator) p).getInner(); if (p instanceof Embellishment || !(p instanceof Decorator)) { break; } r = p; } if (p instanceof Embellishment) { GamePiece v = p; p = ((Decorator) p).getInner(); if (p instanceof Decorator) { GamePiece w = p; GamePiece u = p; for (;;) { p = ((Decorator) p).getInner(); if (!(p instanceof Decorator)) { break; } u = p; } ((Decorator) r).setInner(w); ((Decorator) u).setInner(v); ((Decorator) v).setInner(p); String s = p.getType(); final SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';'); st.nextToken(); st.nextChar('\0'); st.nextChar('\0'); String front = st.nextToken(); String pname = st.nextToken(); GameModule.getGameModule().getChatter() .show(pname + ": image = " + front + " - decorators in wrong order - fixed"); } } } } /** * Display thye scenario instructions */ public void displayInstructions() { if (scenarioInstructions != null) { for (int i = 0; i < scenarioInstructions.length; i++) { GameModule.getGameModule().getChatter().show(scenarioInstructions[i]); } } } /** * Read a scenario definition from a text file (which will be a straight * conversion of the PDFs of the game rules) */ public void readTextFile() { final FileChooser fc = GameModule.getGameModule().getFileChooser(); if (fc.showOpenDialog() != FileChooser.APPROVE_OPTION) { return; } File file = fc.getSelectedFile(); readingTextFile = true; ParseText p = new ParseText(file); p.parse(); readingTextFile = false; instructions.setEnabled(scenarioInstructions != null); } /** * Read the piece definitions from a file */ public void createPiecesFromFile() { final FileChooser fc = GameModule.getGameModule().getFileChooser(); if (fc.showOpenDialog() != FileChooser.APPROVE_OPTION) { return; } File file = fc.getSelectedFile(); new ParsePieces(file); } /** * Just flip the visibility of the window */ public void piecesProcess() { piecesWindow.setVisible(!piecesWindow.isShowing()); } /** * Display the command menu */ public void launchCommandMenu() { if (curCommander == null) { return; } int i; JMenu theMenu = new JMenu(); JMenuItem mi; for (i = 0; i < 2; i++) { int j; int k = 0; for (j = 0; j < theCommanders.length; j++) { if (theCommanders[j].sidesCommanded[i]) { k++; } } if (k != 0) { JMenu com = new JMenu("Commanders of the " + theSides[i].name + " side"); for (j = 0; j < theCommanders.length; j++) { if (theCommanders[j].sidesCommanded[i]) { mi = new JMenuItem(theCommanders[j].name); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } }); mi.setEnabled(true); com.add(mi); } } theMenu.add(com); } if (curCommander.sidesCommanded[i]) { final int m = i; mi = new JMenuItem("Resign from " + theSides[i].name + " side"); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { resignSide(m); } }); mi.setEnabled(true); theMenu.add(mi); int n = 0; for (j = 0; j < theCommanders.length; j++) { if (theCommanders[j].sidesRequested[i]) { n++; } } if (n != 0) { JMenu app = new JMenu("Approve to join " + theSides[i].name + " side"); JMenu rej = new JMenu("Reject to join " + theSides[i].name + " side"); for (j = 0; j < theCommanders.length; j++) { if (theCommanders[j].sidesRequested[i]) { mi = new JMenuItem(theCommanders[j].name); final int p = j; mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { acceptSide(m, p); } }); mi.setEnabled(true); app.add(mi); mi = new JMenuItem(theCommanders[j].name); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { rejectSide(m, p); } }); mi.setEnabled(true); rej.add(mi); } } theMenu.add(app); theMenu.add(rej); } } else { final int m = i; if (k != 0) { mi = new JMenuItem("Join " + theSides[i].name + " side"); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { joinSide(m); } }); mi.setEnabled(true); theMenu.add(mi); } else { mi = new JMenuItem("Command " + theSides[i].name + " side"); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { commandSide(m); } }); mi.setEnabled(true); theMenu.add(mi); } } } for (i = 0; i < 2; i++) { final int m = i; mi = new JMenuItem((showPZs[i] ? "Hide " : "Show ") + theSides[i].name + " PZs"); mi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { displayPZs(m); } }); mi.setEnabled(true); theMenu.add(mi); mi = new JMenuItem((showZOCs[i] ? "Hide " : "Show ") + theSides[i].name + " ZOCs"); mi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { displayZOCs(m); } }); mi.setEnabled(true); theMenu.add(mi); if (curCommander.sidesCommanded[i]) { mi = new JMenuItem((showHQs[i] ? "Hide " : "Show ") + theSides[i].name + " HQs"); mi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { displayHQs(m); } }); mi.setEnabled(true); theMenu.add(mi); } } theMenu.getPopupMenu().show(commandLaunch, 0, commandLaunch.getHeight()); } /** * Flip display of PZs. */ public void displayPZs(int i) { showPZs[i] = !showPZs[i]; theMap.repaint(); } /** * Flip display of ZOCs. */ public void displayZOCs(int i) { showZOCs[i] = !showZOCs[i]; theMap.repaint(); } /** * Flip display of HQs. */ public void displayHQs(int i) { showHQs[i] = !showHQs[i]; theMap.repaint(); } /** * Resign a given side */ void resignSide(int aSide) { curCommander.logDoCommand(0, aSide, false); } /** * Command a given side */ void commandSide(int aSide) { curCommander.logDoCommand(0, aSide, true); } /** * Request to join a given side */ void joinSide(int aSide) { curCommander.logDoCommand(1, aSide, true); } /** * Accept for a side */ void acceptSide(int aSide, int com) { theCommanders[com].logDoCommand(0, aSide, true); } /** * Reject for a side */ void rejectSide(int aSide, int com) { theCommanders[com].logDoCommand(1, aSide, false); } /* * Abstract methods from AbstractConfigurable which are implemented here */ public String[] getAttributeDescriptions() { return new String[] { "Name of first side", "Name of second side", "OCS Module" }; } public Class<?>[] getAttributeTypes() { return new Class<?>[] { String.class, String.class, ModuleConfig.class }; } public static class ModuleConfig implements ConfigurerFactory { public Configurer getConfigurer(AutoConfigurable c, String key, String name) { return new StringEnumConfigurer(key, name, new String[] { "Baltic Gap", "Case Blue", "DAK", "Korea", "Tunisia", "Hube's Pocket", "Sicily", "Burma", "The Blitzkrieg Legend", "Hungarian Rhapsody", "Reluctant Enemies", "Beyond The Rhine", "Italy" }); } } /* * Abstract methods from AbstractBuildable which are implemented here */ public String[] getAttributeNames() { return new String[] { "FIRST", "SECOND", "MODULE" }; } public void setAttribute(String key, Object value) { if (value instanceof String) { String s = (String) value; if (key.equals("FIRST")) { theSides[0].name = s; } else if (key.equals("SECOND")) { theSides[1].name = s; } else if (key.equals("BG")) { if (Boolean.valueOf(s)) module = BalticGap; } else if (key.equals("CB")) { if (Boolean.valueOf(s)) module = CaseBlue; } else if (key.equals("DAK")) { if (Boolean.valueOf(s)) module = DAK; } else if (key.equals("K")) { if (Boolean.valueOf(s)) module = Korea; } else if (key.equals("T")) { if (Boolean.valueOf(s)) module = Tunisia; } else if (key.equals("MODULE")) { if (value.equals("Baltic Gap")) { module = BalticGap; } else if (value.equals("Case Blue")) { module = CaseBlue; } else if (value.equals("DAK")) { module = DAK; } else if (value.equals("Korea")) { module = Korea; } else if (value.equals("Tunisia")) { module = Tunisia; } else if (value.equals("Hube's Pocket")) { module = Hubes; } else if (value.equals("Sicily")) { module = Sicily; } else if (value.equals("Burma")) { module = Burma; } else if (value.equals("The Blitzkrieg Legend")) { module = TBL; } else if (value.equals("Hungarian Rhapsody")) { module = HR; } else if (value.equals("Reluctant Enemies")) { module = RE; } else if (value.equals("Beyond The Rhine")) { module = BTR; } else if (value.equals("Italy")) { module = Italy; } else { module = BalticGap; } } } } public String getAttributeValueString(String key) { if (key.equals("FIRST")) { return theSides[0].name; } else if (key.equals("SECOND")) { return theSides[1].name; } else if (key.equals("MODULE")) { switch (module) { default: case BalticGap: return "Baltic Gap"; case CaseBlue: return "Case Blue"; case DAK: return "DAK"; case Korea: return "Korea"; case Tunisia: return "Tunisia"; case Hubes: return "Hube's Pocket"; case Sicily: return "Sicily"; case Burma: return "Burma"; case TBL: return "The Blitzkrieg Legend"; case HR: return "Hungarian Rhapsody"; case RE: return "Reluctant Enemies"; case BTR: return "Beyond The Rhine"; case Italy: return "Italy"; } } return null; } /* * Abstract methods from Buildable which are implemented here */ /** * Create all the objects which are going to hang off the task bar here. * * @param parent */ public void addTo(Buildable parent) { if (parent instanceof ToolBarComponent) { toolbar = ((ToolBarComponent) parent).getToolBar(); createNormalEntries(); createDebugEntries(); } /* * Add this object to lists of those which encode/decode commands and * to list of those that save game information */ GameModule.getGameModule().addCommandEncoder(this); GameModule.getGameModule().getGameState().addGameComponent(this); /* * Create the preferences in case they don't exist */ GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new BooleanConfigurer(HIDDEN_MOVEMENT_OFF, "OCS - Disable all Fog Of War", Boolean.FALSE)); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new StringEnumConfigurer(ZONE_SECURITY, "OCS - Display of pieces in off-map boxes", new String[] { "Visible", "Masked", "Invisible" })); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new BooleanConfigurer(RANGE_IN_USE, "OCS - Enable range based extra Fog Of War", Boolean.FALSE)); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new IntConfigurer( RANGE_AIR_HIDDEN, "OCS - Range at which air units become invisible", new Integer(40))); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new IntConfigurer( RANGE_HIDDEN, "OCS - Range at which land/sea units become invisible", new Integer(20))); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new IntConfigurer(RANGE_CONCEALED, "OCS - Range at which units become masked", new Integer(10))); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new IntConfigurer( RANGE_FLAT, "OCS - Range at which stacks are shown as a single counter", new Integer(5))); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new BooleanConfigurer(USE_FORMATIONS, "OCS - Enable Formation Markers as in 13.7", Boolean.FALSE)); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new BooleanConfigurer(HEX_RANGES, "OCS - Range Options use hexes rather than radii", Boolean.FALSE)); GameModule.getGameModule().getPrefs().addOption(Resources.getString("Prefs.general_tab"), new BooleanConfigurer(USE_NEAREST_AEP, "OCS - Use nearest AEP (rather than minimal distance)", Boolean.FALSE)); /* * Listen for chnages to user name / password */ GameModule.getGameModule().getPrefs().getOption(GameModule.REAL_NAME) .addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { userIdChanged(); } }); GameModule.getGameModule().getPrefs().getOption(GameModule.SECRET_NAME) .addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { userIdChanged(); } }); /* * Get the main map */ List<Map> a = GameModule.getGameModule().getAllDescendantComponentsOf(Map.class); theMap = a.get(0); /* * Get the hex size from the main map */ List<BoardPicker> b = theMap.getAllDescendantComponentsOf(BoardPicker.class); if (!b.isEmpty()) { BoardPicker c = b.get(0); String[] boards = c.getAllowableBoardNames(); if (boards.length != 0) { Board d = c.getBoard(boards[0]); List<HexGrid> e = d.getAllDescendantComponentsOf(HexGrid.class); if (!e.isEmpty()) { HexGrid h = e.get(0); hexSize = h.getDy(); } } } } /* * Names of the extra preferences needed for OCS FOW */ public final static String HIDDEN_MOVEMENT_OFF = "OCS-hiddenoff"; public final static String RANGE_IN_USE = "OCS-userange"; public final static String ZONE_SECURITY = "OCS-zonesecurity"; public final static String RANGE_AIR_HIDDEN = "OCS-rangeairhide"; public final static String RANGE_HIDDEN = "OCS-rangehide"; public final static String RANGE_CONCEALED = "OCS-rangeconceal"; public final static String RANGE_FLAT = "OCS-rangeFlat"; public final static String USE_NEAREST_AEP = "OCS-usenearestaep"; public final static String USE_FORMATIONS = "OCS-useformations"; public final static String HEX_RANGES = "OCS-usehexranges"; /* * Abstract methods from Configurable which are implemented here */ public Class<?>[] getAllowableConfigureComponents() { return new Class[0]; } public HelpFile getHelpFile() { return null; } public void removeFrom(Buildable parent) { } /* * Methods from the GameComponent interface which are implemented here */ /** * Notify the GameComponent that a game has started/ended * * @param gameStarting if true, a game is starting. If false, then a game is * ending */ public void setup(boolean gameStarting) { hexZones = null; if (!gameStarting) { /* * Read the preferences for hidden movement. If this is a save game * about to be loaded then these will be overridden from the save file */ hiddenMovementOff = Boolean.TRUE .equals(GameModule.getGameModule().getPrefs().getValue(HIDDEN_MOVEMENT_OFF)); rangeInUse = Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(RANGE_IN_USE)); useFormations = Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(USE_FORMATIONS)); hexRanges = Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(HEX_RANGES)); Object o = GameModule.getGameModule().getPrefs().getValue(ZONE_SECURITY); if (o instanceof String) { String a = ((String) o); if (a.equals("Visible")) { zoneSecurity = OcsCounter.VISIBLE; } else if (a.equals("Masked")) { zoneSecurity = OcsCounter.CONCEALED; } else if (a.equals("Invisible")) { zoneSecurity = OcsCounter.HIDDEN; } } o = GameModule.getGameModule().getPrefs().getValue(RANGE_AIR_HIDDEN); if (o instanceof Integer) { hexRangeAirHidden = ((Integer) o).intValue(); rangeAirHidden = convertHexesToPixels(hexRangeAirHidden); } o = GameModule.getGameModule().getPrefs().getValue(RANGE_HIDDEN); if (o instanceof Integer) { hexRangeHidden = ((Integer) o).intValue(); rangeHidden = convertHexesToPixels(hexRangeHidden); } o = GameModule.getGameModule().getPrefs().getValue(RANGE_CONCEALED); if (o instanceof Integer) { hexRangeConcealed = ((Integer) o).intValue(); rangeConcealed = convertHexesToPixels(hexRangeConcealed); } o = GameModule.getGameModule().getPrefs().getValue(RANGE_FLAT); if (o instanceof Integer) { hexRangeFlattened = ((Integer) o).intValue(); rangeFlattened = convertHexesToPixels(hexRangeFlattened); } useNearest = Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(USE_NEAREST_AEP)); curCommander = null; theSides[0].controlled = false; theSides[1].controlled = false; theCommanders = new Commander[0]; if (textLaunch != null) { textLaunch.setEnabled(false); } instructions.setEnabled(false); } else { userIdChanged(); if (textLaunch != null) { textLaunch.setEnabled(true); } instructions.setEnabled(scenarioInstructions != null); } } /** * Read the current value of the preference */ static void readUseNearest() { useNearest = Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(USE_NEAREST_AEP)); } /** * When saving a game, each GameComponent should return a {@link * Command} that, when executed, restores the GameComponent to its state * when the game was saved If this component has no persistent state, return * null */ public Command getRestoreCommand() { if (GameModule.getGameModule().getArchiveWriter() != null) { return new RestoreStaticsScenarioCommand(); } return new RestoreStaticsCommand(); } /* * Encode/decode OCS Special commands */ static public final String OCS_RESTORE = "OCS-res\t"; static public final String OCS_SCENARIO = "OCS-scen\t"; static public final String OCS_BOARD = "OCS-board\t"; static public final String OCS_COMMANDER = "OCS-cmd\t"; static public final String OCS_VIEWS = "OCS-views\t"; static public final String OCS_NEW_VIEW = "OCS-new-view\t"; static public final String OCS_MVD_VIEW = "OCS-moved-view\t"; public String encode(Command c) { if (c instanceof MapOverride.RestoreRestrict) { MapOverride.RestoreRestrict d = (MapOverride.RestoreRestrict) c; SequenceEncoder se = new SequenceEncoder('\t'); d.appendTo(se); return OCS_VIEWS + se.getValue(); } if (c instanceof MapOverride.NewRestrict) { MapOverride.NewRestrict d = (MapOverride.NewRestrict) c; SequenceEncoder se = new SequenceEncoder('\t'); d.appendTo(se); return OCS_NEW_VIEW + se.getValue(); } if (c instanceof MapOverride.MovedRestrict) { MapOverride.MovedRestrict d = (MapOverride.MovedRestrict) c; SequenceEncoder se = new SequenceEncoder('\t'); d.appendTo(se); return OCS_MVD_VIEW + se.getValue(); } if (c instanceof RestoreBoardCommand) { RestoreBoardCommand d = (RestoreBoardCommand) c; SequenceEncoder se = new SequenceEncoder('\t'); se.append(d.mapName); se.append(d.boardName); se.append(d.lines.length); for (int i = 0; i < d.lines.length; i++) { se.append(d.lines[i].text); se.append(d.lines[i].font); se.append(d.lines[i].height); se.append(d.lines[i].y); se.append(d.lines[i].width); } return OCS_BOARD + se.getValue(); } if (c instanceof RestoreStaticsCommand) { RestoreStaticsCommand d = (RestoreStaticsCommand) c; SequenceEncoder se = new SequenceEncoder('\t'); se.append(d.hiddenMovementOff); se.append(d.rangeInUse); se.append(d.zoneSecurity); se.append(d.rangeAirHidden); se.append(d.rangeHidden); se.append(d.rangeConcealed); se.append(d.rangeFlattened); se.append(d.theCommanders.length); for (int i = 0; i < d.theCommanders.length; i++) { se.append(d.theCommanders[i].name); se.append(d.theCommanders[i].password); se.append(d.theCommanders[i].sidesCommanded[0]); se.append(d.theCommanders[i].sidesCommanded[1]); se.append(d.theCommanders[i].sidesRequested[0]); se.append(d.theCommanders[i].sidesRequested[1]); se.append(d.theCommanders[i].sidesRejected[0]); se.append(d.theCommanders[i].sidesRejected[1]); se.append(d.theCommanders[i].sidesAccepted[0]); se.append(d.theCommanders[i].sidesAccepted[1]); } if (d.scenInstr == null) { se.append(0); } else { se.append(d.scenInstr.length); for (int i = 0; i < d.scenInstr.length; i++) { se.append(d.scenInstr[i]); } } se.append(d.useFormations); se.append(d.hexRanges); return OCS_RESTORE + se.getValue(); } if (c instanceof RestoreStaticsScenarioCommand) { RestoreStaticsScenarioCommand d = (RestoreStaticsScenarioCommand) c; SequenceEncoder se = new SequenceEncoder('\t'); if (d.scenInstr == null) { se.append(0); } else { se.append(d.scenInstr.length); for (int i = 0; i < d.scenInstr.length; i++) { se.append(d.scenInstr[i]); } } return OCS_SCENARIO + se.getValue(); } if (c instanceof CommanderCommand) { CommanderCommand d = (CommanderCommand) c; SequenceEncoder se = new SequenceEncoder('\t'); se.append(d.name); se.append(d.password); se.append(d.command); se.append(d.side); se.append(d.state); return OCS_COMMANDER + se.getValue(); } return null; } public Command decode(String command) { if (command.startsWith(OCS_VIEWS)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); String m = st.nextToken(); Map n = Map.getMapById(m); if (n == null) return null; return ((MapOverride) n).createRestoreRestrict(st); } if (command.startsWith(OCS_NEW_VIEW)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); String m = st.nextToken(); Map n = Map.getMapById(m); return ((MapOverride) n).createNewRestrict(st); } if (command.startsWith(OCS_MVD_VIEW)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); String m = st.nextToken(); Map n = Map.getMapById(m); return ((MapOverride) n).createMovedRestrict(st); } if (command.startsWith(OCS_BOARD)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); String m = st.nextToken(); String b = st.nextToken(); int k = st.nextInt(0); Line[] l; l = new Line[k]; for (int i = 0; i < k; i++) { l[i] = new Line(); l[i].text = st.nextToken(); l[i].font = st.nextInt(0); l[i].height = st.nextInt(32); l[i].y = st.nextInt(24); l[i].width = st.nextInt(500); } return new RestoreBoardCommand(m, b, l); } if (command.startsWith(OCS_RESTORE)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); RestoreStaticsCommand c = new RestoreStaticsCommand(st.nextBoolean(false), st.nextBoolean(false), st.nextInt(OcsCounter.VISIBLE), st.nextInt(40), st.nextInt(20), st.nextInt(10), st.nextInt(5), st.nextInt(0)); for (int i = 0; i < c.theCommanders.length; i++) { c.theCommanders[i] = new Commander(st.nextToken(), st.nextToken()); c.theCommanders[i].sidesCommanded[0] = st.nextBoolean(false); c.theCommanders[i].sidesCommanded[1] = st.nextBoolean(false); c.theCommanders[i].sidesRequested[0] = st.nextBoolean(false); c.theCommanders[i].sidesRequested[1] = st.nextBoolean(false); c.theCommanders[i].sidesRejected[0] = st.nextBoolean(false); c.theCommanders[i].sidesRejected[1] = st.nextBoolean(false); c.theCommanders[i].sidesAccepted[0] = st.nextBoolean(false); c.theCommanders[i].sidesAccepted[1] = st.nextBoolean(false); } int k = st.nextInt(0); if (k != 0) { c.scenInstr = new String[k]; for (int i = 0; i < k; i++) { c.scenInstr[i] = st.nextToken(); } } c.useFormations = st.nextBoolean(false); c.hexRanges = st.nextBoolean(false); return c; } if (command.startsWith(OCS_SCENARIO)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); RestoreStaticsScenarioCommand c = new RestoreStaticsScenarioCommand(true); int k = st.nextInt(0); if (k != 0) { c.scenInstr = new String[k]; for (int i = 0; i < k; i++) { c.scenInstr[i] = st.nextToken(); } } return c; } if (command.startsWith(OCS_COMMANDER)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); return new CommanderCommand(st.nextToken(), st.nextToken(), st.nextInt(-1), st.nextInt(0), st.nextBoolean(false)); } if (command.startsWith(PlayerRoster.COMMAND_PREFIX)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(command, '\t'); st.nextToken(); st.nextToken(); st.nextToken(); st.nextToken(); return new NullCommand(); } return null; } /* * Special methods relating to commanders */ /** * This is called whenever the user changes his name and/or password */ void userIdChanged() { /* * Get the user's name and password */ check++; Object o; String nam = "test"; String password = "xyz"; o = GameModule.getGameModule().getPrefs().getValue(GameModule.REAL_NAME); if (o instanceof String) { nam = (String) o; } o = GameModule.getGameModule().getPrefs().getValue(GameModule.SECRET_NAME); if (o instanceof String) { password = (String) o; } /* * Remove old user */ curCommander = null; theSides[0].controlled = false; theSides[1].controlled = false; /* * If special user then controls both sides ( only in debug mode ) */ if (this instanceof Debug && nam.equals("Sauron") && password.equals("TheDarkLord")) { theSides[0].controlled = true; theSides[1].controlled = true; return; } /* * Does the new user match an existing user */ int i; for (i = 0; i < theCommanders.length; i++) { if (theCommanders[i].name.equals(nam) && theCommanders[i].password.equals(password)) { theSides[0].controlled = theCommanders[i].sidesCommanded[0]; theSides[1].controlled = theCommanders[i].sidesCommanded[1]; curCommander = theCommanders[i]; for (int j = 0; j < 2; j++) { if (curCommander.sidesRejected[j]) { GameModule.getGameModule().getChatter() .show("Sorry but you have been rejected by the " + theSides[j].name + " side"); curCommander.sidesRejected[j] = false; } else if (curCommander.sidesAccepted[j]) { GameModule.getGameModule().getChatter() .show("You have successfully joined the " + theSides[j].name + " side"); curCommander.sidesAccepted[j] = false; } } return; } } curCommander = new Commander(nam, password); addNewCommander(curCommander); } /** * Add a new commander to the list */ static void addNewCommander(Commander c) { Commander[] x = new Commander[theCommanders.length + 1]; if (theCommanders.length != 0) { System.arraycopy(theCommanders, 0, x, 0, theCommanders.length); } x[theCommanders.length] = c; theCommanders = x; Statics.check++; theMap.repaint(); } /** * List of hex zones on the current map */ List<OcsHexZone> hexZones; /** * Build list of hex zones */ void buildHexZoneList() { if (hexZones != null) return; Collection<Board> bs = theMap.getBoards(); hexZones = new ArrayList<OcsHexZone>(); for (Board b : bs) { hexZones.addAll(b.getAllDescendantComponentsOf(OcsHexZone.class)); } for (OcsHexZone h : hexZones) { h.convertHexNameToPoint(); } } /** * Returns hex zone if point is a hex shadowed by a hex zone */ OcsHexZone isHexZone(Point p) { buildHexZoneList(); for (OcsHexZone h : hexZones) { if (h.theHex != null && p.equals(h.theHex)) return h; } return null; } }