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