All Downloads are FREE. Search and download functionalities are using the official Maven repository.

squidpony.squidai.BeamAOE Maven / Gradle / Ivy

Go to download

SquidLib platform-independent logic and utility code. Please refer to https://github.com/SquidPony/SquidLib .

There is a newer version: 3.0.6
Show newest version
package squidpony.squidai;

import squidpony.squidgrid.FOV;
import squidpony.squidgrid.LOS;
import squidpony.squidgrid.Measurement;
import squidpony.squidgrid.Radius;
import squidpony.squidgrid.mapping.DungeonUtility;
import squidpony.squidmath.Coord;
import squidpony.squidmath.OrderedMap;
import squidpony.squidmath.OrderedSet;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Queue;

import static java.lang.Math.round;
import static squidpony.squidmath.NumberTools.cos;
import static squidpony.squidmath.NumberTools.sin;

/**
 * Beam Area of Effect that affects an slightly expanded (Elias) line from a given origin Coord out to a given length,
 * plus an optional radius of cells around the path of the line, while respecting obstacles in its path and possibly
 * stopping if obstructed. There are several ways to specify the BeamAOE's direction and length, including specifying
 * an endpoint or specifying an angle in degrees and a distance to the end of the line (without the radius included).
 * You can specify the RadiusType to Radius.DIAMOND for Manhattan distance, RADIUS.SQUARE for Chebyshev, or
 * RADIUS.CIRCLE for Euclidean.
 *
 * You may want the LineAOE class instead of this. LineAOE travels point-to-point and does not restrict length, while
 * BeamAOE travels a specific length (and may have a radius, like LineAOE) but then stops only after the travel down the
 * length and radius has reached its end. This difference is relevant if a game has effects that have a definite
 * area measured in a rectangle or elongated pillbox shape, such as a "20-foot-wide bolt of lightning, 100 feet long."
 * BeamAOE is more suitable for that effect, while LineAOE may be more suitable for things like focused lasers that
 * pass through small (likely fleshy) obstacles but stop after hitting the aimed-at target.
 *
 * BeamAOE will strike a small area behind the user and in the opposite direction of the target if the radius is
 * greater than 0. This behavior may be altered in a future version.
 *
 * This will produce doubles for its findArea() method which are equal to 1.0.
 *
 * This class uses squidpony.squidmath.Elias and squidpony.squidai.DijkstraMap to create its area of effect.
 * Created by Tommy Ettinger on 7/14/2015.
 */
public class BeamAOE implements AOE, Serializable {
    private static final long serialVersionUID = 2L;
    private Coord origin, end;
    private int radius;
    private int length;
    private char[][] dungeon;
    private DijkstraMap dijkstra;
    private Radius rt;
    private LOS los;

    private Reach reach = new Reach(1, 1, Radius.SQUARE, AimLimit.FREE);

    public BeamAOE(Coord origin, Coord end)
    {
        dijkstra = new DijkstraMap();
        dijkstra.measurement = Measurement.EUCLIDEAN;
        rt = Radius.SQUARE;
        this.origin = origin;
        this.end = end;
        length =(int) round(rt.radius(origin.x, origin.y, end.x, end.y));
        reach.maxDistance = length;
        radius = 0;
        los = new LOS(LOS.THICK);
    }
    public BeamAOE(Coord origin, Coord end, int radius)
    {
        dijkstra = new DijkstraMap();
        dijkstra.measurement = Measurement.EUCLIDEAN;
        rt = Radius.SQUARE;
        this.origin = origin;
        this.end = end;
        this.radius = radius;
        length =(int) round(rt.radius(origin.x, origin.y, end.x, end.y));
        reach.maxDistance = length;
        los = new LOS(LOS.THICK);
    }
    public BeamAOE(Coord origin, Coord end, int radius, Radius radiusType)
    {
        dijkstra = new DijkstraMap();
        rt = radiusType;
        switch (radiusType)
        {
            case OCTAHEDRON:
            case DIAMOND:
                dijkstra.measurement = Measurement.MANHATTAN;
                break;
            case CUBE:
            case SQUARE:
                dijkstra.measurement = Measurement.CHEBYSHEV;
                break;
            default:
                dijkstra.measurement = Measurement.EUCLIDEAN;
                break;
        }
        this.origin = origin;
        this.end = end;
        this.radius = radius;
        length =(int) round(rt.radius(origin.x, origin.y, end.x, end.y));
        reach.maxDistance = length;
        los = new LOS(LOS.THICK);
    }

