From 81cbec5348a444a1d9e394b8c2ae668ac85063a8 Mon Sep 17 00:00:00 2001 From: punchready Date: Mon, 7 Jun 2021 00:27:58 +0200 Subject: [PATCH] fix: mind stone creates an infinite ray --- .../gamelibrary/gamelogic/GameLogic.java | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java index e982da6..f513ba9 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java @@ -176,6 +176,10 @@ public class GameLogic { throw new InvalidRequestException("Invalid soul stone target (same as origin)"); } + if(data.originField.distanceChebyshev(data.targetField) != 1) { + throw new InvalidRequestException("Invalid soul stone target distance"); + } + if(target.isAlive()) { throw new InvalidRequestException("Invalid soul stone target (already alive)"); } @@ -403,8 +407,7 @@ public class GameLogic { } case MindStone -> { EntityType target = data.originEntity.type == EntityType.P1 ? EntityType.P2 : EntityType.P1; - //todo: extend to infinity - for(IntVector2 pos: rasterize(data.originField, data.targetField, false, true)) { + for(IntVector2 pos: rasterizeInfinity(data.originField, data.targetField, state.mapSize, false)) { for(Entity entity: state.entities.findByPosition(pos)) { if(entity.id.isSameType(target)) { result.add(new EventBuilder(EventType.TakenDamageEvent) @@ -1292,6 +1295,62 @@ public class GameLogic { return result; } + /** + * Computes all fields which intersect the ray between the center points of the given two fields extending past the second one. + * @param size The size of the map + * @param includeA Whether to include point a in the result + * @return The list of intersecting positions + */ + public static ArrayList rasterizeInfinity(IntVector2 a, IntVector2 b, IntVector2 size, boolean includeA) { + ArrayList result = new ArrayList<>(); + + if(includeA) { + result.add(a); + } + + int x1 = a.getX(); + int y1 = a.getY(); + int x2 = b.getX(); + int y2 = b.getY(); + + Line2D line = new Line2D.Float(x1 + 0.5f, y1 + 0.5f, x2 + 0.5f, y2 + 0.5f); + double l = line.getP1().distance(line.getP2()); + + for(int i = 0; i < size.getX(); i++) { + for(int j = 0; j < size.getY(); j++) { + HashSet intersections = new HashSet<>(); + for(Line2D.Float part: getWireframe(new Rectangle.Float(i, j, 1, 1))) { + Point2D.Float intersection = calculateInterceptionPoint(line.getP1(), line.getP2(), part.getP1(), part.getP2()); + if(intersection != null) { + double dPa = intersection.distance(part.getP1()); + double dPb = intersection.distance(part.getP2()); + // sum of distances to points of the rectangle part == 1 => point lies on line segment + // -----a---x----b----- + // --x--a--------b----- + if(dPa + dPb == 1) { + double da = intersection.distance(line.getP1()); + double db = intersection.distance(line.getP2()); + // distance to a greater than to b => point lies on the ray from a over b + // sum of distances analog to rectangle part => point lies between a and b + // 0.000000005 because computers suck (missing precision) + if(da > db || da + db <= l + 0.000000005) { + intersections.add(intersection); + if(intersections.size() > 1) { + break; + } + } + } + } + } + if(intersections.size() > 1) { + result.add(new IntVector2(i, j)); + } + } + } + + return result; + } + //https://rosettacode.org/wiki/Find_the_intersection_of_two_lines#Java public static Point2D.Float calculateInterceptionPoint(Point2D s1, Point2D s2, Point2D d1, Point2D d2) { double a1 = s2.getY() - s1.getY(); @@ -1303,6 +1362,9 @@ public class GameLogic { double c2 = a2 * d1.getX() + b2 * d1.getY(); double delta = a1 * b2 - a2 * b1; + if(delta == 0) { + return null; + } return new Point2D.Float((float) ((b2 * c1 - b1 * c2) / delta), (float) ((a1 * c2 - a2 * c1) / delta)); }