diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java index 77706c7ec..99db23615 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java @@ -30,16 +30,48 @@ public class SceneRegion { public boolean contains(Position position) { switch (shape) { - case ScriptRegionShape.CUBIC: - return (Math.abs(pos.getX() - position.getX()) <= size.getX() / 2f) - && (Math.abs(pos.getY() - position.getY()) <= size.getY() / 2f) + case ScriptRegionShape.SPHERE -> { + val x = pos.getX() - position.getX(); + val y = pos.getY() - position.getY(); + val z = pos.getZ() - position.getZ(); + // x^2 + y^2 + z^2 = radius^2 + return x * x + y * y + z * z <= radius * radius; + } + case ScriptRegionShape.CUBIC -> { + return (Math.abs(pos.getX() - position.getX()) <= size.getX() / 2f) + && (Math.abs(pos.getY() - position.getY()) <= size.getY() / 2f) && (Math.abs(pos.getZ() - position.getZ()) <= size.getZ() / 2f); - case ScriptRegionShape.SPHERE: - var x = Math.pow(pos.getX() - position.getX(), 2); - var y = Math.pow(pos.getY() - position.getY(), 2); - var z = Math.pow(pos.getZ() - position.getZ(), 2); - // ^ means XOR in java! - return x + y + z <= (radius * radius); + } + case ScriptRegionShape.POLYGON -> { + // algorithm is "ray casting": https://www.youtube.com/watch?v=RSXM9bgqxJM + if (Math.abs(pos.getY() - position.getY()) > height / 2f) return false; + var count = 0; + for (var i = 0; i < point_array.size(); ++i) { + val j = (i + 1) % point_array.size(); + + val yp = position.getZ(); + val y1 = point_array.get(i).getY(); + val y2 = point_array.get(j).getY(); + + val xp = position.getX(); + val x1 = point_array.get(i).getX(); + val x2 = point_array.get(j).getX(); + + if ((yp < y1) != (yp < y2) + && xp < x1 + ((yp - y1) / (y2 - y1)) * (x2 - x1)) { + ++count; + } + } + + return count % 2 == 1; + } + case ScriptRegionShape.CYLINDER -> { + if (Math.abs(pos.getY() - position.getY()) > height / 2f) return false; + val x = pos.getX() - position.getX(); + val z = pos.getZ() - position.getZ(); + // x^2 + z^2 = radius^2 + return x * x + z * z <= radius * radius; + } } return false; }