001package squidpony.squidai;
002
003import squidpony.annotation.GwtIncompatible;
004import squidpony.squidgrid.FOVCache;
005import squidpony.squidgrid.Radius;
006import squidpony.squidmath.Coord;
007
008import java.util.ArrayList;
009import java.util.LinkedHashMap;
010import java.util.Set;
011
012/**
013 * Area of Effect interface meant to be implemented by various specific burst, line, flowing, and user-made AOE types.
014 * Created by Tommy Ettinger on 5/8/2015.
015 */
016public interface AOE {
017    /**
018     * After an AOE has been constructed, it may need to have the affected area shifted over to a different position
019     * without changing any other properties of the AOE. Some AOE implementations may have an origin where the AOE
020     * starts emanating from, but the origin will not be affected by this method; instead the cell specified by target
021     * must be enough on its own to select a different target area without the producer of the AOE needing to move.
022     * @param aim a  that will be used to change the location of the AOE without its producer needing to move
023     */
024    void shift(Coord aim);
025
026    /**
027     * Given a Set of Points that the producer of the AOE wants to include in the region of this AOE, this method does
028     * a quick approximation to see if there is any possibility that the AOE as currently configured might include one
029     * of those Points within itself. It does not do a full, detailed scan, nor does it count how many opponents might
030     * be included. It does not check the map to verify that there is any sort of path to a target. It is recommended
031     * that the Set of Points consist only of enemies that are within FOV, which cuts down a lot on the amount of checks
032     * this needs to make; if the game doesn't restrict the player's FOV, this is still recommended (just with a larger
033     * FOV radius) because it prevents checking enemies on the other side of the map and through multiple walls.
034     * @param targets a Set of Points that are desirable targets to include in this AOE
035     * @return true if there could be at least one target within the AOE, false otherwise. Very approximate.
036     */
037    boolean mayContainTarget(Set<Coord> targets);
038
039    /**
040     * Returns a LinkedHashMap of Coord keys and ArrayList of Coord values, where each Coord key is an ideal location to
041     * hit as many of the Points in targets as possible without hitting any Points in requiredExclusions, and each value
042     * is the collection of targets that will be hit if the associated key is used. The length of any ArrayList in the
043     * returned collection's values will be the number of targets likely to be affected by the AOE when shift() is
044     * called with the Coord key as an argument; all of the ArrayLists should have the same length. The second argument
045     * may be null, in which case this will initialize it to an empty Set of Coord and disregard it.
046     *
047     * With complex maps and varied arrangements of obstacles and desirable targets, calculating the best points to
048     * evaluate for AI can be computationally difficult. This method provides a way to calculate with good accuracy
049     * the best Points to pass to shift(Coord) before calling findArea(). For "blackened thrash industrial death metal"
050     * levels of brutality for the AI, the results of this can be used verbatim, but for more reasonable AI levels, you
051     * can intentionally alter the best options to simulate imperfect aim or environmental variance on the AOE.
052     *
053     * Beast-like creatures that do not need devious AI should probably not use this method at all and instead use
054     * shift(Coord) with the location of some enemy (probably the closest) as its argument.
055     * @param targets a Set of Points that are desirable targets to include in this AOE
056     * @param requiredExclusions a Set of Points that this tries strongly to avoid including in this AOE
057     * @return a LinkedHashMap of Coord keys and ArrayList of Coord values where keys are ideal locations and values are the target points that will be hit when that key is used.
058     */
059    LinkedHashMap<Coord, ArrayList<Coord>> idealLocations(Set<Coord> targets, Set<Coord> requiredExclusions);
060
061    /**
062     * A variant of idealLocations that takes two groups of desirable targets, and will rate locations by how many
063     * priorityTargets are in the AOE, then by how many lesserTargets are in the AOE, and will only consider locations
064     * that do not affect a Coord in requiredExclusions. Unlike the variant of idealLocations that only takes one group
065     * of targets, this variant can return a collection with ArrayList values where the same Coord appears four times
066     * in the same ArrayList; this is done only for priorityTargets that are affected by the target Coord at the
067     * associated key, and is done so that the length of each similar-quality ArrayList should be identical (since a
068     * priorityTarget is worth four times what a lesserTarget is worth in the calculation this uses).
069     * @param priorityTargets A Set of Points that are the most-wanted targets to include in this AOE
070     * @param lesserTargets A Set of Points that are the less-wanted targets to include in this AOE, should not overlap with priorityTargets
071     * @param requiredExclusions a Set of Points that this tries strongly to avoid including in this AOE
072     * @return a LinkedHashMap of Coord keys and ArrayList of Coord values where keys are ideal locations and values are the target points that will be hit when that key is used.
073     */
074    LinkedHashMap<Coord, ArrayList<Coord>> idealLocations(Set<Coord> priorityTargets, Set<Coord> lesserTargets, Set<Coord> requiredExclusions);
075
076    /**
077     * This must be called before any other methods, and takes a char[][] with '#' for walls, anything else for floors.
078     * It must be bounded with walls, which DungeonGenerator does automatically.
079     * @param map width first, height second, 2D char array.
080     */
081    void setMap(char[][] map);
082
083    /**
084     * This is how an AOE interacts with anything that uses it. It expects a map to have already been set with setMap,
085     * with '#' for walls, '.' for floors and potentially other chars that implementors can use if they are present in
086     * the map. The map must be bounded by walls, which DungeonGenerator does automatically and other generators can
087     * easily add with two loops.
088     *
089     * This returns a HashMap of Coord keys to Double values; if a cell is 100% affected by the AOE then the value
090     * should be 1.0; if it is 50% affected it should be 0.5, if unaffected should be 0.0, etc. The Coord keys should
091     * have the same x and y as the x,y map positions they correspond to.
092     * @return a HashMap of Coord keys to Double values from 1.0 (fully affected) to 0.0 (unaffected).
093     */
094    LinkedHashMap<Coord, Double> findArea();
095
096    /**
097     * Get the position from which the AOE originates, which may be related to the location of the AOE's effect, as for
098     * lines, cones, and other emitted effects, or may be unrelated except for determining which enemies can be seen
099     * or targeted from a given origin point (as for distant effects that radiate from a chosen central point, but
100     * have a maxRange at which they can deliver that effect).
101     */
102    Coord getOrigin();
103
104    /**
105     * Set the position from which the AOE originates, which may be related to the location of the AOE's effect, as for
106     * lines, cones, and other emitted effects, or may be unrelated except for determining which enemies can be seen
107     * or targeted from a given origin point (as for distant effects that radiate from a chosen central point, but
108     * have a maxRange at which they can deliver that effect).
109     */
110    void setOrigin(Coord origin);
111
112    /**
113     * Gets the AimLimit enum that can be used to restrict points this checks (defaults to null if not set).
114     * You can use limitType to restrict any Points that might be processed based on the given origin (which will be
115     * used as the geometric origin for any calculations this makes) with AimLimit values having the following meanings:
116     *
117     * <ul>
118     *     <li>AimLimit.FREE makes no restrictions; it is equivalent here to passing null for limit.</li>
119     *     <li>AimLimit.EIGHT_WAY will only consider Points to be valid targets
120     *     if they are along a straight line with an angle that is a multiple of 45 degrees, relative to the positive x
121     *     axis. Essentially, this limits the points to those a queen could move to in chess.</li>
122     *     <li>AimLimit.ORTHOGONAL will cause the AOE to only consider Points to be valid targets if
123     *     they are along a straight line with an angle that is a multiple of 90 degrees, relative to the positive x
124     *     axis. Essentially, this limits the points to those a rook could move to in chess.</li>
125     *     <li>AimLimit.DIAGONAL will cause the AOE to only consider Points to be valid targets if they are along a
126     *     straight line with an angle that is 45 degrees greater than a multiple of 90 degrees, relative to the
127     *     positive x axis. Essentially, this limits the points to those a bishop could move to in chess.</li>
128     *     <li>null will cause the AOE to consider all points.</li>
129     * </ul>
130     */
131    AimLimit getLimitType();
132    /**
133     * The minimum inclusive range that the AOE can be shift()-ed to using the distance measurement from radiusType.
134     */
135    int getMinRange();
136    /**
137     * The maximum inclusive range that the AOE can be shift()-ed to using the distance measurement from radiusType.
138     */
139    int getMaxRange();
140    /**
141     * Used to determine distance from origin for the purposes of selecting a target location that is within the bounds
142     * of minRange and maxRange. Not necessarily used for the implementation of the AOE (randomized-floodfill-based AOE
143     * should almost always use Manhattan distance for its spread due to how the algorithm works, but the positioning of
144     * where that floodfill should be allowed to start should likely follow the same distance measurement as the rest of
145     * the game, like Radius.SQUARE for Chebyshev distance/8-way movement).
146     */
147    Radius getMetric();
148
149    /**
150     * Gets the same values returned by getLimitType(), getMinRange(), getMaxRange(), and getMetric() bundled into one
151     * Reach object.
152     * @return a non-null Reach object.
153     */
154    Reach getReach();
155
156    /**
157     * You can use limitType to restrict any Points that might be processed based on the given origin (which will be
158     * used as the geometric origin for any calculations this makes) with AimLimit values having the following meanings:
159     *
160     * <ul>
161     *     <li>AimLimit.FREE makes no restrictions; it is equivalent here to passing null for limit.</li>
162     *     <li>AimLimit.EIGHT_WAY will only consider Points to be valid targets
163     *     if they are along a straight line with an angle that is a multiple of 45 degrees, relative to the positive x
164     *     axis. Essentially, this limits the points to those a queen could move to in chess.</li>
165     *     <li>AimLimit.ORTHOGONAL will cause the AOE to only consider Points to be valid targets if
166     *     they are along a straight line with an angle that is a multiple of 90 degrees, relative to the positive x
167     *     axis. Essentially, this limits the points to those a rook could move to in chess.</li>
168     *     <li>AimLimit.DIAGONAL will cause the AOE to only consider Points to be valid targets if they are along a
169     *     straight line with an angle that is 45 degrees greater than a multiple of 90 degrees, relative to the
170     *     positive x axis. Essentially, this limits the points to those a bishop could move to in chess.</li>
171     * </ul>
172     *
173     * Points that are not valid for this limit will simply not be considered.
174     * @param limitType an AimLimit enum
175     */
176    void setLimitType(AimLimit limitType);
177    /**
178     * The minimum inclusive range that the AOE can be shift()-ed to using the distance measurement from radiusType.
179     */
180    void setMinRange(int minRange);
181    /**
182     * The maximum inclusive range that the AOE can be shift()-ed to using the distance measurement from radiusType.
183     */
184    void setMaxRange(int maxRange);
185    /**
186     * Used to determine distance from origin for the purposes of selecting a target location that is within the bounds
187     * of minRange and maxRange. Not necessarily used for the implementation of the AOE (randomized-floodfill-based AOE
188     * should almost always use Manhattan distance for its spread due to how the algorithm works, but the positioning of
189     * where that floodfill should be allowed to start should likely follow the same distance measurement as the rest of
190     * the game, like Radius.SQUARE for Chebyshev distance/8-way movement).
191     */
192    void setMetric(Radius metric);
193
194    /**
195     * Sets the same values as setLimitType(), setMinRange(), setMaxRange(), and setMetric() using one Reach object.
196     * @param reach a non-null Reach object.
197     */
198    void setReach(Reach reach);
199
200    /**
201     * If you use FOVCache to pre-compute FOV maps for a level, you can share the speedup from using the cache with
202     * some AOE implementations that rely on FOV. Not all implementations need to actually make use of the cache, but
203     * those that use FOV for calculations should benefit. The cache parameter this receives should have completed its
204     * calculations, which can be confirmed by calling awaitCache(). Ideally, the FOVCache will have done its initial
205     * calculations in another thread while the previous level or menu was being displayed, and awaitCache() will only
206     * be a formality.
207     * @param cache The FOVCache for the current level; can be null to stop using the cache
208     */
209    @GwtIncompatible
210    void setCache(FOVCache cache);
211
212}