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}