    public BeamAOE(Coord origin, double angle, int length)
    {
        dijkstra = new DijkstraMap();
        dijkstra.measurement = Measurement.EUCLIDEAN;
        rt = Radius.SQUARE;
        this.origin = origin;
        double theta = Math.toRadians(angle);
        end = Coord.get((int) round(cos(theta) * length) + origin.x,
                (int) round(sin(theta) * length) + origin.y);
        this.length = length;
        reach.maxDistance = this.length;
        radius = 0;
        los = new LOS(LOS.THICK);
    }
    public BeamAOE(Coord origin, double angle, int length, int radius)
    {
        dijkstra = new DijkstraMap();
        dijkstra.measurement = Measurement.EUCLIDEAN;
        rt = Radius.SQUARE;
        this.origin = origin;
        double theta = Math.toRadians(angle);
        end = Coord.get((int) round(cos(theta) * length) + origin.x,
                (int) round(sin(theta) * length) + origin.y);
        this.radius = radius;
        this.length = length;
        reach.maxDistance = this.length;
        los = new LOS(LOS.THICK);
    }
    public BeamAOE(Coord origin, double angle, int length, int radius, Radius radiusType)
    {
        dijkstra = new DijkstraMap();
        rt = radiusType;
        switch (radiusType)
        {
            case OCTAHEDRON:
            case DIAMOND:
                dijkstra.measurement = Measurement.MANHATTAN;
                break;
            case CUBE:
            case SQUARE:
                dijkstra.measurement = Measurement.CHEBYSHEV;
                break;
            default:
                dijkstra.measurement = Measurement.EUCLIDEAN;
                break;
        }
        this.origin = origin;
        double theta = Math.toRadians(angle);
        end = Coord.get((int) round(cos(theta) * length) + origin.x,
                (int) round(sin(theta) * length) + origin.y);
        this.radius = radius;
        this.length = length;
        reach.maxDistance = this.length;
        los = new LOS(LOS.THICK);
    }
    private double[][] initDijkstra()
    {
        los.isReachable(dungeon, origin.x, origin.y, end.x, end.y, rt);
        Queue lit = los.getLastPath();

        dijkstra.initialize(dungeon);
        for(Coord p : lit)
        {
            dijkstra.setGoal(p);
        }
        if(radius == 0)
            return dijkstra.gradientMap;
        return dijkstra.partialScan(radius, null);
    }

    @Override
    public Coord getOrigin() {
        return origin;
    }

    @Override
    public void setOrigin(Coord origin) {
        this.origin = origin;
        dijkstra.resetMap();
        dijkstra.clearGoals();
    }

