// // @(#)GUIBuild.java 12/2002 // // Copyright 2002 Zachary DelProposto. All rights reserved. // Use is subject to license terms. // // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. // Or from http://www.gnu.org/ // package dip.gui.order; import dip.order.Build; import dip.order.Orderable; import dip.order.ValidationOptions; import dip.gui.order.GUIOrder.MapInfo; import dip.misc.Utils; import dip.world.Position; import dip.world.Location; import dip.world.Province; import dip.world.Unit; import dip.world.Power; import dip.world.RuleOptions; import dip.process.Adjustment.AdjustmentInfoMap; import dip.process.Adjustment; import java.awt.geom.Point2D; import org.apache.batik.util.SVGConstants; import org.apache.batik.util.CSSConstants; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.w3c.dom.svg.*; import dip.gui.map.MapMetadata; import dip.gui.map.DefaultMapRenderer2; import dip.gui.map.SVGUtils; import java.awt.geom.Point2D; import org.apache.batik.util.SVGConstants; import org.apache.batik.util.CSSConstants; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.dom.util.XLinkSupport; import org.w3c.dom.svg.*; import org.w3c.dom.*; /** * GUIOrder implementation of Build order. * * */ public class GUIBuild extends Build implements GUIOrder { // BuildParameter constants /** Required. Used to set build Unit.Type. Associated value must be a Unit.Type */ public transient static final BuildParameter BUILD_UNIT = new BuildParameter("BUILD_UNIT"); // i18n keys private static final String BUILD_FLEET_OK = "GUIBuild.ok.fleet"; private static final String BUILD_ARMY_OK = "GUIBuild.ok.army"; private static final String BUILD_WING_OK = "GUIBuild.ok.wing"; private static final String NOBUILD_FLEET_LANDLOCKED = "GUIBuild.bad.fleet.landlocked"; private static final String NOBUILD_NO_ARMY_IN_SEA = "GUIBuild.bad.army_in_sea"; private static final String NOBUILD_NO_UNIT_SELECTED = "GUIBuild.bad.no_unit_selected"; private static final String NOBUILD_MUST_BE_AN_OWNED_SC = "GUIBuild.bad.must_own_sc"; private static final String NOBUILD_NOT_OWNED_HOME_SC = "GUIBuild.bad.now_owned_home_sc"; private static final String NOBUILD_NEED_ONE_OWNED_SC = "GUIBuild.bad.need_one_owned_sc"; private static final String NOBUILD_NO_BUILDS_AVAILABLE = "GUIBuild.bad.no_builds_available"; private static final String NOBUILD_SC_NOT_CONTROLLED = "GUIBuild.bad.sc_not_controlled"; private static final String NOBUILD_UNIT_PRESENT = "GUIBuild.bad.unit_already_present"; private static final String NOBUILD_UNOWNED_SC = "GUIBuild.bad.unowned_sc"; // instance variables private transient final static int REQ_LOC = 1; private transient int currentLocNum = 0; private transient Point2D.Float failPt = null; private transient SVGGElement group = null; /** Creates a GUIBuild */ protected GUIBuild() { super(); }// GUIBuild() /** Creates a GUIBuild */ protected GUIBuild(Power power, Location source, Unit.Type sourceUnitType) { super(power, source, sourceUnitType); }// GUIBuild() /** This only accepts Build orders. All others will throw an IllegalArgumentException. */ public void deriveFrom(Orderable order) { if( !(order instanceof Build) ) { throw new IllegalArgumentException(); } Build build = (Build) order; power = build.getPower(); src = build.getSource(); srcUnitType = build.getSourceUnitType(); // set completed currentLocNum = REQ_LOC; }// deriveFrom() public boolean testLocation(StateInfo stateInfo, Location location, StringBuffer sb) { sb.setLength(0); if(isComplete()) { sb.append( Utils.getLocalString(GUIOrder.COMPLETE, getFullName()) ); return false; } Position position = stateInfo.getPosition(); Province province = location.getProvince(); if(province.hasSupplyCenter()) { Power SCOwner = position.getSupplyCenterOwner(province); // general screening, applicable to all build options // if(SCOwner == null) { sb.append( Utils.getLocalString(NOBUILD_UNOWNED_SC) ); return false; } if(position.hasUnit(province)) { sb.append( Utils.getLocalString(NOBUILD_UNIT_PRESENT) ); return false; } if( !stateInfo.canIssueOrder(SCOwner) ) { sb.append( Utils.getLocalString(NOBUILD_SC_NOT_CONTROLLED) ); return false; } // indicate if we have no builds available // Adjustment.AdjustmentInfo adjInfo = stateInfo.getAdjustmenInfoMap().get(SCOwner); if(adjInfo.getAdjustmentAmount() <= 0) { sb.append( Utils.getLocalString(NOBUILD_NO_BUILDS_AVAILABLE, SCOwner.getName()) ); return false; } // build-option-specific, based upon RuleOptions // RuleOptions ruleOpts = stateInfo.getRuleOptions(); if(ruleOpts.getOptionValue(RuleOptions.OPTION_BUILDS) == RuleOptions.VALUE_BUILDS_ANY_OWNED) { return checkBuildUnit(stateInfo, province, location, sb); } else if(ruleOpts.getOptionValue(RuleOptions.OPTION_BUILDS) == RuleOptions.VALUE_BUILDS_ANY_IF_HOME_OWNED) { // check if we have ONE owned home supply center before buidling // in a non-home supply center. // if( SCOwner != position.getSupplyCenterHomePower(province) && !position.hasAnOwnedHomeSC(SCOwner) ) { sb.append( Utils.getLocalString(NOBUILD_NEED_ONE_OWNED_SC) ); return false; // failed } // we (probably) can build here return checkBuildUnit(stateInfo, province, location, sb); } else { // build only in owned HOME supply centers // if(SCOwner == position.getSupplyCenterHomePower(province)) { // we (probably) can build here return checkBuildUnit(stateInfo, province, location, sb); } // build failure. sb.append( Utils.getLocalString(NOBUILD_NOT_OWNED_HOME_SC) ); return false; } } else { sb.append( Utils.getLocalString(NOBUILD_MUST_BE_AN_OWNED_SC) ); return false; } // NO return here: thus we must appropriately exit within an if/else block above. }// testLocation() public boolean clearLocations() { if(isComplete()) { return false; } currentLocNum = 0; power = null; src = null; //srcUnitType: not cleared return true; }// clearLocations() public boolean setLocation(StateInfo stateInfo, Location location, StringBuffer sb) { if(testLocation(stateInfo, location, sb)) { currentLocNum++; src = new Location(location.getProvince(), location.getCoast()); power = stateInfo.getPosition().getSupplyCenterOwner(location.getProvince()); // srcUnitType: already defined assert (srcUnitType != null); sb.setLength(0); sb.append( Utils.getLocalString(GUIOrder.COMPLETE, getFullName()) ); return true; } return false; }// setLocation() public boolean isComplete() { assert (currentLocNum <= getNumRequiredLocations()); return (currentLocNum == getNumRequiredLocations()); }// isComplete() public int getNumRequiredLocations() { return REQ_LOC; } public int getCurrentLocationNum() { return currentLocNum; } /** Used to set what type of Unit we are building. Value must be a Unit.Type */ public void setParam(Parameter param, Object value) { if(param != BUILD_UNIT || !(value instanceof Unit.Type)) { throw new IllegalArgumentException(); } srcUnitType = (Unit.Type) value; }// setParam() /** Used to set what type of Unit we are building. */ public Object getParam(Parameter param) { if(param != BUILD_UNIT) { throw new IllegalArgumentException(); } return srcUnitType; }// getParam() public void removeFromDOM(MapInfo mapInfo) { if(group != null) { SVGGElement powerGroup = mapInfo.getPowerSVGGElement(power, LAYER_HIGHEST); GUIOrderUtils.removeChild(powerGroup, group); group = null; } }// removeFromDOM() /** Places a unit in the desired area. */ public void updateDOM(MapInfo mapInfo) { // if we are not displayable, we exit, after remove the order (if // it was created) if( !GUIOrderUtils.isDisplayable(power, mapInfo) ) { removeFromDOM(mapInfo); return; } // determine if any change has occured. If no change has occured, // we will not change the DOM. // // we have nothing (yet) to check for change; isDependent() == false. // so just return if we have not been drawn. if(group != null) { return; } // there has been a change, if we are at this point. // // if we've not yet been created, we will create; if we've // already been created, we must remove the existing elements // in our group if(group == null) { // create group group = (SVGGElement) mapInfo.getDocument().createElementNS( SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_G_TAG); group.setId("order_" + this.src.toString()); mapInfo.getPowerSVGGElement(power, LAYER_HIGHEST).appendChild(group); } else { // remove group children GUIOrderUtils.deleteChildren(group); } // now, render the order // (no highlight + shadow required here) // no offset required // SVGElement[] elements = drawOrder(mapInfo); for(int i=0; i<elements.length; i++) { group.appendChild(elements[i]); } // draw 'failed' marker, if appropriate. if(!mapInfo.getTurnState().isOrderSuccessful(this)) { SVGElement useElement = GUIOrderUtils.createFailedOrderSymbol(mapInfo, failPt.x, failPt.y); group.appendChild(useElement); } }// updateDOM() public SVGElement orderSVG(MapInfo mapInfo){ updateDOM(mapInfo); return group; } private SVGElement[] drawOrder(MapInfo mapInfo) { MapMetadata mmd = mapInfo.getMapMetadata(); Point2D.Float center = mmd.getUnitPt(src.getProvince(), src.getCoast()); // get 'integer' and float data float radius = mmd.getOrderRadius(MapMetadata.EL_BUILD, mapInfo.getSymbolName(srcUnitType)); // calculate failPt. failPt = new Point2D.Float(center.x + radius, center.y - radius); // A BUILD consists of the Built Unit ontop of a BuildUnit symbol // elements added in drawing order (thus BuildUnit must come first, // otherwise the unit built will be obscured by the BuilUnit symbol). // SVGElement[] elements = new SVGElement[2]; // BuildUnit symbol MapMetadata.SymbolSize symbolSize = mmd.getSymbolSize(DefaultMapRenderer2.SYMBOL_BUILDUNIT); elements[0] = SVGUtils.createUseElement( mapInfo.getDocument(), "#"+DefaultMapRenderer2.SYMBOL_BUILDUNIT, null, // no ID null, // no special style center.x, center.y, symbolSize); // Unit symbol final String symbolName = mapInfo.getSymbolName(srcUnitType); symbolSize = mmd.getSymbolSize(symbolName); elements[1] = SVGUtils.createUseElement( mapInfo.getDocument(), "#"+symbolName, null, // no ID mapInfo.getUnitCSS(power), // unit style center.x, center.y, symbolSize); return elements; }// drawOrder() public boolean isDependent() { return false; } /** * All build options require that appropriate units are built in * appropriate places (e.g., armies can't go in the water, fleets * can't go in landlocked provinces, fleets must have coasts specified * if required, etc.). This method takes care of that. * <p> * returns false if we cannot build here. */ private boolean checkBuildUnit(StateInfo stateInfo, Province province, Location loc, StringBuffer sb) { if(srcUnitType == null) { sb.append( Utils.getLocalString(NOBUILD_NO_UNIT_SELECTED) ); return false; } if(srcUnitType.equals(Unit.Type.ARMY)) { if(province.isSea()) { sb.append( Utils.getLocalString(NOBUILD_NO_ARMY_IN_SEA) ); return false; } else { // check borders if( !GUIOrderUtils.checkBorder(this, loc, srcUnitType, stateInfo.getPhase(), sb) ) { return false; } sb.append( Utils.getLocalString(BUILD_ARMY_OK) ); return true; } } else if(srcUnitType.equals(Unit.Type.FLEET)) { if(province.isLandLocked()) { sb.append( Utils.getLocalString(NOBUILD_FLEET_LANDLOCKED) ); return false; } else { // check borders if( !GUIOrderUtils.checkBorder(this, loc, srcUnitType, stateInfo.getPhase(), sb) ) { return false; } sb.append( Utils.getLocalString(BUILD_FLEET_OK) ); return true; } } else if(srcUnitType.equals(Unit.Type.WING)) { // check borders if( !GUIOrderUtils.checkBorder(this, loc, srcUnitType, stateInfo.getPhase(), sb) ) { return false; } sb.append( Utils.getLocalString(BUILD_WING_OK) ); return true; } // this should not occur. sb.append("** Unknown unit type! **"); return false; }// checkBuildUnit() /** * Typesafe Enumerated Parameter class for setting * required Build parameters. * */ protected static class BuildParameter extends Parameter { /** Creates a BuildParameter */ public BuildParameter(String name) { super(name); }// BuildParameter() }// nested class BuildParameter }// class GUIBuild