package squidpony.squidai; import squidpony.annotation.GwtIncompatible; import squidpony.squidgrid.FOVCache; import squidpony.squidgrid.Radius; import squidpony.squidmath.Coord; import squidpony.squidmath.OrderedMap; import squidpony.squidmath.OrderedSet; import java.util.ArrayList; import java.util.Collection; /** * An AOE type that has a center Coord only and only affects that single Coord. Useful if you need an AOE implementation * for something that does not actually affect an area. * This will produce doubles for its findArea() method which are equal to 1.0. * * This class doesn't use any other SquidLib class to create its area of effect. * Created by Tommy Ettinger on 7/13/2015. */ public class PointAOE implements AOE { private Coord center, origin = null; private int mapWidth, mapHeight; private Reach reach = new Reach(1, 1, Radius.SQUARE, null); public PointAOE(Coord center) { this.center = center; } public PointAOE(Coord center, int minRange, int maxRange) { this.center = center; reach.minDistance = minRange; reach.maxDistance = maxRange; } public Coord getCenter() { return center; } public void setCenter(Coord center) { if (center.isWithin(mapWidth, mapHeight) && AreaUtils.verifyReach(reach, origin, center)) { this.center = center; } } @Override public void shift(Coord aim) { setCenter(aim); } @Override public boolean mayContainTarget(Collection<Coord> targets) { for (Coord p : targets) { if(center.x == p.x && center.y == p.y) return true; } return false; } @Override public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> targets, Collection<Coord> requiredExclusions) { if(targets == null) return new OrderedMap<>(); int totalTargets = targets.size(); OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets); if(totalTargets == 0) return bestPoints; double dist = 0.0; for(Coord p : targets) { if (AreaUtils.verifyReach(reach, origin, p)) { dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); if (dist <= reach.maxDistance && dist >= reach.minDistance) { ArrayList<Coord> ap = new ArrayList<>(); ap.add(p); bestPoints.put(p, ap); } } } return bestPoints; } @Override public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> priorityTargets, Collection<Coord> lesserTargets, Collection<Coord> requiredExclusions) { if(priorityTargets == null) return idealLocations(lesserTargets, requiredExclusions); if(requiredExclusions == null) requiredExclusions = new OrderedSet<>(); int totalTargets = priorityTargets.size() + lesserTargets.size(); OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets * 4); if(totalTargets == 0) return bestPoints; double dist = 0.0; for(Coord p : priorityTargets) { if (AreaUtils.verifyReach(reach, origin, p)) { dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); if (dist <= reach.maxDistance && dist >= reach.minDistance) { ArrayList<Coord> ap = new ArrayList<>(); ap.add(p); ap.add(p); ap.add(p); ap.add(p); bestPoints.put(p, ap); } } } if(bestPoints.isEmpty()) { for (Coord p : lesserTargets) { if (AreaUtils.verifyReach(reach, origin, p)) { dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); if (dist <= reach.maxDistance && dist >= reach.minDistance) { ArrayList<Coord> ap = new ArrayList<>(); ap.add(p); bestPoints.put(p, ap); } } } } return bestPoints; } /* @Override public ArrayList<ArrayList<Coord>> idealLocations(Set<Coord> targets, Set<Coord> requiredExclusions) { int totalTargets = targets.size() + 1; int maxEffect = (int)radiusType.volume2D(radius); ArrayList<ArrayList<Coord>> locs = new ArrayList<ArrayList<Coord>>(totalTargets); for(int i = 0; i < totalTargets; i++) { locs.add(new ArrayList<Coord>(maxEffect)); } if(totalTargets == 1) return locs; int ctr = 0; if(radius < 1) { locs.get(totalTargets - 2).addAll(targets); return locs; } boolean[][] tested = new boolean[dungeon.length][dungeon[0].length]; for (int x = 1; x < dungeon.length - 1; x += radius) { BY_POINT: for (int y = 1; y < dungeon[x].length - 1; y += radius) { for(Coord ex : requiredExclusions) { if(radiusType.radius(x, y, ex.x, ex.y) <= radius) continue BY_POINT; } ctr = 0; for(Coord tgt : targets) { if(radiusType.radius(x, y, tgt.x, tgt.y) <= radius) ctr++; } if(ctr > 0) locs.get(totalTargets - ctr).add(Coord.get(x, y)); } } Coord it; for(int t = 0; t < totalTargets - 1; t++) { if(locs.get(t).size() > 0) { int numPoints = locs.get(t).size(); for (int i = 0; i < numPoints; i++) { it = locs.get(t).get(i); for (int x = Math.max(1, it.x - radius / 2); x < it.x + (radius + 1) / 2 && x < dungeon.length - 1; x++) { BY_POINT: for (int y = Math.max(1, it.y - radius / 2); y <= it.y + (radius - 1) / 2 && y < dungeon[0].length - 1; y++) { if(tested[x][y]) continue; tested[x][y] = true; for(Coord ex : requiredExclusions) { if(radiusType.radius(x, y, ex.x, ex.y) <= radius) continue BY_POINT; } ctr = 0; for(Coord tgt : targets) { if(radiusType.radius(x, y, tgt.x, tgt.y) <= radius) ctr++; } if(ctr > 0) locs.get(totalTargets - ctr).add(Coord.get(x, y)); } } } } } return locs; } */ @Override public void setMap(char[][] map) { if (map != null && map.length > 0) { mapWidth = map.length; mapHeight = map[0].length; } } @Override public OrderedMap<Coord, Double> findArea() { OrderedMap<Coord, Double> ret = new OrderedMap<>(1); ret.put(Coord.get(center.x, center.y), 1.0); return ret; } @Override public Coord getOrigin() { return origin; } @Override public void setOrigin(Coord origin) { this.origin = origin; } @Override public AimLimit getLimitType() { return reach.limit; } @Override public int getMinRange() { return reach.minDistance; } @Override public int getMaxRange() { return reach.maxDistance; } @Override public Radius getMetric() { return reach.metric; } /** * Gets the same values returned by getLimitType(), getMinRange(), getMaxRange(), and getMetric() bundled into one * Reach object. * * @return a non-null Reach object. */ @Override public Reach getReach() { return reach; } @Override public void setLimitType(AimLimit limitType) { reach.limit = limitType; } @Override public void setMinRange(int minRange) { reach.minDistance = minRange; } @Override public void setMaxRange(int maxRange) { reach.maxDistance = maxRange; } @Override public void setMetric(Radius metric) { reach.metric = metric; } /** * Sets the same values as setLimitType(), setMinRange(), setMaxRange(), and setMetric() using one Reach object. * * @param reach a non-null Reach object. */ @Override public void setReach(Reach reach) { } /** * If you use FOVCache to pre-compute FOV maps for a level, you can share the speedup from using the cache with * some AOE implementations that rely on FOV. Not all implementations need to actually make use of the cache, but * those that use FOV for calculations should benefit. The cache parameter this receives should have completed its * calculations, which can be confirmed by calling awaitCache(). Ideally, the FOVCache will have done its initial * calculations in another thread while the previous level or menu was being displayed, and awaitCache() will only * be a formality. * * @param cache The FOVCache for the current level; can be null to stop using the cache */ @GwtIncompatible @Override public void setCache(FOVCache cache) { } }