    @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;
        length = 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(reach != null)
            this.reach = reach;
    }

    public Coord getEnd() {
        return end;
    }

    public void setEnd(Coord end) {
        if (AreaUtils.verifyReach(reach, origin, end))
        {
            this.end = rt.extend(origin, end, length, false, dungeon.length, dungeon[0].length);
        }

    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public Radius getRadiusType()
    {
        return rt;
    }
    public void setRadiusType(Radius radiusType)
    {
        rt = radiusType;
        switch (radiusType)
        {
            case OCTAHEDRON:
            case DIAMOND:
                dijkstra.measurement = Measurement.MANHATTAN;
                break;
            case CUBE:
            case SQUARE:
                dijkstra.measurement = Measurement.CHEBYSHEV;
                break;
            default:
                dijkstra.measurement = Measurement.EUCLIDEAN;
                break;
        }
    }

    @Override
    public void shift(Coord aim) {
        setEnd(aim);
    }

    @Override
    public boolean mayContainTarget(Collection targets) {
        for (Coord p : targets)
        {
            if(rt.radius(origin.x, origin.y, p.x, p.y) + rt.radius(end.x, end.y, p.x, p.y) -
                    rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + radius)
                return true;
        }
        return false;
    }

    @Override
    public OrderedMap> idealLocations(Collection targets, Collection requiredExclusions) {
        if(targets == null)
            return new OrderedMap<>();
        if(requiredExclusions == null) requiredExclusions = new OrderedSet<>();

        //requiredExclusions.remove(origin);

        int totalTargets = targets.size();
        OrderedMap> bestPoints = new OrderedMap<>(totalTargets * 8);

        if(totalTargets == 0)
            return bestPoints;

        Coord[] ts = targets.toArray(new Coord[targets.size()]);
        Coord[] exs = requiredExclusions.toArray(new Coord[requiredExclusions.size()]);
        Coord t;

        double[][][] compositeMap = new double[ts.length][dungeon.length][dungeon[0].length];

        char[][] dungeonCopy = new char[dungeon.length][dungeon[0].length];
        for (int i = 0; i < dungeon.length; i++) {
            System.arraycopy(dungeon[i], 0, dungeonCopy[i], 0, dungeon[i].length);
        }
        DijkstraMap dt = new DijkstraMap(dungeon, dijkstra.measurement);
        double[][] resMap = DungeonUtility.generateResistances(dungeon);
        Coord tempPt = Coord.get(0, 0);
        for (int i = 0; i < exs.length; ++i) {
            t = rt.extend(origin, exs[i], length, false, dungeon.length, dungeon[0].length);
            dt.resetMap();
            dt.clearGoals();
            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
            Queue lit = los.getLastPath();


            for(Coord p : lit)
            {
                dt.setGoal(p);
            }
            if(radius > 0)
                dt.partialScan(radius, null);

            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    tempPt = Coord.get(x, y);
                    dungeonCopy[x][y] = (dt.gradientMap[x][y] < DijkstraMap.FLOOR || !AreaUtils.verifyReach(reach, origin, tempPt)) ? '!' : dungeonCopy[x][y];
                }
            }
        }

        //t = rt.extend(origin, ts[0], length, false, dungeon.length, dungeon[0].length);

        for (int i = 0; i < ts.length; ++i) {
            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);

            t = rt.extend(origin, ts[i], length, false, dungeon.length, dungeon[0].length);
            dt.resetMap();
            dt.clearGoals();
            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
            Queue lit = los.getLastPath();

            for(Coord p : lit)
            {
                dt.setGoal(p);
            }
            if(radius > 0)
                dt.partialScan(radius, null);


            double dist = 0.0;
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
                        dist = reach.metric.radius(origin.x, origin.y, x, y);
                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius)
                            compositeMap[i][x][y] = dm.physicalMap[x][y];
                        else
                            compositeMap[i][x][y] = DijkstraMap.WALL;
                    }
                    else compositeMap[i][x][y] = DijkstraMap.WALL;
                }
            }
            if(compositeMap[i][ts[i].x][ts[i].y] > DijkstraMap.FLOOR)
            {
                for (int x = 0; x < dungeon.length; x++) {
                    Arrays.fill(compositeMap[i][x], 99999.0);
                }
                continue;
            }


            dm.initialize(compositeMap[i]);
            dm.setGoal(ts[i]);
            dm.scan(null, null);
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!') ? dm.gradientMap[x][y] : 99999.0;
                }
            }
        }
        double bestQuality = 99999 * ts.length;
        double[][] qualityMap = new double[dungeon.length][dungeon[0].length];
        for (int x = 0; x < qualityMap.length; x++) {
            for (int y = 0; y < qualityMap[x].length; y++) {
                qualityMap[x][y] = 0.0;
                long bits = 0;
                for (int i = 0; i < ts.length; ++i) {
                    qualityMap[x][y] += compositeMap[i][x][y];
                    if(compositeMap[i][x][y] < 99999.0 && i < 63)
                        bits |= 1 << i;
                }
                if(qualityMap[x][y] < bestQuality)
                {
                    ArrayList ap = new ArrayList<>();

                    for (int i = 0; i < ts.length && i < 63; ++i) {
                        if((bits & (1 << i)) != 0)
                            ap.add(ts[i]);
                    }

                    if(ap.size() > 0) {
                        bestQuality = qualityMap[x][y];
                        bestPoints.clear();
                        bestPoints.put(Coord.get(x, y), ap);
                    }
                }
                else if(qualityMap[x][y] == bestQuality)
                {
                    ArrayList ap = new ArrayList<>();

                    for (int i = 0; i < ts.length && i < 63; ++i) {
                        if((bits & (1 << i)) != 0)
                            ap.add(ts[i]);
                    }

                    if (ap.size() > 0) {
                        bestPoints.put(Coord.get(x, y), ap);
                    }
                }
            }
        }

        return bestPoints;
    }

    @Override
    public OrderedMap> idealLocations(Collection priorityTargets, Collection lesserTargets, Collection requiredExclusions) {
        if(priorityTargets == null)
            return idealLocations(lesserTargets, requiredExclusions);
        if(requiredExclusions == null) requiredExclusions = new OrderedSet<>();

        //requiredExclusions.remove(origin);
        int totalTargets = priorityTargets.size() + lesserTargets.size();
        OrderedMap> bestPoints = new OrderedMap<>(totalTargets * 8);

        if(totalTargets == 0)
            return bestPoints;

        Coord[] pts = priorityTargets.toArray(new Coord[priorityTargets.size()]);
        Coord[] lts = lesserTargets.toArray(new Coord[lesserTargets.size()]);
        Coord[] exs = requiredExclusions.toArray(new Coord[requiredExclusions.size()]);
        Coord t;// = rt.extend(origin, exs[0], length, false, dungeon.length, dungeon[0].length);

        double[][][] compositeMap = new double[totalTargets][dungeon.length][dungeon[0].length];

        char[][] dungeonCopy = new char[dungeon.length][dungeon[0].length],
                dungeonPriorities = new char[dungeon.length][dungeon[0].length];
        for (int i = 0; i < dungeon.length; i++) {
            System.arraycopy(dungeon[i], 0, dungeonCopy[i], 0, dungeon[i].length);
            Arrays.fill(dungeonPriorities[i], '#');
        }
        DijkstraMap dt = new DijkstraMap(dungeon, dijkstra.measurement);
        double[][] resMap = DungeonUtility.generateResistances(dungeon);
        Coord tempPt = Coord.get(0, 0);
        for (int i = 0; i < exs.length; ++i) {
            t = rt.extend(origin, exs[i], length, false, dungeon.length, dungeon[0].length);
            dt.resetMap();
            dt.clearGoals();
            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
            Queue lit = los.getLastPath();

            for(Coord p : lit)
            {
                dt.setGoal(p);
            }
            if(radius > 0)
                dt.partialScan(radius, null);

            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    tempPt = Coord.get(x, y);
                    dungeonCopy[x][y] = (dt.gradientMap[x][y] < DijkstraMap.FLOOR  || !AreaUtils.verifyReach(reach, origin, tempPt)) ? '!' : dungeonCopy[x][y];
                }
            }
        }

        t = rt.extend(origin, pts[0], length, false, dungeon.length, dungeon[0].length);

        for (int i = 0; i < pts.length; ++i) {
            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);

            t = rt.extend(origin, pts[i], length, false, dungeon.length, dungeon[0].length);
            dt.resetMap();
            dt.clearGoals();
            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
            Queue lit = los.getLastPath();

            for(Coord p : lit)
            {
                dt.setGoal(p);
            }
            if(radius > 0)
                dt.partialScan(radius, null);


            double dist = 0.0;
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
                        dist = reach.metric.radius(origin.x, origin.y, x, y);
                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius) {
                            compositeMap[i][x][y] = dm.physicalMap[x][y];
                            dungeonPriorities[x][y] = dungeon[x][y];
                        }
                        else
                            compositeMap[i][x][y] = DijkstraMap.WALL;
                    }
                    else compositeMap[i][x][y] = DijkstraMap.WALL;
                }
            }
            if(compositeMap[i][pts[i].x][pts[i].y] > DijkstraMap.FLOOR)
            {
                for (int x = 0; x < dungeon.length; x++) {
                    Arrays.fill(compositeMap[i][x], 399999.0);
                }
                continue;
            }


            dm.initialize(compositeMap[i]);
            dm.setGoal(pts[i]);
            dm.scan(null, null);
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!') ? dm.gradientMap[x][y] : 399999.0;
                }
            }
            dm.resetMap();
            dm.clearGoals();
        }

        t = rt.extend(origin, lts[0], length, false, dungeon.length, dungeon[0].length);

        for (int i = pts.length; i < totalTargets; ++i) {
            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);

            t = rt.extend(origin, lts[i - pts.length], length, false, dungeon.length, dungeon[0].length);
            dt.resetMap();
            dt.clearGoals();
            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
            Queue lit = los.getLastPath();

            for(Coord p : lit)
            {
                dt.setGoal(p);
            }
            if(radius > 0)
                dt.partialScan(radius, null);


            double dist = 0.0;
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
                        dist = reach.metric.radius(origin.x, origin.y, x, y);
                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius)
                            compositeMap[i][x][y] = dm.physicalMap[x][y];
                        else
                            compositeMap[i][x][y] = DijkstraMap.WALL;
                    }
                    else compositeMap[i][x][y] = DijkstraMap.WALL;
                }
            }
            if(compositeMap[i][lts[i - pts.length].x][lts[i - pts.length].y] > DijkstraMap.FLOOR)
            {
                for (int x = 0; x < dungeon.length; x++)
                {
                    Arrays.fill(compositeMap[i][x], 99999.0);
                }
                continue;
            }


            dm.initialize(compositeMap[i]);
            dm.setGoal(lts[i - pts.length]);
            dm.scan(null, null);
            for (int x = 0; x < dungeon.length; x++) {
                for (int y = 0; y < dungeon[x].length; y++) {
                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!' && dungeonPriorities[x][y] != '#') ? dm.gradientMap[x][y] : 99999.0;
                }
            }
            dm.resetMap();
            dm.clearGoals();
        }
        double bestQuality = 99999 * lts.length + 399999 * pts.length;
        double[][] qualityMap = new double[dungeon.length][dungeon[0].length];
        for (int x = 0; x < qualityMap.length; x++) {
            for (int y = 0; y < qualityMap[x].length; y++) {
                qualityMap[x][y] = 0.0;
                long pbits = 0, lbits = 0;
                for (int i = 0; i < pts.length; ++i) {
                    qualityMap[x][y] += compositeMap[i][x][y];
                    if(compositeMap[i][x][y] < 399999.0 && i < 63)
                        pbits |= 1 << i;
                }
                for (int i = pts.length; i < totalTargets; ++i) {
                    qualityMap[x][y] += compositeMap[i][x][y];
                    if(compositeMap[i][x][y] < 99999.0 && i < 63)
                        lbits |= 1 << i;
                }
                if(qualityMap[x][y] < bestQuality)
                {
                    ArrayList ap = new ArrayList<>();

                    for (int i = 0; i < pts.length && i < 63; ++i) {
                        if((pbits & (1 << i)) != 0)
                            ap.add(pts[i]);
                    }
                    for (int i = pts.length; i < totalTargets && i < 63; ++i) {
                        if((lbits & (1 << i)) != 0)
                            ap.add(lts[i - pts.length]);
                    }

                    if(ap.size() > 0) {
                        bestQuality = qualityMap[x][y];
                        bestPoints.clear();
                        bestPoints.put(Coord.get(x, y), ap);
                    }
                }
                else if(qualityMap[x][y] == bestQuality)
                {
                    ArrayList ap = new ArrayList<>();

                    for (int i = 0; i < pts.length && i < 63; ++i) {
                        if ((pbits & (1 << i)) != 0) {
                            ap.add(pts[i]);
                            ap.add(pts[i]);
                            ap.add(pts[i]);
                            ap.add(pts[i]);
                        }
                    }
                    for (int i = pts.length; i < totalTargets && i < 63; ++i) {
                        if((lbits & (1 << i)) != 0)
                            ap.add(lts[i - pts.length]);
                    }

                    if (ap.size() > 0) {
                        bestPoints.put(Coord.get(x, y), ap);
                    }
                }
            }
        }

        return bestPoints;
    }

    /*
        @Override
        public ArrayList> idealLocations(Set targets, Set requiredExclusions) {
            int totalTargets = targets.size() + 1;
            int volume = (int)(rt.radius(1, 1, dungeon.length - 2, dungeon[0].length - 2) * radius * 2.1);
            ArrayList> locs = new ArrayList>(totalTargets);
            for(int i = 0; i < totalTargets; i++)
            {
                locs.add(new ArrayList(volume));
            }
            if(totalTargets == 1)
                return locs;

            int ctr = 0;

            boolean[][] tested = new boolean[dungeon.length][dungeon[0].length];
            for (int x = 1; x < dungeon.length - 1; x += radius) {
                for (int y = 1; y < dungeon[x].length - 1; y += radius) {

                    if(mayContainTarget(requiredExclusions, x, y))
                        continue;
                    ctr = 0;
                    for(Coord tgt : targets)
                    {
                        if(rt.radius(origin.x, origin.y, tgt.x, tgt.y) + rt.radius(end.x, end.y, tgt.x, tgt.y) -
                            rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + 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++) {
                            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;

                                if(mayContainTarget(requiredExclusions, x, y))
                                    continue;

                                ctr = 0;
                                for(Coord tgt : targets)
                                {
                                    if(rt.radius(origin.x, origin.y, tgt.x, tgt.y) + rt.radius(end.x, end.y, tgt.x, tgt.y) -
                                            rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + radius)
                                        ctr++;
                                }
                                if(ctr > 0)
                                    locs.get(totalTargets - ctr).add(Coord.get(x, y));
                            }
                        }
                    }
                }
            }
            return locs;
        }
    */
    @Override
    public void setMap(char[][] map) {
        dungeon = map;
        end = rt.extend(origin, end, length, false, map.length, map[0].length);
        dijkstra.resetMap();
        dijkstra.clearGoals();
    }

    @Override
    public OrderedMap findArea() {
        double[][] dmap = initDijkstra();
        dmap[origin.x][origin.y] = DijkstraMap.DARK;
        dijkstra.resetMap();
        dijkstra.clearGoals();
        return AreaUtils.dijkstraToHashMap(dmap);
    }

    /**
     * Unused because FOVCache rarely provides a speed boost and usually does the opposite. The implementation for this
     * method should be a no-op.
     * @param cache an FOV that could be an FOVCache for the current level; can be null to stop using the cache
     * @deprecated AOE doesn't really benefit from using an FOVCache
     */
    @Override
    @Deprecated
    public void setCache(FOV cache) {
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy