Advertisement
Guest User

Untitled

a guest
Apr 28th, 2017
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.11 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2005 by Scott Giese, Rodney Kinney, Brent Easton
  3.  * Modified for the Warmahordes module by Malnorma Cxio.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Library General Public
  7.  * License (LGPL) as published by the Free Software Foundation.
  8.  *
  9.  * This library is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * Library General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Library General Public
  15.  * License along with this library; if not, copies are available
  16.  * at http://www.opensource.org.
  17.  */
  18. package cxio.malnorma;
  19.  
  20. import java.awt.AlphaComposite;
  21. import java.awt.Color;
  22. import java.awt.Component;
  23. import java.awt.Composite;
  24. import java.awt.Frame;
  25. import java.awt.Graphics;
  26. import java.awt.Graphics2D;
  27. import java.awt.Point;
  28. import java.awt.Rectangle;
  29. import java.awt.Shape;
  30. import java.awt.Window;
  31. import java.awt.event.ActionEvent;
  32. import java.awt.event.ActionListener;
  33. import java.awt.geom.AffineTransform;
  34. import java.awt.geom.Area;
  35. import java.awt.geom.Arc2D;
  36. import java.awt.geom.Ellipse2D;
  37. import java.beans.PropertyChangeEvent;
  38. import java.beans.PropertyChangeListener;
  39. import java.util.*;
  40.  
  41. import javax.swing.Box;
  42. import javax.swing.BoxLayout;
  43. import javax.swing.JButton;
  44. import javax.swing.JLabel;
  45. import javax.swing.JPanel;
  46. import javax.swing.JSeparator;
  47. import javax.swing.JTextField;
  48. import javax.swing.KeyStroke;
  49. import javax.swing.SwingUtilities;
  50.  
  51. import VASSAL.build.module.Map;
  52. import VASSAL.build.module.documentation.HelpFile;
  53. import VASSAL.build.module.map.MapShader;
  54. import VASSAL.build.module.map.boardPicker.Board;
  55. import VASSAL.build.module.map.boardPicker.board.GeometricGrid;
  56. import VASSAL.build.module.map.boardPicker.board.MapGrid;
  57. import VASSAL.command.ChangeTracker;
  58. import VASSAL.command.Command;
  59. import VASSAL.configure.BooleanConfigurer;
  60. import VASSAL.configure.ChooseComponentDialog;
  61. import VASSAL.configure.ColorConfigurer;
  62. import VASSAL.configure.IntConfigurer;
  63. import VASSAL.configure.NamedHotKeyConfigurer;
  64. import VASSAL.configure.StringConfigurer;
  65. import VASSAL.counters.Decorator;
  66. import VASSAL.counters.FreeRotator;
  67. import VASSAL.counters.GamePiece;
  68. import VASSAL.counters.KeyCommand;
  69. import VASSAL.counters.PieceEditor;
  70. import VASSAL.i18n.PieceI18nData;
  71. import VASSAL.i18n.Resources;
  72. import VASSAL.i18n.TranslatablePiece;
  73. import VASSAL.tools.NamedKeyStroke;
  74. import VASSAL.tools.SequenceEncoder;
  75.  
  76. /**
  77.  * @author Scott Giese sgiese@sprintmail.com
  78.  *
  79.  * Displays a transparency surrounding the GamePiece which represents the Area of Effect of the GamePiece
  80.  */
  81. public class AreaOfEffect extends Decorator implements TranslatablePiece, MapShader.ShadedPiece {
  82.   public static final String ID = "cxio.malnorma.AreaOfEffectMal;";
  83.   protected static final Color defaultTransparencyColor = Color.GRAY;
  84.   protected static final float defaultTransparencyLevel = 0.3F;
  85.   protected static final int defaultRadius = 1;
  86.  
  87.   protected Color transparencyColor;
  88.   protected List<Color> colorOptions = new ArrayList<Color>();
  89.   protected float transparencyLevel;
  90.   protected int radius;
  91.   protected boolean alwaysActive;
  92.   protected boolean active;
  93.   protected String activateCommand;
  94.   protected NamedKeyStroke activateKey;
  95.   protected KeyCommand[] commands;
  96.   protected String mapShaderName;
  97.   protected MapShader shader;
  98.   protected KeyCommand keyCommand;
  99.   protected boolean fixedRadius = true;
  100.   protected String radiusMarker = "";
  101.   protected String description = "";
  102.   protected String halfCircleMarker = "";
  103.  
  104.   public AreaOfEffect() {
  105.     this(ID + ColorConfigurer.colorToString(defaultTransparencyColor), null);
  106.   }
  107.  
  108.   public AreaOfEffect(String type, GamePiece inner) {
  109.     mySetType(type);
  110.     setInner(inner);
  111.     colorOptions.add(null);
  112.     colorOptions.add(new Color(255, 28, 45));
  113.     colorOptions.add(new Color(28, 255, 102));
  114.     colorOptions.add(new Color(20, 180, 255));
  115.     colorOptions.add(new Color(255, 255, 100));
  116.   }
  117.  
  118.   public String getDescription() {
  119.     String d = "Area Of Effect [Mal]";
  120.     if (description.length() > 0) {
  121.       d += " - " + description;
  122.     }
  123.     return d;
  124.   }
  125.  
  126.   public String myGetType() {
  127.     final SequenceEncoder se = new SequenceEncoder(';');
  128.     se.append(transparencyColor);
  129.     se.append((int) (transparencyLevel * 100));
  130.     se.append(radius);
  131.     se.append(alwaysActive);
  132.     se.append(activateCommand);
  133.     se.append(activateKey);
  134.     se.append(mapShaderName == null ? "" : mapShaderName);
  135.     se.append(fixedRadius);
  136.     se.append(radiusMarker);
  137.     se.append(description);
  138.     se.append(halfCircleMarker);
  139.  
  140.     return ID + se.getValue();
  141.   }
  142.  
  143.   public void mySetType(String type) {
  144.     final SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(type, ';');
  145.     st.nextToken();    // Discard ID
  146.     transparencyColor = st.nextColor(defaultTransparencyColor);
  147.     transparencyLevel = st.nextInt((int) (defaultTransparencyLevel * 100)) / 100.0F;
  148.     radius = st.nextInt(defaultRadius);
  149.     alwaysActive = st.nextBoolean(true);
  150.     activateCommand = st.nextToken("Show Area");
  151.     activateKey = st.nextNamedKeyStroke(null);
  152.     keyCommand = new KeyCommand(activateCommand, activateKey, Decorator.getOutermost(this), this);
  153.     mapShaderName = st.nextToken("");
  154.     if (mapShaderName.length() == 0) {
  155.       mapShaderName = null;
  156.     }
  157.     fixedRadius = st.nextBoolean(true);
  158.     radiusMarker = st.nextToken("");
  159.     description = st.nextToken("");
  160.     halfCircleMarker = st.nextToken("");
  161.     shader = null;
  162.     commands = null;
  163.   }
  164.  
  165.   // State does not change during the game
  166.   public String myGetState() {
  167.     return alwaysActive ? "" : String.valueOf(active);
  168.   }
  169.  
  170.   // State does not change during the game
  171.   public void mySetState(String newState) {
  172.     if (!alwaysActive) {
  173.       active = "true".equals(newState);
  174.     }
  175.   }
  176.  
  177.   public Rectangle boundingBox() {
  178.     // TODO: Need the context of the parent Component, because the transparency is only drawn
  179.     // on a Map.View object.  Because this context is not known, the bounding box returned by
  180.     // this method does not encompass the bounds of the transparency.  The result of this is
  181.     // that portions of the transparency will not be drawn after scrolling the Map window.
  182.     return piece.boundingBox();
  183.   }
  184.  
  185.   public Shape getShape() {
  186.     return piece.getShape();
  187.   }
  188.  
  189.   public String getName() {
  190.     return piece.getName();
  191.   }
  192.  
  193.   public void draw(Graphics g, int x, int y, Component obs, double zoom) {
  194.     if ((alwaysActive || active) && mapShaderName == null && getRadius() > 0) {
  195.       // The transparency is only drawn on a Map.View component. Only the
  196.       // GamePiece is drawn within other windows (Counter Palette, etc.).
  197.       if (obs instanceof Map.View && getMap() != null) {
  198.         final Graphics2D g2d = (Graphics2D) g;
  199.  
  200.         final Color oldColor = g2d.getColor();
  201.         int auraLevel = getAuraLayer();
  202.         g2d.setColor(transparencyColor);
  203.         if (auraLevel > 0 && auraLevel <= colorOptions.size()) {
  204.             g2d.setColor(colorOptions.get(auraLevel));
  205.         }
  206.  
  207.         final Composite oldComposite = g2d.getComposite();
  208.         g2d.setComposite(AlphaComposite.getInstance(
  209.           AlphaComposite.SRC_OVER, transparencyLevel));
  210.  
  211.         Area a = getArea();
  212.        
  213.  
  214.         if (zoom != 1.0) {
  215.           a = new Area(AffineTransform.getScaleInstance(zoom,zoom)
  216.                                       .createTransformedShape(a));
  217.         }
  218.  
  219.         g2d.fill(a);
  220.  
  221.         g2d.setColor(oldColor);
  222.         g2d.setComposite(oldComposite);
  223.       }
  224.     }
  225.  
  226.     // Draw the GamePiece
  227.     piece.draw(g, x, y, obs, zoom);
  228.   }
  229.  
  230.   protected Area getArea() {
  231.     Area a;
  232.     final Map map = getMap();
  233.     // Always draw the area centered on the piece's current position
  234.     // (For instance, don't draw it at an offset if it's in an expanded stack)
  235.     final Point mapPosition = getPosition();
  236.     final int myRadius = getRadius();
  237.  
  238.     final Board board = map.findBoard(mapPosition);
  239.     final MapGrid grid = board == null ? null : board.getGrid();
  240.  
  241.     if (grid instanceof GeometricGrid) {
  242.       final GeometricGrid gGrid = (GeometricGrid) grid;
  243.  
  244.       final Rectangle boardBounds = board.bounds();
  245.       final Point boardPosition = new Point(
  246.         mapPosition.x-boardBounds.x, mapPosition.y-boardBounds.y);
  247.  
  248.       a = gGrid.getGridShape(boardPosition, myRadius); // In board co-ords
  249.       final AffineTransform t = AffineTransform.getTranslateInstance(
  250.         boardBounds.x, boardBounds.y); // Translate back to map co-ords
  251.  
  252.       final double mag = board.getMagnification();
  253.       if (mag != 1.0) {
  254.         t.translate(boardPosition.x, boardPosition.y);
  255.         t.scale(mag, mag);
  256.         t.translate(-boardPosition.x, -boardPosition.y);
  257.       }
  258.       a = a.createTransformedArea(t);
  259.     }
  260.     else {
  261.       FreeRotator myRotation = (FreeRotator) Decorator.getDecorator(this, FreeRotator.class);
  262.       double ringWidth = 10;
  263.       double start = 0;
  264.       if (myRotation != null) {
  265.         start = myRotation.getCumulativeAngle();
  266.         while (start < 0) start += 360;
  267.       }
  268.       double innerDiff = Math.toDegrees(Math.asin(ringWidth / myRadius));
  269.       a = getHalfCircle() ?
  270.           new Area(new Arc2D.Double(mapPosition.x - myRadius,
  271.                       mapPosition.y - myRadius,
  272.                       myRadius * 2,
  273.                       myRadius * 2, start, 180, Arc2D.CHORD)) :
  274.           new Area(new Ellipse2D.Double(mapPosition.x - myRadius,
  275.                       mapPosition.y - myRadius,
  276.                       myRadius * 2,
  277.                       myRadius * 2));
  278.       a.subtract(getHalfCircle() ?
  279.             new Area(new Arc2D.Double(mapPosition.x - myRadius + ringWidth,
  280.                     mapPosition.y - myRadius + ringWidth,
  281.                     (myRadius - ringWidth) * 2,
  282.                     (myRadius - ringWidth) * 2,
  283.                     start + innerDiff, 180 - innerDiff * 2, Arc2D.CHORD))
  284.             : new Area(new Ellipse2D.Double(mapPosition.x - myRadius + ringWidth,
  285.                     mapPosition.y - myRadius + ringWidth,
  286.                     (myRadius - ringWidth) * 2,
  287.                     (myRadius - ringWidth) * 2)));
  288.     }
  289.     return a;
  290.   }
  291.  
  292.   protected int getRadius() {
  293.     if (fixedRadius) {
  294.       return radius;
  295.     }
  296.     else {
  297.       final String r =
  298.         (String) Decorator.getOutermost(this).getProperty(radiusMarker);
  299.       try {
  300.         return Integer.parseInt(r);
  301.       }
  302.       catch (NumberFormatException e) {
  303.         reportDataError(this, Resources.getString("Error.non_number_error"), "radius["+radiusMarker+"]="+r, e);
  304.         return 0;
  305.       }
  306.     }
  307.   }
  308.  
  309.   protected int getAuraLayer() {
  310.     final String r =
  311.             (String) Decorator.getOutermost(this).getProperty("Aura Color");
  312.     try {
  313.         return Integer.parseInt(r);
  314.     }
  315.     catch (NumberFormatException e) {
  316.         return 0;
  317.     }
  318.   }
  319.  
  320.   protected boolean getHalfCircle() {
  321.       final String marker = (String) Decorator.getOutermost(this).getProperty(halfCircleMarker);
  322.       int halfcircle = 0;
  323.       try {
  324.         halfcircle = Integer.parseInt(marker);
  325.       } catch (NumberFormatException e) {
  326.         // Just eat it - treat an error as 0
  327.       }
  328.       return halfcircle > 0;
  329.   }
  330.  
  331.   // No hot-keys
  332.   protected KeyCommand[] myGetKeyCommands() {
  333.     if (commands == null) {
  334.       if (alwaysActive || activateCommand.length() == 0) {
  335.         commands = new KeyCommand[0];
  336.       }
  337.       else {
  338.         commands = new KeyCommand[]{keyCommand};
  339.       }
  340.     }
  341.     return commands;
  342.   }
  343.  
  344.   // No hot-keys
  345.   public Command myKeyEvent(KeyStroke stroke) {
  346.     Command c = null;
  347.     myGetKeyCommands();
  348.     if (!alwaysActive
  349.         && keyCommand.matches(stroke)) {
  350.       final ChangeTracker t = new ChangeTracker(this);
  351.       active = !active;
  352.       c = t.getChangeCommand();
  353.     }
  354.     return c;
  355.   }
  356.  
  357.   public HelpFile getHelpFile() {
  358.     return HelpFile.getReferenceManualPage("AreaOfEffect.htm");
  359.   }
  360.  
  361.   public PieceEditor getEditor() {
  362.     return new TraitEditor(this);
  363.   }
  364.  
  365.   public Area getArea(MapShader shader) {
  366.     Area a = null;
  367.     final MapShader.ShadedPiece shaded = (MapShader.ShadedPiece) Decorator.getDecorator(piece,MapShader.ShadedPiece.class);
  368.     if (shaded != null) {
  369.       a = shaded.getArea(shader);
  370.     }
  371.     if (alwaysActive || active) {
  372.       if (shader.getConfigureName().equals(mapShaderName)) {
  373.         Area myArea = getArea();
  374.         if (a == null) {
  375.           a = myArea;
  376.         }
  377.         else {
  378.           a.add(myArea);
  379.         }
  380.       }
  381.     }
  382.     return a;
  383.   }
  384.  
  385.   protected static class TraitEditor implements PieceEditor {
  386.     protected JPanel panel;
  387.     protected ColorConfigurer transparencyColorValue;
  388.     protected IntConfigurer transparencyValue;
  389.     protected IntConfigurer radiusValue;
  390.     protected BooleanConfigurer alwaysActive;
  391.     protected StringConfigurer activateCommand;
  392.     protected NamedHotKeyConfigurer activateKey;
  393.     protected BooleanConfigurer useMapShader;
  394.     protected BooleanConfigurer fixedRadius;
  395.     protected StringConfigurer radiusMarker;
  396.     protected StringConfigurer descConfig;
  397.     protected Box selectShader;
  398.     protected String mapShaderId;
  399.     protected StringConfigurer halfCircleMarker;
  400.  
  401.     protected TraitEditor(AreaOfEffect trait) {
  402.       panel = new JPanel();
  403.       panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
  404.  
  405.       panel.add(new JLabel("Contributed by Scott Giese (sgiese@sprintmail.com)", JLabel.CENTER));
  406.       panel.add(new JSeparator());
  407.       panel.add(new JLabel(" "));
  408.  
  409.       descConfig = new StringConfigurer(null, "Description:  ", trait.description);
  410.       panel.add(descConfig.getControls());
  411.  
  412.       useMapShader = new BooleanConfigurer(null, "Use Map Shading?", trait.mapShaderName != null);
  413.       mapShaderId = trait.mapShaderName;
  414.       panel.add(useMapShader.getControls());
  415.       selectShader = Box.createHorizontalBox();
  416.  
  417.       panel.add(selectShader);
  418.       final JLabel l = new JLabel("Map Shading:  ");
  419.       selectShader.add(l);
  420.       final JTextField tf = new JTextField(12);
  421.       tf.setEditable(false);
  422.       selectShader.add(tf);
  423.       tf.setText(trait.mapShaderName);
  424.       final JButton b = new JButton("Select");
  425.       selectShader.add(b);
  426.       b.addActionListener(new ActionListener() {
  427.         public void actionPerformed(ActionEvent e) {
  428.           ChooseComponentDialog d = new ChooseComponentDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, panel), MapShader.class);
  429.           d.setVisible(true);
  430.           if (d.getTarget() != null) {
  431.             mapShaderId = d.getTarget().getConfigureName();
  432.             tf.setText(mapShaderId);
  433.           }
  434.           else {
  435.             mapShaderId = null;
  436.             tf.setText("");
  437.           }
  438.         }
  439.       });
  440.  
  441.       transparencyColorValue = new ColorConfigurer(null, "Fill Color:  ", trait.transparencyColor);
  442.       panel.add(transparencyColorValue.getControls());
  443.       transparencyValue = new IntConfigurer(null, "Opacity (%):  ", (int) (trait.transparencyLevel * 100));
  444.       panel.add(transparencyValue.getControls());
  445.  
  446.       fixedRadius = new BooleanConfigurer(null, "Fixed Radius?",
  447.                                           Boolean.valueOf(trait.fixedRadius));
  448.       fixedRadius.addPropertyChangeListener(new PropertyChangeListener() {
  449.         public void propertyChange(PropertyChangeEvent evt) {
  450.           updateRangeVisibility();
  451.         }
  452.       });
  453.       panel.add(fixedRadius.getControls());
  454.  
  455.       radiusValue = new IntConfigurer(null, "Radius: ", trait.radius);
  456.       panel.add(radiusValue.getControls());
  457.  
  458.       radiusMarker = new StringConfigurer(null, "Radius Marker: ", trait.radiusMarker);
  459.       panel.add(radiusMarker.getControls());
  460.  
  461.       alwaysActive = new BooleanConfigurer(null, "Always visible?", trait.alwaysActive ? Boolean.TRUE : Boolean.FALSE);
  462.       activateCommand = new StringConfigurer(null, "Toggle visible command:  ", trait.activateCommand);
  463.       activateKey = new NamedHotKeyConfigurer(null, "Toggle visible keyboard shortcut:  ", trait.activateKey);
  464.  
  465.       halfCircleMarker = new StringConfigurer(null, "Semicircle Marker: ", trait.halfCircleMarker);
  466.       panel.add(halfCircleMarker.getControls());
  467.  
  468.       updateRangeVisibility();
  469.  
  470.       alwaysActive.addPropertyChangeListener(new PropertyChangeListener() {
  471.         public void propertyChange(PropertyChangeEvent evt) {
  472.           updateCommandVisibility();
  473.         }
  474.       });
  475.       updateCommandVisibility();
  476.  
  477.       useMapShader.addPropertyChangeListener(new PropertyChangeListener() {
  478.         public void propertyChange(PropertyChangeEvent evt) {
  479.           updateFillVisibility();
  480.         }
  481.       });
  482.       updateFillVisibility();
  483.  
  484.       panel.add(alwaysActive.getControls());
  485.       panel.add(activateCommand.getControls());
  486.       panel.add(activateKey.getControls());
  487.     }
  488.  
  489.     protected void updateFillVisibility() {
  490.       final boolean useShader = Boolean.TRUE.equals(useMapShader.getValue());
  491.       transparencyColorValue.getControls().setVisible(!useShader);
  492.       transparencyValue.getControls().setVisible(!useShader);
  493.       selectShader.setVisible(useShader);
  494.       repack();
  495.     }
  496.  
  497.     protected void updateRangeVisibility() {
  498.       final boolean fixedRange = fixedRadius.booleanValue().booleanValue();
  499.       radiusValue.getControls().setVisible(fixedRange);
  500.       radiusMarker.getControls().setVisible(!fixedRange);
  501.       repack();
  502.     }
  503.  
  504.     protected void updateCommandVisibility() {
  505.       final boolean alwaysActiveSelected = Boolean.TRUE.equals(alwaysActive.getValue());
  506.       activateCommand.getControls().setVisible(!alwaysActiveSelected);
  507.       activateKey.getControls().setVisible(!alwaysActiveSelected);
  508.       repack();
  509.     }
  510.  
  511.     protected void repack() {
  512.       final Window w = SwingUtilities.getWindowAncestor(alwaysActive.getControls());
  513.       if (w != null) {
  514.         w.pack();
  515.       }
  516.     }
  517.  
  518.     public Component getControls() {
  519.       return panel;
  520.     }
  521.  
  522.     public String getState() {
  523.       return "false";
  524.     }
  525.  
  526.     public String getType() {
  527.       final boolean alwaysActiveSelected = Boolean.TRUE.equals(alwaysActive.getValue());
  528.       final SequenceEncoder se = new SequenceEncoder(';');
  529.       se.append(transparencyColorValue.getValueString());
  530.       se.append(transparencyValue.getValueString());
  531.       se.append(radiusValue.getValueString());
  532.       se.append(alwaysActiveSelected);
  533.       se.append(activateCommand.getValueString());
  534.       se.append(activateKey.getValueString());
  535.       if (Boolean.TRUE.equals(useMapShader.getValue()) && mapShaderId != null) {
  536.         se.append(mapShaderId);
  537.       }
  538.       else {
  539.         se.append("");
  540.       }
  541.       se.append(fixedRadius.getValueString());
  542.       se.append(radiusMarker.getValueString());
  543.       se.append(descConfig.getValueString());
  544.       se.append(halfCircleMarker.getValueString());
  545.  
  546.       return AreaOfEffect.ID + se.getValue();
  547.     }
  548.   }
  549.  
  550.   public PieceI18nData getI18nData() {
  551.     return getI18nData(activateCommand, getCommandDescription(description, "Toggle Visible command"));
  552.   }
  553. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement