Repository: runelite/runelite
Pull request #18240 (2024-09-06 04:48:39)

clues: clean up CoordinateClue
Addresses first two bullets in #18236:
- Replaces constructors with builder
- Replaces `lightRequired` with a check for the firepit varbit presence

tylerwgrass: I've flattened the class.

I tried test loading a few clue scrolls by using associated coordinates listed on the wiki but they don't seem to match what the currently mapped points are, not sure what that is about.

For example I tried loading the clue for coordinates `"03 degrees 09 minutes south, 43 degrees 26 minutes east"`
which should be here
![200px-03 09S_43 26E_map](https://github.com/user-attachments/assets/c56d55a3-c33e-47d6-9885-039875edd240)

but my client shows this location prior to this commit (and doesn't show at all within this commit because it just fetches from the coord map)
![image](https://github.com/user-attachments/assets/badc6534-94a8-4285-885c-d93c7e2cfb58)

not sure if i'm just testing incorrectly
Felanbird: I can replicate triggering that step manually, shows the map location wrong on 1.10.51 too, idk why, when Jagex unlocked the map #17616 was reported within 4 hours so I assume this isn't actually wrong?
Nightfirecat: Possibly incorrect coordinate of that clue aside, as that's unrelated to this PR, this looks pretty good now. I've pushed a commit which changes the `CLUES` construction to more what I envisioned (a list, which is streamed and collected to a map, so the location does not need to be entered twice for every clue)

Patch:
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java
index 02425d8c2..4d920d043 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java
@@ -890,10 +890,7 @@ public class ClueScrollPlugin extends Plugin
 		}
 
 		WorldPoint coordinate = coordinatesToWorldPoint(degX, minX, degY, minY);
-		// Convert from overworld to real
-		WorldPoint mirrorPoint = WorldPoint.getMirrorPoint(coordinate, false);
-		// Use mirror point as mirrorLocation if there is one
-		return new CoordinateClue(text, coordinate, coordinate == mirrorPoint ? null : mirrorPoint);
+		return CoordinateClue.forLocation(coordinate);
 	}
 
 	/**
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
index 1c9bbb9cc..4fc419574 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
@@ -24,16 +24,15 @@
  */
 package net.runelite.client.plugins.cluescrolls.clues;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
 import java.awt.Color;
 import java.awt.Graphics2D;
-import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import lombok.AccessLevel;
+import lombok.Builder;
 import lombok.Getter;
-import lombok.NonNull;
-import lombok.ToString;
 import net.runelite.api.Varbits;
 import net.runelite.api.annotations.Varbit;
 import net.runelite.api.coords.LocalPoint;
@@ -54,210 +53,799 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
 @Getter
 public class CoordinateClue extends ClueScroll implements LocationClueScroll
 {
-	@Getter
-	@ToString
-	@VisibleForTesting
-	static class CoordinateClueInfo
-	{
-		private final String directions;
-		private final boolean lightRequired;
-		@Getter(onMethod_ = {@Varbit})
-		private final int lightSourceVarbitId;
-		private final Enemy enemy;
-
-		private CoordinateClueInfo(@NonNull String directions)
-		{
-			this(directions, null);
-		}
-
-		private CoordinateClueInfo(@NonNull String directions, Enemy enemy)
-		{
-			this.directions = directions;
-			this.enemy = enemy;
-			this.lightRequired = false;
-			this.lightSourceVarbitId = -1;
-		}
-
-		private CoordinateClueInfo(@Nonnull String directions, Enemy enemy, boolean lightRequired, @Varbit int lightSourceVarbitId)
-		{
-			this.directions = directions;
-			this.enemy = enemy;
-			this.lightRequired = lightRequired;
-			this.lightSourceVarbitId = lightSourceVarbitId;
-		}
-	}
-
-	static final ImmutableMap<WorldPoint, CoordinateClueInfo> CLUES = new ImmutableMap.Builder<WorldPoint, CoordinateClueInfo>()
+	static final ImmutableMap<WorldPoint, CoordinateClue> CLUES = List.of(
 		// Medium
-		.put(new WorldPoint(2479, 3158, 0), new CoordinateClueInfo("South of fruit tree patch, west of Tree Gnome Village."))
-		.put(new WorldPoint(2887, 3154, 0), new CoordinateClueInfo("West of Banana plantation on Karamja."))
-		.put(new WorldPoint(2743, 3151, 0), new CoordinateClueInfo("Entrance of Brimhaven dungeon."))
-		.put(new WorldPoint(3184, 3150, 0), new CoordinateClueInfo("South of Lumbridge Swamp."))
-		.put(new WorldPoint(3217, 3177, 0), new CoordinateClueInfo("East of Lumbridge Swamp."))
-		.put(new WorldPoint(3007, 3144, 0), new CoordinateClueInfo("Near the entrance to the Asgarnian Ice Dungeon, south of Port Sarim (AIQ)."))
-		.put(new WorldPoint(2896, 3119, 0), new CoordinateClueInfo("Near Karambwan fishing spot (DKP)."))
-		.put(new WorldPoint(2697, 3207, 0), new CoordinateClueInfo("Centre of Moss Giant Island, west of Brimhaven."))
-		.put(new WorldPoint(2679, 3110, 0), new CoordinateClueInfo("North of Hazelmere's house (CLS)."))
-		.put(new WorldPoint(3510, 3074, 0), new CoordinateClueInfo("East of Uzer (DLQ)."))
-		.put(new WorldPoint(3160, 3251, 0), new CoordinateClueInfo("West of trapdoor leading to H.A.M Hideout."))
-		.put(new WorldPoint(2643, 3252, 0), new CoordinateClueInfo("South of Ardougne Zoo, North of Tower of Life (DJP)."))
-		.put(new WorldPoint(2322, 3061, 0), new CoordinateClueInfo("South-west of Castle wars (BKP)."))
-		.put(new WorldPoint(2875, 3046, 0), new CoordinateClueInfo("North of nature altar, north of Shilo Village (CKR)."))
-		.put(new WorldPoint(2849, 3033, 0), new CoordinateClueInfo("West of nature altar, north of Shilo Village (CKR)."))
-		.put(new WorldPoint(2848, 3296, 0), new CoordinateClueInfo("North of Crandor island."))
-		.put(new WorldPoint(2583, 2990, 0), new CoordinateClueInfo("Feldip Hills, south-east of Gu'Thanoth (AKS)."))
-		.put(new WorldPoint(3179, 3344, 0), new CoordinateClueInfo("In the cow pen north of the Lumbridge windmill."))
-		.put(new WorldPoint(2383, 3370, 0), new CoordinateClueInfo("West of the outpost"))
-		.put(new WorldPoint(3312, 3375, 0), new CoordinateClueInfo("North-west of Exam Centre, on the hill."))
-		.put(new WorldPoint(3121, 3384, 0), new CoordinateClueInfo("North-east of Draynor Manor, near River Lum."))
-		.put(new WorldPoint(3430, 3388, 0), new CoordinateClueInfo("West of Mort Myre Swamp (BKR)."))
-		.put(new WorldPoint(2920, 3403, 0), new CoordinateClueInfo("South-east of Taverley, near Lady of the Lake."))
-		.put(new WorldPoint(2594, 2899, 0), new CoordinateClueInfo("South-east of Feldip Hills, by the crimson swifts (AKS)."))
-		.put(new WorldPoint(2387, 3435, 0), new CoordinateClueInfo("West of Tree Gnome Stronghold, near the pen containing terrorbirds."))
-		.put(new WorldPoint(2512, 3467, 0), new CoordinateClueInfo("Baxtorian Falls (Bring rope)."))
-		.put(new WorldPoint(2381, 3468, 0), new CoordinateClueInfo("West of Tree Gnome Stronghold, north of the pen with terrorbirds."))
-		.put(new WorldPoint(3005, 3475, 0), new CoordinateClueInfo("Ice Mountain, west of Edgeville Monastery."))
-		.put(new WorldPoint(2585, 3505, 0), new CoordinateClueInfo("By the shore line north of the Coal Trucks."))
-		.put(new WorldPoint(3443, 3515, 0), new CoordinateClueInfo("South of Slayer Tower (CKS)."))
-		.put(new WorldPoint(2416, 3516, 0), new CoordinateClueInfo("Tree Gnome Stronghold, west of Grand Tree, near swamp."))
-		.put(new WorldPoint(3429, 3523, 0), new CoordinateClueInfo("South of Slayer Tower (CKS)."))
-		.put(new WorldPoint(2363, 3531, 0), new CoordinateClueInfo("North-east of Eagles' Peak (AKQ)."))
-		.put(new WorldPoint(2919, 3535, 0), new CoordinateClueInfo("East of Burthorpe pub."))
-		.put(new WorldPoint(3548, 3560, 0), new CoordinateClueInfo("Inside Fenkenstrain's Castle."))
-		.put(new WorldPoint(1476, 3566, 0), new CoordinateClueInfo("Graveyard of Heroes in west Shayzien."))
-		.put(new WorldPoint(2735, 3638, 0), new CoordinateClueInfo("East of Rellekka, north-west of Golden Apple Tree (AJR)."))
-		.put(new WorldPoint(2681, 3653, 0), new CoordinateClueInfo("Rellekka, in the garden of the south-east house."))
-		.put(new WorldPoint(2537, 3881, 0), new CoordinateClueInfo("Miscellania (CIP)."))
-		.put(new WorldPoint(2828, 3234, 0), new CoordinateClueInfo("Southern coast of Crandor."))
-		.put(new WorldPoint(1247, 3726, 0), new CoordinateClueInfo("Just inside the Farming Guild"))
-		.put(new WorldPoint(3770, 3898, 0), new CoordinateClueInfo("On the small island north-east of Fossil Island's mushroom forest."))
-		.put(new WorldPoint(1659, 3111, 0), new CoordinateClueInfo("Dig west of the Bazaar in Civitas illa Fortis."))
+		CoordinateClue.builder()
+			.location(new WorldPoint(2479, 3158, 0))
+			.directions("South of fruit tree patch, west of Tree Gnome Village.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2887, 3154, 0))
+			.directions("West of Banana plantation on Karamja.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2743, 3151, 0))
+			.directions("Entrance of Brimhaven dungeon.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3184, 3150, 0))
+			.directions("South of Lumbridge Swamp.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3217, 3177, 0))
+			.directions("East of Lumbridge Swamp.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3007, 3144, 0))
+			.directions("Near the entrance to the Asgarnian Ice Dungeon, south of Port Sarim (AIQ).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2896, 3119, 0))
+			.directions("Near Karambwan fishing spot (DKP).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2697, 3207, 0))
+			.directions("Centre of Moss Giant Island, west of Brimhaven.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2679, 3110, 0))
+			.directions("North of Hazelmere's house (CLS).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3510, 3074, 0))
+			.directions("East of Uzer (DLQ).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3160, 3251, 0))
+			.directions("West of trapdoor leading to H.A.M Hideout.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2643, 3252, 0))
+			.directions("South of Ardougne Zoo, North of Tower of Life (DJP).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2322, 3061, 0))
+			.directions("South-west of Castle wars (BKP).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2875, 3046, 0))
+			.directions("North of nature altar, north of Shilo Village (CKR).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2849, 3033, 0))
+			.directions("West of nature altar, north of Shilo Village (CKR).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2848, 3296, 0))
+			.directions("North of Crandor island.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2583, 2990, 0))
+			.directions("Feldip Hills, south-east of Gu'Tanoth (AKS).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3179, 3344, 0))
+			.directions("In the cow pen north of the Lumbridge windmill.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2383, 3370, 0))
+			.directions("West of the outpost")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3312, 3375, 0))
+			.directions("North-west of Exam Centre, on the hill.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3121, 3384, 0))
+			.directions("North-east of Draynor Manor, near River Lum.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3430, 3388, 0))
+			.directions("West of Mort Myre Swamp (BKR).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2920, 3403, 0))
+			.directions("South-east of Taverley, near Lady of the Lake.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2594, 2899, 0))
+			.directions("South-east of Feldip Hills, by the crimson swifts (AKS).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2387, 3435, 0))
+			.directions("West of Tree Gnome Stronghold, near the pen containing terrorbirds.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2512, 3467, 0))
+			.directions("Baxtorian Falls (Bring rope).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2381, 3468, 0))
+			.directions("West of Tree Gnome Stronghold, north of the pen with terrorbirds.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3005, 3475, 0))
+			.directions("Ice Mountain, west of Edgeville Monastery.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2585, 3505, 0))
+			.directions("By the shore line north of the Coal Trucks.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3443, 3515, 0))
+			.directions("South of Slayer Tower (CKS).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2416, 3516, 0))
+			.directions("Tree Gnome Stronghold, west of Grand Tree, near swamp.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3429, 3523, 0))
+			.directions("South of Slayer Tower (CKS).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2363, 3531, 0))
+			.directions("North-east of Eagles' Peak (AKQ).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2919, 3535, 0))
+			.directions("East of Burthorpe pub.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3548, 3560, 0))
+			.directions("Inside Fenkenstrain's Castle.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1476, 3566, 0))
+			.directions("Graveyard of Heroes in west Shayzien.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2735, 3638, 0))
+			.directions("East of Rellekka, north-west of Golden Apple Tree (AJR).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2681, 3653, 0))
+			.directions("Rellekka, in the garden of the south-east house.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2537, 3881, 0))
+			.directions("Miscellania (CIP).")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2828, 3234, 0))
+			.directions("Southern coast of Crandor.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1247, 3726, 0))
+			.directions("Just inside the Farming Guild")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3770, 3898, 0))
+			.directions("On the small island north-east of Fossil Island's mushroom forest.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1659, 3111, 0))
+			.directions("Dig west of the Bazaar in Civitas illa Fortis.")
+			.build(),
 		// Hard
-		.put(new WorldPoint(2209, 3161, 0), new CoordinateClueInfo("North-east of Tyras Camp (BJS if 76 Agility).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2181, 3206, 0), new CoordinateClueInfo("South of Iorwerth Camp.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3081, 3209, 0), new CoordinateClueInfo("Small Island (CLP).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3399, 3246, 0), new CoordinateClueInfo("Behind the PvP Arena."))
-		.put(new WorldPoint(2699, 3251, 0), new CoordinateClueInfo("Little island (AIR).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3546, 3251, 0), new CoordinateClueInfo("North-east of Burgh de Rott.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3544, 3256, 0), new CoordinateClueInfo("North-east of Burgh de Rott.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2841, 3267, 0), new CoordinateClueInfo("Crandor island.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3168, 3041, 0), new CoordinateClueInfo("Bedabin Camp.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2542, 3031, 0), new CoordinateClueInfo("Gu'Tanoth, may require 20gp.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2581, 3030, 0), new CoordinateClueInfo("Gu'Tanoth island, enter cave north-west of Feldip Hills (AKS).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2961, 3024, 0), new CoordinateClueInfo("Ship yard (DKP).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2339, 3311, 0), new CoordinateClueInfo("East of Prifddinas on Arandar mountain pass.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3440, 3341, 0), new CoordinateClueInfo("Nature Spirit's grotto (BIP).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2763, 2974, 0), new CoordinateClueInfo("Cairn Isle, west of Shilo Village (CKR).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3138, 2969, 0), new CoordinateClueInfo("West of Bandit Camp in Kharidian Desert.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2924, 2963, 0), new CoordinateClueInfo("On the southern part of eastern Karamja, west of the gnome glider.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2838, 2914, 0), new CoordinateClueInfo("Kharazi Jungle, near water pool (CKR).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3441, 3419, 0), new CoordinateClueInfo("Mort Myre Swamp (BKR).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2950, 2902, 0), new CoordinateClueInfo("South-east of Kharazi Jungle.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2775, 2891, 0), new CoordinateClueInfo("South-west of Kharazi Jungle.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3113, 3602, 0), new CoordinateClueInfo("Wilderness. South-west of Ferox Enclave (level 11).", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2892, 3675, 0), new CoordinateClueInfo("On the summit of Trollheim.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3168, 3677, 0), new CoordinateClueInfo("Wilderness. Graveyard of Shadows.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2853, 3690, 0), new CoordinateClueInfo("Entrance to the troll Stronghold.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3305, 3692, 0), new CoordinateClueInfo("Wilderness. West of eastern green dragons.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3055, 3696, 0), new CoordinateClueInfo("Wilderness. Bandit Camp.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3302, 3696, 0), new CoordinateClueInfo("Wilderness. West of eastern green dragons.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(1479, 3699, 0), new CoordinateClueInfo("Lizardman Canyon (DJR).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2712, 3732, 0), new CoordinateClueInfo("North-east of Rellekka (DKS).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2970, 3749, 0), new CoordinateClueInfo("Wilderness. Forgotten Cemetery.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3094, 3764, 0), new CoordinateClueInfo("Wilderness. Mining site north of Bandit Camp.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3311, 3769, 0), new CoordinateClueInfo("Wilderness. South of the Silk Chasm (Venenatis).", ZAMORAK_WIZARD))
-		.put(new WorldPoint(1460, 3782, 0), new CoordinateClueInfo("Lovakengj, near burning man.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3244, 3792, 0), new CoordinateClueInfo("Wilderness. South-east of Lava Dragon Isle by some Chaos Dwarves.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3140, 3804, 0), new CoordinateClueInfo("Wilderness. North of black chinchompa hunter area.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2946, 3819, 0), new CoordinateClueInfo("Wilderness. Chaos Temple (level 38).", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3771, 3825, 0), new CoordinateClueInfo("Fossil Island. East of Museum Camp.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3013, 3846, 0), new CoordinateClueInfo("Wilderness. West of Lava Maze, before KBD's lair.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3058, 3884, 0), new CoordinateClueInfo("Wilderness. Near runite ore north of Lava Maze.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3290, 3889, 0), new CoordinateClueInfo("Wilderness. Demonic Ruins.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3770, 3897, 0), new CoordinateClueInfo("Small Island north of Fossil Island.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(2505, 3899, 0), new CoordinateClueInfo("Small Island north-west of Miscellania (AJS).", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3285, 3942, 0), new CoordinateClueInfo("Wilderness. Rogues' Castle.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3159, 3959, 0), new CoordinateClueInfo("Wilderness. North of Deserted Keep, west of Resource Area.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3039, 3960, 0), new CoordinateClueInfo("Wilderness. Pirates' Hideout.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2987, 3963, 0), new CoordinateClueInfo("Wilderness. West of Wilderness Agility Course.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(3189, 3963, 0), new CoordinateClueInfo("Wilderness. North of Resource Area, near magic axe hut.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2341, 3697, 0), new CoordinateClueInfo("North-east of the Piscatoris Fishing Colony bank.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(3143, 3774, 0), new CoordinateClueInfo("In level 32 Wilderness, by the black chinchompa hunting area.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(2970, 3913, 0), new CoordinateClueInfo("Frozen Waste Plateau, south-west of Wilderness Agility Course.", ZAMORAK_WIZARD))
-		.put(new WorldPoint(1410, 3611, 0), new CoordinateClueInfo("Lake Molch dock west of Shayzien Encampment.", SARADOMIN_WIZARD))
-		.put(new WorldPoint(1409, 3483, 0), new CoordinateClueInfo("South of Shayziens' Wall.", SARADOMIN_WIZARD))
+		CoordinateClue.builder()
+			.location(new WorldPoint(2209, 3161, 0))
+			.directions("North-east of Tyras Camp (BJS if 76 Agility).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2181, 3206, 0))
+			.directions("South of Iorwerth Camp.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3081, 3209, 0))
+			.directions("Small Island (CLP).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3399, 3246, 0))
+			.directions("Behind the PvP Arena.")
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2699, 3251, 0))
+			.directions("Little island (AIR).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3546, 3251, 0))
+			.directions("North-east of Burgh de Rott.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3544, 3256, 0))
+			.directions("North-east of Burgh de Rott.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2841, 3267, 0))
+			.directions("Crandor island.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3168, 3041, 0))
+			.directions("Bedabin Camp.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2542, 3031, 0))
+			.directions("Gu'Tanoth, may require 20gp.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2581, 3030, 0))
+			.directions("Gu'Tanoth island, enter cave north-west of Feldip Hills (AKS).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2961, 3024, 0))
+			.directions("Ship yard (DKP).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2339, 3311, 0))
+			.directions("East of Prifddinas on Arandar mountain pass.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3440, 3341, 0))
+			.directions("Nature Spirit's grotto (BIP).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2763, 2974, 0))
+			.directions("Cairn Isle, west of Shilo Village (CKR).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3138, 2969, 0))
+			.directions("West of Bandit Camp in Kharidian Desert.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2924, 2963, 0))
+			.directions("On the southern part of eastern Karamja, west of the gnome glider.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2838, 2914, 0))
+			.directions("Kharazi Jungle, near water pool (CKR).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3441, 3419, 0))
+			.directions("Mort Myre Swamp (BKR).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2950, 2902, 0))
+			.directions("South-east of Kharazi Jungle.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2775, 2891, 0))
+			.directions("South-west of Kharazi Jungle.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3113, 3602, 0))
+			.directions("Wilderness. South-west of Ferox Enclave (level 11).")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2892, 3675, 0))
+			.directions("On the summit of Trollheim.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3168, 3677, 0))
+			.directions("Wilderness. Graveyard of Shadows.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2853, 3690, 0))
+			.directions("Entrance to the troll Stronghold.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3305, 3692, 0))
+			.directions("Wilderness. West of eastern green dragons.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3055, 3696, 0))
+			.directions("Wilderness. Bandit Camp.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3302, 3696, 0))
+			.directions("Wilderness. West of eastern green dragons.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1479, 3699, 0))
+			.directions("Lizardman Canyon (DJR).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2712, 3732, 0))
+			.directions("North-east of Rellekka (DKS).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2970, 3749, 0))
+			.directions("Wilderness. Forgotten Cemetery.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3094, 3764, 0))
+			.directions("Wilderness. Mining site north of Bandit Camp.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3311, 3769, 0))
+			.directions("Wilderness. South of the Silk Chasm (Venenatis).")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1460, 3782, 0))
+			.directions("Lovakengj, near burning man.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3244, 3792, 0))
+			.directions("Wilderness. South-east of Lava Dragon Isle by some Chaos Dwarves.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3140, 3804, 0))
+			.directions("Wilderness. North of black chinchompa hunter area.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2946, 3819, 0))
+			.directions("Wilderness. Chaos Temple (level 38).")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3771, 3825, 0))
+			.directions("Fossil Island. East of Museum Camp.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3013, 3846, 0))
+			.directions("Wilderness. West of Lava Maze, before KBD's lair.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3058, 3884, 0))
+			.directions("Wilderness. Near runite ore north of Lava Maze.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3290, 3889, 0))
+			.directions("Wilderness. Demonic Ruins.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3770, 3897, 0))
+			.directions("Small Island north of Fossil Island.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2505, 3899, 0))
+			.directions("Small Island north-west of Miscellania (AJS).")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3285, 3942, 0))
+			.directions("Wilderness. Rogues' Castle.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3159, 3959, 0))
+			.directions("Wilderness. North of Deserted Keep, west of Resource Area.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3039, 3960, 0))
+			.directions("Wilderness. Pirates' Hideout.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2987, 3963, 0))
+			.directions("Wilderness. West of Wilderness Agility Course.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3189, 3963, 0))
+			.directions("Wilderness. North of Resource Area, near magic axe hut.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2341, 3697, 0))
+			.directions("North-east of the Piscatoris Fishing Colony bank.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3143, 3774, 0))
+			.directions("In level 32 Wilderness, by the black chinchompa hunting area.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2970, 3913, 0))
+			.directions("Frozen Waste Plateau, south-west of Wilderness Agility Course.")
+			.enemy(ZAMORAK_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1410, 3611, 0))
+			.directions("Lake Molch dock west of Shayzien Encampment.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1409, 3483, 0))
+			.directions("South of Shayziens' Wall.")
+			.enemy(SARADOMIN_WIZARD)
+			.build(),
 		// Elite
-		.put(new WorldPoint(2357, 3151, 0), new CoordinateClueInfo("Lletya.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3587, 3180, 0), new CoordinateClueInfo("Meiyerditch.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2820, 3078, 0), new CoordinateClueInfo("Tai Bwo Wannai. Hardwood Grove. 100 Trading sticks or elite Karamja diary completion is needed to enter.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3811, 3060, 0), new CoordinateClueInfo("Small island north-east of Mos Le'Harmless.", ARMADYLEAN_OR_BANDOSIAN_GUARD, true, Varbits.FIRE_PIT_MOS_LE_HARMLESS))
-		.put(new WorldPoint(2180, 3282, 0), new CoordinateClueInfo("North of Iorwerth Camp.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2870, 2997, 0), new CoordinateClueInfo("North-east corner in Shilo Village.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3302, 2988, 0), new CoordinateClueInfo("On top of a cliff to the west of Pollnivneach.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2511, 2980, 0), new CoordinateClueInfo("Just south of Gu'Tanoth, west of gnome glider (AKS).", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2732, 3372, 0), new CoordinateClueInfo("Legends' Guild.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3573, 3425, 0), new CoordinateClueInfo("North of Dessous's tomb from Desert Treasure.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3828, 2848, 0), new CoordinateClueInfo("East of Harmony Island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3225, 2838, 0), new CoordinateClueInfo("South of Desert Treasure pyramid.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(1773, 3510, 0), new CoordinateClueInfo("Ruins north of the Hosidius mine.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3822, 3562, 0), new CoordinateClueInfo("North-east of Dragontooth Island. Bring a Ghostspeak Amulet and 25 Ecto-tokens to reach the island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3603, 3564, 0), new CoordinateClueInfo("North of the wrecked ship, outside of Port Phasmatys.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2936, 2721, 0), new CoordinateClueInfo("Eastern shore of Crash Island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2697, 2705, 0), new CoordinateClueInfo("South-west of Ape Atoll.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2778, 3678, 0), new CoordinateClueInfo("Mountain Camp.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2827, 3740, 0), new CoordinateClueInfo("West of the entrance to the Ice Path, where the Troll child resides.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2359, 3799, 0), new CoordinateClueInfo("Neitiznot.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2194, 3807, 0), new CoordinateClueInfo("Pirates' Cove.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2700, 3808, 0), new CoordinateClueInfo("Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3215, 3835, 0), new CoordinateClueInfo("Wilderness. Lava Dragon Isle.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3369, 3894, 0), new CoordinateClueInfo("Wilderness. Fountain of Rune.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2065, 3923, 0), new CoordinateClueInfo("Outside the western wall on Lunar Isle.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3188, 3933, 0), new CoordinateClueInfo("Wilderness. Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3043, 3940, 0), new CoordinateClueInfo("Wilderness. South of Pirates' Hideout.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3380, 3963, 0), new CoordinateClueInfo("Wilderness. North of Volcano.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3051, 3736, 0), new CoordinateClueInfo("East of the Wilderness Obelisk in 28 Wilderness.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2316, 3814, 0), new CoordinateClueInfo("West of Neitiznot, near the bridge.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2872, 3937, 0), new CoordinateClueInfo("Weiss.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls (BJP).", BANDOSIAN_GUARD))
-		.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_GUARD))
-		.put(new WorldPoint(1451, 3509, 0), new CoordinateClueInfo("Ruins of Morra.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(3318, 2706, 0), new CoordinateClueInfo("Necropolis mine", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(1557, 3183, 0), new CoordinateClueInfo("North of Ortus Farm", ARMADYLEAN_OR_BANDOSIAN_GUARD))
-		.put(new WorldPoint(1571, 3245, 0), new CoordinateClueInfo("At the top of The Proudspire", ARMADYLEAN_OR_BANDOSIAN_GUARD))
+		CoordinateClue.builder()
+			.location(new WorldPoint(2357, 3151, 0))
+			.directions("Lletya.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3587, 3180, 0))
+			.directions("Meiyerditch.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2820, 3078, 0))
+			.directions("Tai Bwo Wannai. Hardwood Grove. 100 Trading sticks or elite Karamja diary completion is needed to enter.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3811, 3060, 0))
+			.directions("Small island north-east of Mos Le'Harmless.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.lightSourceVarbitId(Varbits.FIRE_PIT_MOS_LE_HARMLESS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2180, 3282, 0))
+			.directions("North of Iorwerth Camp.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2870, 2997, 0))
+			.directions("North-east corner in Shilo Village.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3302, 2988, 0))
+			.directions("On top of a cliff to the west of Pollnivneach.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2511, 2980, 0))
+			.directions("Just south of Gu'Tanoth, west of gnome glider (AKS).")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2732, 3372, 0))
+			.directions("Legends' Guild.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3573, 3425, 0))
+			.directions("North of Dessous's tomb from Desert Treasure.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3828, 2848, 0))
+			.directions("East of Harmony Island.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3225, 2838, 0))
+			.directions("South of Desert Treasure pyramid.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1773, 3510, 0))
+			.directions("Ruins north of the Hosidius mine.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3822, 3562, 0))
+			.directions("North-east of Dragontooth Island. Bring a Ghostspeak Amulet and 25 Ecto-tokens to reach the island.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3603, 3564, 0))
+			.directions("North of the wrecked ship, outside of Port Phasmatys.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2936, 2721, 0))
+			.directions("Eastern shore of Crash Island.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2697, 2705, 0))
+			.directions("South-west of Ape Atoll.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2778, 3678, 0))
+			.directions("Mountain Camp.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2827, 3740, 0))
+			.directions("West of the entrance to the Ice Path, where the Troll child resides.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2359, 3799, 0))
+			.directions("Neitiznot.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2194, 3807, 0))
+			.directions("Pirates' Cove.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2700, 3808, 0))
+			.directions("Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3215, 3835, 0))
+			.directions("Wilderness. Lava Dragon Isle.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3369, 3894, 0))
+			.directions("Wilderness. Fountain of Rune.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2065, 3923, 0))
+			.directions("Outside the western wall on Lunar Isle.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3188, 3933, 0))
+			.directions("Wilderness. Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3043, 3940, 0))
+			.directions("Wilderness. South of Pirates' Hideout.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3380, 3963, 0))
+			.directions("Wilderness. North of Volcano.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3051, 3736, 0))
+			.directions("East of the Wilderness Obelisk in 28 Wilderness.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2316, 3814, 0))
+			.directions("West of Neitiznot, near the bridge.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2872, 3937, 0))
+			.directions("Weiss.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2484, 4016, 0))
+			.directions("Northeast corner of the Island of Stone.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2222, 3331, 0))
+			.directions("Prifddinas, west of the Tower of Voices")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3560, 3987, 0))
+			.directions("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2318, 2954, 0))
+			.directions("North-east corner of the Isle of Souls (BJP).")
+			.enemy(BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2094, 2889, 0))
+			.directions("West side of the Isle of Souls.")
+			.enemy(ARMADYLEAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1451, 3509, 0))
+			.directions("Ruins of Morra.")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3318, 2706, 0))
+			.directions("Necropolis mine")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1557, 3183, 0))
+			.directions("North of Ortus Farm")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1571, 3245, 0))
+			.directions("At the top of The Proudspire")
+			.enemy(ARMADYLEAN_OR_BANDOSIAN_GUARD)
+			.build(),
 		// Master
-		.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))
-		.put(new WorldPoint(2155, 3100, 0), new CoordinateClueInfo("South of Port Tyras (BJS if 76 Agility).", BRASSICAN_MAGE))
-		.put(new WorldPoint(2217, 3092, 0), new CoordinateClueInfo("Poison Waste island (DLR).", BRASSICAN_MAGE))
-		.put(new WorldPoint(3830, 3060, 0), new CoordinateClueInfo("Small island located north-east of Mos Le'Harmless.", BRASSICAN_MAGE, true, Varbits.FIRE_PIT_MOS_LE_HARMLESS))
-		.put(new WorldPoint(2834, 3271, 0), new CoordinateClueInfo("Crandor island.", BRASSICAN_MAGE))
-		.put(new WorldPoint(2732, 3284, 0), new CoordinateClueInfo("Witchaven.", BRASSICAN_MAGE))
-		.put(new WorldPoint(3622, 3320, 0), new CoordinateClueInfo("Meiyerditch. Outside mine.", BRASSICAN_MAGE))
-		.put(new WorldPoint(2303, 3328, 0), new CoordinateClueInfo("East of Prifddinas.", BRASSICAN_MAGE))
-		.put(new WorldPoint(3570, 3405, 0), new CoordinateClueInfo("North of Dessous's tomb from Desert Treasure.", BRASSICAN_MAGE))
-		.put(new WorldPoint(2840, 3423, 0), new CoordinateClueInfo("Water Obelisk Island.", BRASSICAN_MAGE))
-		.put(new WorldPoint(3604, 3564, 0), new CoordinateClueInfo("North of the wrecked ship, outside of Port Phasmatys (ALQ).", BRASSICAN_MAGE))
-		.put(new WorldPoint(3085, 3569, 0), new CoordinateClueInfo("Wilderness. Obelisk of Air.", BRASSICAN_MAGE))
-		.put(new WorldPoint(2934, 2727, 0), new CoordinateClueInfo("Eastern shore of Crash Island.", BRASSICAN_MAGE))
-		.put(new WorldPoint(1451, 3695, 0), new CoordinateClueInfo("West side of Lizardman Canyon with Lizardman shaman.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(2538, 3739, 0), new CoordinateClueInfo("Waterbirth Island. Bring a pet rock and rune thrownaxe OR have 85 agility.", BRASSICAN_MAGE))
-		.put(new WorldPoint(1248, 3751, 0), new CoordinateClueInfo("In the north wing of the Farming Guild.", BRASSICAN_MAGE))
-		.put(new WorldPoint(1698, 3792, 0), new CoordinateClueInfo("Arceuus church.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(2951, 3820, 0), new CoordinateClueInfo("Wilderness. Chaos Temple (level 38).", ANCIENT_WIZARDS))
-		.put(new WorldPoint(2202, 3825, 0), new CoordinateClueInfo("Pirates' Cove, between Lunar Isle and Rellekka.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(1761, 3853, 0), new CoordinateClueInfo("Arceuus essence mine (CIS).", BRASSICAN_MAGE))
-		.put(new WorldPoint(2090, 3863, 0), new CoordinateClueInfo("South of Lunar Isle, west of Astral altar.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(1442, 3878, 0), new CoordinateClueInfo("Northern area of the Lovakengj Sulphur Mine. Facemask or Slayer Helmet recommended.", BRASSICAN_MAGE))
-		.put(new WorldPoint(3380, 3929, 0), new CoordinateClueInfo("Wilderness. Near Volcano.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE))
-		.put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS))
-		.put(new WorldPoint(3028, 3928, 0), new CoordinateClueInfo("Wilderness. South-east of Agility Training Area.", BRASSICAN_MAGE))
-		.put(new WorldPoint(1769, 3418, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS))
-		.build();
+		CoordinateClue.builder()
+			.location(new WorldPoint(2178, 3209, 0))
+			.directions("South of Iorwerth Camp.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2155, 3100, 0))
+			.directions("South of Port Tyras (BJS if 76 Agility).")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2217, 3092, 0))
+			.directions("Poison Waste island (DLR).")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3830, 3060, 0))
+			.directions("Small island located north-east of Mos Le'Harmless.")
+			.enemy(BRASSICAN_MAGE)
+			.lightSourceVarbitId(Varbits.FIRE_PIT_MOS_LE_HARMLESS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2834, 3271, 0))
+			.directions("Crandor island.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2732, 3284, 0))
+			.directions("Witchaven.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3622, 3320, 0))
+			.directions("Meiyerditch. Outside mine.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2303, 3328, 0))
+			.directions("East of Prifddinas.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3570, 3405, 0))
+			.directions("North of Dessous's tomb from Desert Treasure.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2840, 3423, 0))
+			.directions("Water Obelisk Island.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3604, 3564, 0))
+			.directions("North of the wrecked ship, outside of Port Phasmatys (ALQ).")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3085, 3569, 0))
+			.directions("Wilderness. Obelisk of Air.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2934, 2727, 0))
+			.directions("Eastern shore of Crash Island.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1451, 3695, 0))
+			.directions("West side of Lizardman Canyon with Lizardman shaman.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2538, 3739, 0))
+			.directions("Waterbirth Island. Bring a pet rock and rune thrownaxe OR have 85 agility.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1248, 3751, 0))
+			.directions("In the north wing of the Farming Guild.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1698, 3792, 0))
+			.directions("Arceuus church.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2951, 3820, 0))
+			.directions("Wilderness. Chaos Temple (level 38).")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2202, 3825, 0))
+			.directions("Pirates' Cove, between Lunar Isle and Rellekka.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1761, 3853, 0))
+			.directions("Arceuus essence mine (CIS).")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(2090, 3863, 0))
+			.directions("South of Lunar Isle, west of Astral altar.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1442, 3878, 0))
+			.directions("Northern area of the Lovakengj Sulphur Mine. Facemask or Slayer Helmet recommended.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3380, 3929, 0))
+			.directions("Wilderness. Near Volcano.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3188, 3939, 0))
+			.directions("Wilderness. Resource Area.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3304, 3941, 0))
+			.directions("Wilderness. East of Rogues' Castle.")
+			.enemy(ANCIENT_WIZARDS)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(3028, 3928, 0))
+			.directions("Wilderness. South-east of Agility Training Area.")
+			.enemy(BRASSICAN_MAGE)
+			.build(),
+		CoordinateClue.builder()
+			.location(new WorldPoint(1769, 3418, 0))
+			.directions("Crabclaw Isle")
+			.enemy(ANCIENT_WIZARDS)
+			.build()
+	)
+		.stream()
+		.collect(Collectors.collectingAndThen(
+			Collectors.toMap(
+				CoordinateClue::getLocation,
+				clue -> clue
+			),
+			ImmutableMap::copyOf
+		));
 
 	private final String text;
+	private final String directions;
+	private final Enemy enemy;
+	@Getter(onMethod_ = {@Varbit})
+	private final int lightSourceVarbitId;
 	@Getter(AccessLevel.PRIVATE)
 	private final WorldPoint location;
 	/**
@@ -266,22 +854,32 @@ public class CoordinateClue extends ClueScroll implements LocationClueScroll
 	@Nullable
 	private final WorldPoint mirrorLocation;
 
-	public CoordinateClue(String text, WorldPoint location, WorldPoint mirrorLocation)
+	@Builder
+	private CoordinateClue(
+		String text,
+		String directions,
+		Enemy enemy,
+		WorldPoint location,
+		@Varbit Integer lightSourceVarbitId
+	)
 	{
 		this.text = text;
+		this.directions = directions;
+		this.enemy = enemy;
 		this.location = location;
-		this.mirrorLocation = mirrorLocation;
+		this.mirrorLocation = location == null ? null : WorldPoint.getMirrorPoint(location, false);
+		this.lightSourceVarbitId = lightSourceVarbitId == null ? -1 : lightSourceVarbitId;
 
-		final CoordinateClueInfo clueInfo = CLUES.get(location);
-		if (clueInfo != null)
-		{
-			setFirePitVarbitId(clueInfo.getLightSourceVarbitId());
-			setRequiresLight(clueInfo.lightRequired);
-			setEnemy(clueInfo.getEnemy());
-		}
+		setFirePitVarbitId(this.lightSourceVarbitId);
+		setRequiresLight(this.lightSourceVarbitId != -1);
 		setRequiresSpade(true);
 	}
 
+	public static CoordinateClue forLocation(WorldPoint location)
+	{
+		return CLUES.get(location);
+	}
+
 	@Override
 	public WorldPoint getLocation(ClueScrollPlugin plugin)
 	{
@@ -291,7 +889,7 @@ public class CoordinateClue extends ClueScroll implements LocationClueScroll
 	@Override
 	public WorldPoint[] getLocations(ClueScrollPlugin plugin)
 	{
-		if (mirrorLocation != null)
+		if (mirrorLocation != null && mirrorLocation != location)
 		{
 			return new WorldPoint[]{location, mirrorLocation};
 		}
@@ -306,7 +904,7 @@ public class CoordinateClue extends ClueScroll implements LocationClueScroll
 	{
 		panelComponent.getChildren().add(TitleComponent.builder().text("Coordinate Clue").build());
 
-		final CoordinateClueInfo solution = CLUES.get(location);
+		final CoordinateClue solution = CLUES.get(location);
 
 		if (solution != null)
 		{


Test patch:
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ConfigKeyTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ConfigKeyTest.java
index 798f4c523..9f6d5f23c 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ConfigKeyTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ConfigKeyTest.java
@@ -38,9 +38,7 @@ public class ConfigKeyTest
 	{
 		List<ClueScroll> allClues = new ArrayList<>();
 		allClues.addAll(FairyRingClue.CLUES);
-		CoordinateClue.CLUES.keySet().stream()
-			.map(l -> new CoordinateClue("location", l, null))
-			.forEach(allClues::add);
+		allClues.addAll(CoordinateClue.CLUES.values());
 		allClues.addAll(CipherClue.CLUES);
 		allClues.addAll(CrypticClue.CLUES);
 		allClues.addAll(FaloTheBardClue.CLUES);
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java
index 91d0080cb..052a17ffd 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java
@@ -24,10 +24,10 @@
  */
 package net.runelite.client.plugins.cluescrolls.clues;
 
-import java.util.Map;
 import net.runelite.api.coords.WorldPoint;
-import org.junit.Test;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 public class CoordinateClueTest
 {
@@ -35,22 +35,31 @@ public class CoordinateClueTest
 	public void testDuplicateCoordinates()
 	{
 		// If this doesn't throw then the clues map doesn't have duplicate keys
-		new CoordinateClue("test", new WorldPoint(0, 0, 0), null);
+		CoordinateClue.builder().build();
+	}
+
+	@Test
+	public void testRequiresLight()
+	{
+		final CoordinateClue clueWithFirepit = CoordinateClue.forLocation(new WorldPoint(3830, 3060, 0));
+		final CoordinateClue clueWithoutFirepit = CoordinateClue.forLocation(new WorldPoint(2217, 3092, 0));
+
+		assertTrue(clueWithFirepit.isRequiresLight());
+		assertFalse(clueWithoutFirepit.isRequiresLight());
 	}
 
 	@Test
 	public void testIsleOfSoulsNpcs()
 	{
-		for (Map.Entry<WorldPoint, CoordinateClue.CoordinateClueInfo> clueEntry : CoordinateClue.CLUES.entrySet())
+		for (CoordinateClue clue : CoordinateClue.CLUES.values())
 		{
-			final CoordinateClue.CoordinateClueInfo clueInfo = clueEntry.getValue();
-			final Enemy enemy = clueInfo.getEnemy();
+			final Enemy enemy = clue.getEnemy();
 			if (!(enemy == Enemy.ARMADYLEAN_GUARD || enemy == Enemy.BANDOSIAN_GUARD))
 			{
 				continue;
 			}
 
-			assertTrue("Armadylean guard-only and Bandosian guard-only clues only occur on the Isle of Souls; the following entry must be corrected:\n" + clueEntry, clueInfo.getDirections().contains("Isle of Souls"));
+			assertTrue("Armadylean guard-only and Bandosian guard-only clues only occur on the Isle of Souls; the following entry must be corrected:\n" + clue, clue.getDirections().contains("Isle of Souls"));
 		}
 	}
 }