Переглянути джерело

Apply new project formatting

Lilith 2 роки тому
батько
коміт
9a93244147

+ 210 - 0
HuntBuddy/.editorconfig

@@ -0,0 +1,210 @@
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
+root = true
+
+[*]
+
+# Indentation and spacing
+indent_size = 4
+indent_style = tab
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = true
+
+# C# files
+[*.cs]
+
+# Organize usings
+dotnet_separate_import_directive_groups = true
+dotnet_sort_system_directives_first = true
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = true:warning
+dotnet_style_qualification_for_field = true:warning
+dotnet_style_qualification_for_method = true:warning
+dotnet_style_qualification_for_property = true:warning
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:warning
+dotnet_style_predefined_type_for_member_access = true:warning
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
+
+# Expression-level preferences
+dotnet_style_coalesce_expression = true:warning
+dotnet_style_collection_initializer = true:warning
+dotnet_style_explicit_tuple_names = true:warning
+dotnet_style_null_propagation = true:error
+dotnet_style_object_initializer = true:warning
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:warning
+dotnet_style_prefer_compound_assignment = true:warning
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
+dotnet_style_prefer_inferred_tuple_names = true:warning
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+
+# Field preferences
+dotnet_style_readonly_field = true:suggestion
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all:suggestion
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# var preferences
+csharp_style_var_elsewhere = false:warning
+csharp_style_var_for_built_in_types = false:warning
+csharp_style_var_when_type_is_apparent = false:warning
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = when_on_single_line:suggestion
+csharp_style_expression_bodied_constructors = when_on_single_line:suggestion
+csharp_style_expression_bodied_indexers = when_on_single_line:suggestion
+csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion
+csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion
+csharp_style_expression_bodied_methods = when_on_single_line:suggestion
+csharp_style_expression_bodied_operators = when_on_single_line:suggestion
+csharp_style_expression_bodied_properties = when_on_single_line:suggestion
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true:warning
+csharp_style_pattern_matching_over_is_with_cast_check = true:warning
+csharp_style_prefer_extended_property_pattern = true:warning
+csharp_style_prefer_not_pattern = true:warning
+csharp_style_prefer_pattern_matching = true:warning
+csharp_style_prefer_switch_expression = true:warning
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true:warning
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:silent
+csharp_prefer_readonly_struct = true:warning
+
+# Code-block preferences
+csharp_prefer_braces = when_multiline:warning
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = file_scoped:error
+csharp_style_prefer_top_level_statements = false:error
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_prefer_tuple_swap = true:error
+csharp_style_prefer_null_check_over_type_check = true:error
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:silent
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:suggestion
+
+# New line preferences
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = none
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = false
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = false
+
+#### Naming styles ####
+
+# Style Definitions
+dotnet_naming_style.pascal_case_style.capitalization               = pascal_case
+
+dotnet_naming_style.I_prefix_style.required_prefix                 = I
+dotnet_naming_style.I_prefix_style.capitalization                  = pascal_case
+
+dotnet_naming_style.camel_case_underscore_style.capitalization     = camel_case
+
+# Use PascalCase for constant fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity  = warning
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols   = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style     = pascal_case_style
+dotnet_naming_symbols.constant_fields.applicable_kinds             = field
+dotnet_naming_symbols.constant_fields.applicable_accessibilities   = *
+dotnet_naming_symbols.constant_fields.required_modifiers           = const
+
+# Use PascalCase for public fields
+dotnet_naming_rule.pascal_case_for_public_fields.severity          = warning
+dotnet_naming_rule.pascal_case_for_public_fields.symbols           = public_fields
+dotnet_naming_rule.pascal_case_for_public_fields.style             = pascal_case_style
+dotnet_naming_symbols.public_fields.applicable_kinds               = field
+dotnet_naming_symbols.public_fields.applicable_accessibilities     = public
+
+# internal and private fields should be camelCase
+dotnet_naming_rule.camel_case_for_private_internal_fields.severity       = warning
+dotnet_naming_rule.camel_case_for_private_internal_fields.symbols        = private_internal_fields
+dotnet_naming_rule.camel_case_for_private_internal_fields.style          = camel_case_underscore_style
+dotnet_naming_symbols.private_internal_fields.applicable_kinds           = field
+dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
+
+# Interfaces must be PascalCase and have an I prefix
+dotnet_naming_rule.interfaces_start_with_I.severity                = warning
+dotnet_naming_rule.interfaces_start_with_I.symbols                 = any_interface
+dotnet_naming_rule.interfaces_start_with_I.style                   = I_prefix_style
+dotnet_naming_symbols.any_interface.applicable_kinds               = interface
+dotnet_naming_symbols.any_interface.applicable_accessibilities     = *
+
+# Classes, structs, methods, enums, events, properties, namespaces, delegates must be PascalCase
+dotnet_naming_rule.general_naming.severity                         = warning
+dotnet_naming_rule.general_naming.symbols                          = general
+dotnet_naming_rule.general_naming.style                            = pascal_case_style
+dotnet_naming_symbols.general.applicable_kinds                     = class,struct,enum,property,method,event,namespace,delegate
+dotnet_naming_symbols.general.applicable_accessibilities           = *

+ 8 - 11
HuntBuddy/Attributes/AliasesAttribute.cs

@@ -1,15 +1,12 @@
 using System;
 
-namespace HuntBuddy.Attributes
-{
-	[AttributeUsage(AttributeTargets.Method)]
-	public class AliasesAttribute : Attribute
-	{
-		public string[] Aliases { get; }
+namespace HuntBuddy.Attributes;
 
-		public AliasesAttribute(params string[] aliases)
-		{
-			this.Aliases = aliases;
-		}
+[AttributeUsage(AttributeTargets.Method)]
+public class AliasesAttribute: Attribute {
+	public string[] Aliases {
+		get;
 	}
-}
+
+	public AliasesAttribute(params string[] aliases) => this.Aliases = aliases;
+}

+ 7 - 12
HuntBuddy/Attributes/CommandAttribute.cs

@@ -1,15 +1,10 @@
 using System;
 
-namespace HuntBuddy.Attributes
-{
-	[AttributeUsage(AttributeTargets.Method)]
-	public class CommandAttribute : Attribute
-	{
-		public string Command { get; }
+namespace HuntBuddy.Attributes;
 
-		public CommandAttribute(string command)
-		{
-			this.Command = command;
-		}
-	}
-}
+[AttributeUsage(AttributeTargets.Method)]
+public class CommandAttribute: Attribute {
+	public string Command { get; }
+
+	public CommandAttribute(string command) => this.Command = command;
+}

+ 4 - 7
HuntBuddy/Attributes/DoNotShowInHelpAttribute.cs

@@ -1,9 +1,6 @@
 using System;
 
-namespace HuntBuddy.Attributes
-{
-	[AttributeUsage(AttributeTargets.Method)]
-	public class DoNotShowInHelpAttribute : Attribute
-	{
-	}
-}
+namespace HuntBuddy.Attributes;
+
+[AttributeUsage(AttributeTargets.Method)]
+public class DoNotShowInHelpAttribute: Attribute;

+ 8 - 11
HuntBuddy/Attributes/HelpMessageAttribute.cs

@@ -1,15 +1,12 @@
 using System;
 
-namespace HuntBuddy.Attributes
-{
-	[AttributeUsage(AttributeTargets.Method)]
-	public class HelpMessageAttribute : Attribute
-	{
-		public string HelpMessage { get; }
+namespace HuntBuddy.Attributes;
 
-		public HelpMessageAttribute(string helpMessage)
-		{
-			this.HelpMessage = helpMessage;
-		}
+[AttributeUsage(AttributeTargets.Method)]
+public class HelpMessageAttribute: Attribute {
+	public string HelpMessage {
+		get;
 	}
-}
+
+	public HelpMessageAttribute(string helpMessage) => this.HelpMessage = helpMessage;
+}

+ 19 - 20
HuntBuddy/Configuration.cs

@@ -1,27 +1,26 @@
 using System.Numerics;
 using System.Text.Json.Serialization;
+
 using Dalamud.Configuration;
 
-namespace HuntBuddy
-{
-	public class Configuration : IPluginConfiguration
-	{
-		public int Version { get; set; }
+namespace HuntBuddy;
+
+public class Configuration: IPluginConfiguration {
+	public int Version {
+		get;
+		set;
+	}
 
-		public bool IncludeAreaOnMap;
-		public bool LockWindowPositions;
-		public bool ShowLocalHunts;
-		public bool ShowLocalHuntIcons;
-		public bool HideLocalHuntBackground;
-		public bool HideCompletedHunts;
-		public float IconScale = 1f;
-		public Vector4 IconBackgroundColour = new (0.76f, 0.75f, 0.76f, 0.8f);
+	public bool IncludeAreaOnMap;
+	public bool LockWindowPositions;
+	public bool ShowLocalHunts;
+	public bool ShowLocalHuntIcons;
+	public bool HideLocalHuntBackground;
+	public bool HideCompletedHunts;
+	public float IconScale = 1f;
+	public Vector4 IconBackgroundColour = new(0.76f, 0.75f, 0.76f, 0.8f);
 
-		[JsonIgnore] public uint IconBackgroundColourU32;
+	[JsonIgnore] public uint IconBackgroundColourU32;
 
-		public void Save()
-		{
-			Service.PluginInterface.SavePluginConfig(this);
-		}
-	}
-}
+	public void Save() => Service.PluginInterface.SavePluginConfig(this);
+}

+ 39 - 51
HuntBuddy/Ipc/TeleportConsumer.cs

@@ -1,66 +1,54 @@
 using System;
-using Dalamud.Plugin.Ipc;
 
-namespace HuntBuddy.Ipc
-{
-	public class TeleportConsumer
-	{
-		private bool isAvailable;
-		private long timeSinceLastCheck;
+using Dalamud.Plugin.Ipc;
 
-		public bool IsAvailable
-		{
-			get
-			{
-				if (this.timeSinceLastCheck + 5000 > Environment.TickCount64)
-				{
-					return this.isAvailable;
-				}
+namespace HuntBuddy.Ipc;
 
-				try
-				{
-					this.consumerMessageSetting.InvokeFunc();
-					this.isAvailable = true;
-					this.timeSinceLastCheck = Environment.TickCount64;
-				}
-				catch
-				{
-					this.isAvailable = false;
-				}
+public class TeleportConsumer {
+	private bool isAvailable;
+	private long timeSinceLastCheck;
 
+	public bool IsAvailable {
+		get {
+			if (this.timeSinceLastCheck + 5000 > Environment.TickCount64) {
 				return this.isAvailable;
 			}
-		}
-
-		private ICallGateSubscriber<bool> consumerMessageSetting = null!;
-		private ICallGateSubscriber<uint, byte, bool> consumerTeleport = null!;
 
-		private void Subscribe()
-		{
-			try
-			{
-				this.consumerTeleport = Service.PluginInterface.GetIpcSubscriber<uint, byte, bool>("Teleport");
-				this.consumerMessageSetting = Service.PluginInterface.GetIpcSubscriber<bool>("Teleport.ChatMessage");
+			try {
+				this.consumerMessageSetting.InvokeFunc();
+				this.isAvailable = true;
+				this.timeSinceLastCheck = Environment.TickCount64;
 			}
-			catch (Exception ex)
-			{
-				Service.PluginLog.Debug($"Failed to subscribe to Teleporter\nReason: {ex}");
+			catch {
+				this.isAvailable = false;
 			}
+
+			return this.isAvailable;
 		}
+	}
 
-		public TeleportConsumer() => this.Subscribe();
+	private ICallGateSubscriber<bool> consumerMessageSetting = null!;
+	private ICallGateSubscriber<uint, byte, bool> consumerTeleport = null!;
 
-		public bool Teleport(uint aetheryteId)
-		{
-			try
-			{
-				return this.consumerTeleport.InvokeFunc(aetheryteId, 0);
-			}
-			catch
-			{
-				Service.Chat.PrintError("Teleporter plugin is not responding");
-				return false;
-			}
+	private void Subscribe() {
+		try {
+			this.consumerTeleport = Service.PluginInterface.GetIpcSubscriber<uint, byte, bool>("Teleport");
+			this.consumerMessageSetting = Service.PluginInterface.GetIpcSubscriber<bool>("Teleport.ChatMessage");
+		}
+		catch (Exception ex) {
+			Service.PluginLog.Debug($"Failed to subscribe to Teleporter\nReason: {ex}");
+		}
+	}
+
+	public TeleportConsumer() => this.Subscribe();
+
+	public bool Teleport(uint aetheryteId) {
+		try {
+			return this.consumerTeleport.InvokeFunc(aetheryteId, 0);
+		}
+		catch {
+			Service.Chat.PrintError("Teleporter plugin is not responding");
+			return false;
 		}
 	}
-}
+}

+ 533 - 537
HuntBuddy/Location.cs

@@ -2,556 +2,552 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
+
+using FFXIVClientStructs.FFXIV.Client.UI.Agent;
+
 using Lumina.Excel.GeneratedSheets;
-using MapType = FFXIVClientStructs.FFXIV.Client.UI.Agent.MapType;
 
-namespace HuntBuddy
-{
-	public static class Location
-	{
-		public class PositionInfo
-		{
-			public float X { get; init; }
+using MapType = FFXIVClientStructs.FFXIV.Client.UI.Agent.MapType;
 
-			public float Y { get; init; }
+namespace HuntBuddy;
 
-			public Vector2 Coordinate => new (this.X, this.Y);
+public static class Location {
+	public class PositionInfo {
+		public float X {
+			get;
+			init;
 		}
 
-		// MobHuntId as key
-		public static readonly Dictionary<uint, PositionInfo> Database = new ()
-		{
-			// Heavensward
-			// Coerthas Western Highlands
-			{ 03481, new PositionInfo { X = 15.0f, Y = 12.0f } }, // Archaeornis
-			{ 03472, new PositionInfo { X = 32.0f, Y = 24.0f } }, // Bergthurs
-			{ 03471, new PositionInfo { X = 30.0f, Y = 31.0f } }, // Deepeye
-			{ 03476, new PositionInfo { X = 28.0f, Y = 12.0f } }, // Frost Grenade
-			{ 03480, new PositionInfo { X = 11.0f, Y = 17.0f } }, // Gelato
-			{ 03484, new PositionInfo { X = 10.0f, Y = 14.0f } }, // Ice Commander
-			{ 03475, new PositionInfo { X = 23.0f, Y = 16.0f } }, // Icetrap
-			{ 03487, new PositionInfo { X = 28.0f, Y = 09.0f } }, // Inland Tursus
-			{ 03483, new PositionInfo { X = 19.0f, Y = 29.0f } }, // Lone Yeti
-			{ 03485, new PositionInfo { X = 22.0f, Y = 21.0f } }, // Polar Bear
-			{ 03482, new PositionInfo { X = 16.0f, Y = 20.0f } }, // Rheum
-			{ 03473, new PositionInfo { X = 26.0f, Y = 24.0f } }, // Silver Wolf
-			{ 03490, new PositionInfo { X = 25.0f, Y = 32.0f } }, // Slate Yeti
-			{ 03478, new PositionInfo { X = 25.0f, Y = 12.0f } }, // Slush Zoblyn
-			{ 03470, new PositionInfo { X = 30.0f, Y = 32.0f } }, // Steinbock
-			{ 03474, new PositionInfo { X = 31.0f, Y = 20.0f } }, // Upland Mylodon
-			{ 03493, new PositionInfo { X = 09.0f, Y = 09.0f } }, // Vindthurs
-			{ 03479, new PositionInfo { X = 15.0f, Y = 17.0f } }, // Wooly Yak
-
-			// The Sea of Clouds
-			{ 03524, new PositionInfo { X = 21.0f, Y = 06.0f } }, // Anzu
-			{ 03498, new PositionInfo { X = 28.0f, Y = 29.0f } }, // Cloudworm
-			{ 03496, new PositionInfo { X = 27.0f, Y = 30.0f } }, // Conodont
-			{ 03505, new PositionInfo { X = 19.0f, Y = 30.0f } }, // Dhalmel
-			{ 03511, new PositionInfo { X = 17.0f, Y = 10.0f } }, // Endymion
-			{ 03494, new PositionInfo { X = 11.0f, Y = 33.0f } }, // Gaelicat
-			{ 03495, new PositionInfo { X = 16.0f, Y = 36.0f } }, // Gastornis
-			{ 03512, new PositionInfo { X = 23.0f, Y = 09.0f } }, // Groundskeeper
-			{ 03506, new PositionInfo { X = 20.0f, Y = 30.0f } }, // Korrigan
-			{ 03501, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Lan'laii Gundu
-			{ 03502, new PositionInfo { X = 36.0f, Y = 20.0f } }, // Nat'laii Gundu
-			{ 03516, new PositionInfo { X = 28.0f, Y = 10.0f } }, // Nat'laii Vundu
-			{ 03497, new PositionInfo { X = 29.0f, Y = 30.0f } }, // Obdella
-			{ 03499, new PositionInfo { X = 20.0f, Y = 34.0f } }, // Paissa
-			{ 03500, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Sanuwa
-			{ 03514, new PositionInfo { X = 30.0f, Y = 14.0f } }, // Sanuwa Vundu
-			{ 03525, new PositionInfo { X = 21.0f, Y = 07.0f } }, // Toco Toco
-			{ 03523, new PositionInfo { X = 14.0f, Y = 07.0f } }, // Tsanahale
-			{ 03503, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Vuk'laii Gundu
-			{ 03513, new PositionInfo { X = 18.0f, Y = 17.0f } }, // Vundu Totem
-			{ 03509, new PositionInfo { X = 09.0f, Y = 16.0f } }, // Window Wamoura
-			{ 03510, new PositionInfo { X = 10.0f, Y = 17.0f } }, // Window Wamouracampa
-			{ 03504, new PositionInfo { X = 20.0f, Y = 38.0f } }, // Wisent
-
-			// The Dravanian Forelands
-			{ 03565, new PositionInfo { X = 30.0f, Y = 16.0f } }, // Bandersnatch
-			{ 03566, new PositionInfo { X = 26.0f, Y = 11.0f } }, // Brown Bear
-			{ 03570, new PositionInfo { X = 28.0f, Y = 22.0f } }, // Clearwater Nanka
-			{ 03569, new PositionInfo { X = 27.0f, Y = 25.0f } }, // Clearwater Ninki Nanka
-			{ 03572, new PositionInfo { X = 28.0f, Y = 32.0f } }, // Dragonfly Watcher
-			{ 03567, new PositionInfo { X = 27.0f, Y = 22.0f } }, // Dravanian Aevis
-			{ 03576, new PositionInfo { X = 16.0f, Y = 33.0f } }, // Dravanian Wyvern
-			{ 03563, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Feather Flea
-			{ 03578, new PositionInfo { X = 17.0f, Y = 26.0f } }, // Forelands Hippocerf
-			{ 03579, new PositionInfo { X = 18.0f, Y = 12.0f } }, // Gallimimus
-			{ 03571, new PositionInfo { X = 25.0f, Y = 29.0f } }, // Loaghtan
-			{ 03592, new PositionInfo { X = 27.0f, Y = 35.0f } }, // Loth Cultivator
-			{ 03590, new PositionInfo { X = 27.0f, Y = 35.0f } }, // Loth Firedrone
-			{ 03591, new PositionInfo { X = 29.0f, Y = 36.0f } }, // Loth Steeldrone
-			{ 03568, new PositionInfo { X = 28.0f, Y = 25.0f } }, // Melia
-			{ 03577, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Miacid
-			{ 03555, new PositionInfo { X = 18.0f, Y = 12.0f } }, // Syricta
-			{ 03586, new PositionInfo { X = 31.0f, Y = 08.0f } }, // Thunder Dragon
-			{ 03582, new PositionInfo { X = 13.0f, Y = 15.0f } }, // Tyrannosaur
-			{ 03581, new PositionInfo { X = 13.0f, Y = 14.0f } }, // Vinegaroon
-			{ 03564, new PositionInfo { X = 35.0f, Y = 21.0f } }, // Wild Chocobo
-
-			// The Churning Mists
-			{ 03619, new PositionInfo { X = 17.0f, Y = 27.0f } }, // Amphiptere
-			{ 03620, new PositionInfo { X = 24.0f, Y = 26.0f } }, // Archaeosaur
-			{ 03625, new PositionInfo { X = 18.0f, Y = 24.0f } }, // Bladed Vinegaroon
-			{ 03630, new PositionInfo { X = 25.0f, Y = 10.0f } }, // Blood Dragon
-			{ 03631, new PositionInfo { X = 09.0f, Y = 36.0f } }, // Cloud Aevis
-			{ 03629, new PositionInfo { X = 08.0f, Y = 19.0f } }, // Diresaur
-			{ 03623, new PositionInfo { X = 20.0f, Y = 12.0f } }, // Dragonet
-			{ 03626, new PositionInfo { X = 34.0f, Y = 21.0f } }, // Elder Syricta
-			{ 03628, new PositionInfo { X = 25.0f, Y = 30.0f } }, // Elder Wyvern
-			{ 03668, new PositionInfo { X = 10.0f, Y = 20.0f } }, // Gnarled Melia
-			{ 03614, new PositionInfo { X = 34.0f, Y = 28.0f } }, // Hropken
-			{ 03621, new PositionInfo { X = 09.0f, Y = 12.0f } }, // Limestone Golem
-			{ 03618, new PositionInfo { X = 20.0f, Y = 28.0f } }, // Lower Skylord
-			{ 03627, new PositionInfo { X = 33.0f, Y = 31.0f } }, // Mists Biast
-			{ 03622, new PositionInfo { X = 10.0f, Y = 18.0f } }, // Mists Drake
-			{ 03617, new PositionInfo { X = 23.0f, Y = 25.0f } }, // Moss Dragon
-			{ 03613, new PositionInfo { X = 28.0f, Y = 32.0f } }, // Sankchinni
-			{ 03615, new PositionInfo { X = 32.0f, Y = 15.0f } }, // Tulihand
-			{ 03624, new PositionInfo { X = 38.0f, Y = 17.7f } }, // Vouivre
-			{ 03616, new PositionInfo { X = 26.0f, Y = 20.0f } }, // Wadjet
-
-			// The Dravanian Hinterlands
-			{ 03612, new PositionInfo { X = 25.0f, Y = 37.0f } }, // Bifericeras
-			{ 03609, new PositionInfo { X = 18.0f, Y = 36.0f } }, // Cockatrice
-			{ 03603, new PositionInfo { X = 12.0f, Y = 16.0f } }, // Crawler
-			{ 03594, new PositionInfo { X = 24.0f, Y = 21.0f } }, // Damselfly
-			{ 03598, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Brandisher
-			{ 03601, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Glider
-			{ 03600, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Sharpshooter
-			{ 03599, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Tinkerer
-			{ 03605, new PositionInfo { X = 10.0f, Y = 21.0f } }, // Great Morbol
-			{ 03597, new PositionInfo { X = 37.0f, Y = 24.0f } }, // Narbrooi
-			{ 03610, new PositionInfo { X = 17.0f, Y = 33.0f } }, // Okeanis
-			{ 03608, new PositionInfo { X = 12.0f, Y = 33.0f } }, // Opken
-			{ 03604, new PositionInfo { X = 11.0f, Y = 27.0f } }, // Orn Kite
-			{ 03607, new PositionInfo { X = 09.0f, Y = 34.0f } }, // Poroggo
-			{ 03595, new PositionInfo { X = 28.0f, Y = 27.0f } }, // Ratel
-			{ 03611, new PositionInfo { X = 12.0f, Y = 32.0f } }, // Sun Leech
-			{ 03593, new PositionInfo { X = 21.0f, Y = 16.0f } }, // Tarantula Hawk
-			{ 03596, new PositionInfo { X = 34.0f, Y = 19.0f } }, // Wildebeest
-
-			// Azys Lla
-			{ 03545, new PositionInfo { X = 35.0f, Y = 24.0f } }, // 6th Legion Vanguard
-			{ 03552, new PositionInfo { X = 27.0f, Y = 33.0f } }, // Adamantite Claw
-			{ 03540, new PositionInfo { X = 31.0f, Y = 06.0f } }, // Allagan Chimera
-			{ 03534, new PositionInfo { X = 15.0f, Y = 13.0f } }, // Clockwork Engineer
-			{ 03536, new PositionInfo { X = 13.0f, Y = 08.0f } }, // Clockwork Harvestman
-			{ 03535, new PositionInfo { X = 18.0f, Y = 13.0f } }, // Clockwork Paladin
-			{ 03542, new PositionInfo { X = 35.0f, Y = 09.0f } }, // Corpse Flower
-			{ 03541, new PositionInfo { X = 29.5f, Y = 12.0f } }, // Empuse
-			{ 03537, new PositionInfo { X = 13.0f, Y = 17.0f } }, // Enforcement Droid
-			{ 03539, new PositionInfo { X = 27.0f, Y = 11.0f } }, // Lamia Cybrid
-			{ 03538, new PositionInfo { X = 28.0f, Y = 13.0f } }, // Lamia Thelytoke
-			{ 03580, new PositionInfo { X = 13.0f, Y = 33.0f } }, // Lesser Hydra
-			{ 03559, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Meracydian Amphiptere
-			{ 03557, new PositionInfo { X = 08.0f, Y = 32.0f } }, // Meracydian Brobinyak
-			{ 03560, new PositionInfo { X = 08.0f, Y = 27.0f } }, // Meracydian Dragon
-			{ 03558, new PositionInfo { X = 06.0f, Y = 35.0f } }, // Meracydian Dragonet
-			{ 03554, new PositionInfo { X = 15.0f, Y = 29.0f } }, // Meracydian Falak
-			{ 03556, new PositionInfo { X = 14.0f, Y = 35.0f } }, // Meracydian Vouivre
-			{ 03533, new PositionInfo { X = 12.0f, Y = 15.0f } }, // Owlbear
-			{ 03543, new PositionInfo { X = 35.0f, Y = 08.0f } }, // Proto-naga
-			{ 03544, new PositionInfo { X = 33.0f, Y = 13.0f } }, // Reptoid
-			{ 03532, new PositionInfo { X = 09.0f, Y = 12.0f } }, // Snapper-rook
-
-			// Stormblood
-			// The Fringes
-			{ 05685, new PositionInfo { X = 10.0f, Y = 27.0f } }, // Diakka
-			{ 05674, new PositionInfo { X = 22.0f, Y = 16.0f } }, // Foper
-			{ 05697, new PositionInfo { X = 25.0f, Y = 27.0f } }, // Gazelle
-			{ 05676, new PositionInfo { X = 11.6f, Y = 12.0f } }, // Gazelle Hawk
-			{ 05679, new PositionInfo { X = 25.0f, Y = 15.0f } }, // Gelid Bhoot
-			{ 05686, new PositionInfo { X = 10.0f, Y = 27.0f } }, // Goosefish
-			{ 05671, new PositionInfo { X = 11.0f, Y = 11.0f } }, // Leshy
-			{ 05687, new PositionInfo { X = 11.0f, Y = 17.0f } }, // Mossling
-			{ 05683, new PositionInfo { X = 12.0f, Y = 17.0f } }, // Mountain Grizzly
-			{ 05691, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Brahmin
-			{ 05689, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Kshatriya
-			{ 05690, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Shudra
-			{ 05688, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Sacred Marid
-			{ 05675, new PositionInfo { X = 10.0f, Y = 12.0f } }, // Sapria
-			{ 05677, new PositionInfo { X = 22.0f, Y = 11.0f } }, // Spinner
-			{ 05693, new PositionInfo { X = 29.0f, Y = 24.0f } }, // Teleoceras
-			{ 05678, new PositionInfo { X = 28.0f, Y = 15.0f } }, // Velodyna Pugil
-			{ 05680, new PositionInfo { X = 17.0f, Y = 10.0f } }, // Velodyna Sarcosuchus
-
-			// The Peaks
-			{ 05705, new PositionInfo { X = 25.0f, Y = 11.0f } }, // Crag Claw
-			{ 05701, new PositionInfo { X = 18.7f, Y = 12.9f } }, // Bloodglider
-			{ 05702, new PositionInfo { X = 14.0f, Y = 08.0f } }, // Fluturini
-			{ 05703, new PositionInfo { X = 12.0f, Y = 08.0f } }, // Gyr Abanian Hornbill
-			{ 05713, new PositionInfo { X = 25.0f, Y = 33.0f } }, // Highland Eruca
-			{ 05712, new PositionInfo { X = 24.0f, Y = 29.0f } }, // Jhammel
-			{ 05714, new PositionInfo { X = 15.0f, Y = 27.0f } }, // Kongamato
-			{ 05707, new PositionInfo { X = 34.0f, Y = 09.0f } }, // Marble Urolith
-			{ 05715, new PositionInfo { X = 09.0f, Y = 26.0f } }, // Pantera
-			{ 05708, new PositionInfo { X = 24.0f, Y = 14.0f } }, // Scarab Beetle
-			{ 05711, new PositionInfo { X = 24.0f, Y = 24.0f } }, // True Griffin
-
-			// The Ruby Sea
-			{ 05737, new PositionInfo { X = 31.0f, Y = 35.0f } }, // Bombfish
-			{ 05736, new PositionInfo { X = 34.0f, Y = 05.0f } }, // Coralshell
-			{ 05740, new PositionInfo { X = 26.0f, Y = 30.0f } }, // Flying Shark
-			{ 05742, new PositionInfo { X = 23.0f, Y = 33.0f } }, // Gasame
-			{ 05734, new PositionInfo { X = 14.0f, Y = 10.0f } }, // Gyuki
-			{ 05751, new PositionInfo { X = 25.0f, Y = 25.0f } }, // Naked Yumemi
-			{ 05743, new PositionInfo { X = 07.0f, Y = 30.0f } }, // Red Bukan
-			{ 05745, new PositionInfo { X = 08.0f, Y = 28.0f } }, // Red Honkan
-			{ 05744, new PositionInfo { X = 09.5f, Y = 25.2f } }, // Red Hyoe
-			{ 05738, new PositionInfo { X = 33.0f, Y = 11.0f } }, // Sea Serpent
-			{ 05739, new PositionInfo { X = 26.0f, Y = 06.0f } }, // Shiranui
-			{ 05746, new PositionInfo { X = 07.0f, Y = 27.0f } }, // Striped Ray
-			{ 05733, new PositionInfo { X = 29.0f, Y = 37.0f } }, // Tatsunoko
-			{ 05735, new PositionInfo { X = 35.0f, Y = 21.0f } }, // Unkiu
-			{ 05750, new PositionInfo { X = 25.0f, Y = 25.0f } }, // Yumemi
-
-			// Yanxia
-			{ 05761, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Bi Fang
-			{ 05769, new PositionInfo { X = 28.0f, Y = 08.0f } }, // Ebisu Catfish
-			{ 05752, new PositionInfo { X = 27.0f, Y = 34.0f } }, // Lupin Bladehand
-			{ 05754, new PositionInfo { X = 24.0f, Y = 32.0f } }, // Lupin Bowhand
-			{ 05753, new PositionInfo { X = 23.0f, Y = 28.0f } }, // Lupin Spearhand
-			{ 05768, new PositionInfo { X = 19.0f, Y = 11.0f } }, // Magatsu Kiyofusa
-			{ 05763, new PositionInfo { X = 33.0f, Y = 17.0f } }, // Minobi
-			{ 05757, new PositionInfo { X = 30.0f, Y = 23.0f } }, // Rhino Beetle
-			{ 05765, new PositionInfo { X = 30.0f, Y = 34.0f } }, // Taoquan
-			{ 05755, new PositionInfo { X = 24.0f, Y = 32.0f } }, // Tenaga
-			{ 05764, new PositionInfo { X = 23.0f, Y = 30.0f } }, // Vanara
-			{ 05762, new PositionInfo { X = 25.0f, Y = 26.0f } }, // Water Serpent
-
-			// The Azim Steppe
-			{ 05785, new PositionInfo { X = 15.0f, Y = 19.0f } }, // Baras
-			{ 05788, new PositionInfo { X = 17.0f, Y = 26.0f } }, // Chaochu
-			{ 05777, new PositionInfo { X = 23.0f, Y = 15.0f } }, // Halgai
-			{ 05778, new PositionInfo { X = 16.0f, Y = 11.0f } }, // Khun Chuluu
-			{ 05781, new PositionInfo { X = 31.0f, Y = 17.0f } }, // Mammoth
-			{ 05783, new PositionInfo { X = 12.0f, Y = 29.0f } }, // Manzasiri
-			{ 05775, new PositionInfo { X = 28.0f, Y = 13.0f } }, // Matamata
-			{ 05782, new PositionInfo { X = 09.0f, Y = 21.0f } }, // Matanga
-			{ 05779, new PositionInfo { X = 23.0f, Y = 10.0f } }, // Muu Shuwuu
-			{ 05780, new PositionInfo { X = 34.0f, Y = 18.0f } }, // Purbol
-			{ 05776, new PositionInfo { X = 26.0f, Y = 29.0f } }, // Steppe Dhole
-			{ 05773, new PositionInfo { X = 31.0f, Y = 32.0f } }, // Steppe Dzo
-
-			// The Lochs
-			{ 05723, new PositionInfo { X = 18.0f, Y = 32.0f } }, // Abaddon
-			{ 05725, new PositionInfo { X = 26.0f, Y = 11.0f } }, // Abalathian Minotaur
-			{ 05720, new PositionInfo { X = 25.0f, Y = 18.0f } }, // Chelone
-			{ 05727, new PositionInfo { X = 29.0f, Y = 15.0f } }, // Creeping Edila
-			{ 05729, new PositionInfo { X = 05.7f, Y = 26.7f } }, // Dark Clay Beast
-			{ 05732, new PositionInfo { X = 23.0f, Y = 10.0f } }, // Guard Bhoot
-			{ 05716, new PositionInfo { X = 08.0f, Y = 17.0f } }, // Kaluk
-			{ 05724, new PositionInfo { X = 16.0f, Y = 12.0f } }, // Loch Leech
-			{ 05730, new PositionInfo { X = 17.0f, Y = 16.0f } }, // Loch Nanka
-			{ 05717, new PositionInfo { X = 20.0f, Y = 18.0f } }, // Phoebad
-			{ 05721, new PositionInfo { X = 16.0f, Y = 21.0f } }, // Soblyn
-			{ 05722, new PositionInfo { X = 22.0f, Y = 23.0f } }, // Salt Dhruva
-			{ 05728, new PositionInfo { X = 17.0f, Y = 08.0f } }, // Specter
-			{ 05726, new PositionInfo { X = 25.0f, Y = 29.0f } }, // Vepar
-			{ 05719, new PositionInfo { X = 20.0f, Y = 25.0f } }, // Yabby			
-			// Shadowbringers
-			// Lakeland
-			{ 08498, new PositionInfo { X = 19.0f, Y = 09.0f } }, // Chiliad Cama
-			{ 08502, new PositionInfo { X = 28.0f, Y = 23.2f } }, // Violet Triffid
-			{ 08503, new PositionInfo { X = 14.0f, Y = 16.5f } }, // Gnole
-			{ 08504, new PositionInfo { X = 24.4f, Y = 23.9f } }, // Wetland Warg
-			{ 08505, new PositionInfo { X = 33.2f, Y = 10.0f } }, // White Gremlin
-			{ 08507, new PositionInfo { X = 25.8f, Y = 23.3f } }, // Hoptrap
-			{ 08508, new PositionInfo { X = 28.5f, Y = 36.7f } }, // Wolverine
-			{ 08511, new PositionInfo { X = 11.3f, Y = 11.0f } }, // Smilodon
-			{ 08514, new PositionInfo { X = 34.2f, Y = 17.0f } }, // Ya-te-veo
-			{ 08515, new PositionInfo { X = 29.0f, Y = 17.6f } }, // Proterosuchus
-			{ 08786, new PositionInfo { X = 20.5f, Y = 25.3f } }, // Lake Viper
-
-			// Kholusia
-			{ 08517, new PositionInfo { X = 31.9f, Y = 18.9f } }, // Ironbeard
-			{ 08518, new PositionInfo { X = 36.4f, Y = 28.7f } }, // Hobgoblin
-			{ 08520, new PositionInfo { X = 17.0f, Y = 18.0f } }, // Defective Talos
-			{ 08522, new PositionInfo { X = 34.8f, Y = 10.5f } }, // Sulfur Byrgen
-			{ 08523, new PositionInfo { X = 35.4f, Y = 29.2f } }, // Maultasche
-			{ 08524, new PositionInfo { X = 14.3f, Y = 11.4f } }, // Huldu
-			{ 08525, new PositionInfo { X = 14.3f, Y = 27.1f } }, // Island Rail
-			{ 08527, new PositionInfo { X = 17.0f, Y = 11.0f } }, // Cliffkite
-			{ 08528, new PositionInfo { X = 27.1f, Y = 13.8f } }, // Cliffmole
-			{ 08529, new PositionInfo { X = 08.0f, Y = 18.0f } }, // Scree Gnome
-			{ 08532, new PositionInfo { X = 17.8f, Y = 26.5f } }, // Wood Eyes
-			{ 08533, new PositionInfo { X = 25.0f, Y = 23.5f } }, // Island Wolf
-			{ 08534, new PositionInfo { X = 10.1f, Y = 29.6f } }, // Kholusian Bison
-			{ 08536, new PositionInfo { X = 32.5f, Y = 26.2f } }, // Whiptail
-			{ 08538, new PositionInfo { X = 22.5f, Y = 09.6f } }, // Highland Hyssop
-			{ 08539, new PositionInfo { X = 19.9f, Y = 33.0f } }, // Tragopan
-			{ 08540, new PositionInfo { X = 13.0f, Y = 15.0f } }, // Saichania
-			{ 08541, new PositionInfo { X = 21.0f, Y = 08.7f } }, // Gulgnu
-			{ 08542, new PositionInfo { X = 21.6f, Y = 32.0f } }, // Germinant
-
-			// Amh Araeng
-			{ 08544, new PositionInfo { X = 11.4f, Y = 30.4f } }, // Masterless Talos
-			{ 08545, new PositionInfo { X = 19.1f, Y = 20.9f } }, // Evil Weapon
-			{ 08547, new PositionInfo { X = 30.4f, Y = 12.3f } }, // Gigantender
-			{ 08550, new PositionInfo { X = 29.4f, Y = 25.4f } }, // Ancient Lizard
-			{ 08556, new PositionInfo { X = 29.4f, Y = 21.7f } }, // Sand Mole
-			{ 08557, new PositionInfo { X = 12.7f, Y = 19.0f } }, // Thistle Mole
-			{ 08558, new PositionInfo { X = 30.9f, Y = 27.3f } }, // Scissorjaws
-			{ 08559, new PositionInfo { X = 21.5f, Y = 09.7f } }, // Gnome
-			{ 08561, new PositionInfo { X = 13.9f, Y = 18.2f } }, // Debitage
-			{ 08562, new PositionInfo { X = 27.1f, Y = 29.6f } }, // Ghilman
-			{ 08563, new PositionInfo { X = 25.0f, Y = 34.3f } }, // Flame Zonure
-			{ 08565, new PositionInfo { X = 15.2f, Y = 16.7f } }, // Phorusrhacos
-			{ 08566, new PositionInfo { X = 21.7f, Y = 09.8f } }, // Desert Coyote
-			{ 08567, new PositionInfo { X = 23.9f, Y = 31.8f } }, // Molamander
-
-			// Il Mheg
-			{ 08155, new PositionInfo { X = 08.4f, Y = 30.0f } }, // Flower Basket
-			{ 08569, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Echevore
-			{ 08574, new PositionInfo { X = 31.0f, Y = 14.3f } }, // Garden Porxie
-			{ 08575, new PositionInfo { X = 19.9f, Y = 16.3f } }, // Phooka
-			{ 08576, new PositionInfo { X = 11.1f, Y = 26.0f } }, // Etainmoth
-			{ 08577, new PositionInfo { X = 29.4f, Y = 12.7f } }, // Green Glider
-			{ 08578, new PositionInfo { X = 21.0f, Y = 08.8f } }, // Moss Fungus
-			{ 08581, new PositionInfo { X = 07.8f, Y = 18.7f } }, // Hawker
-			{ 08582, new PositionInfo { X = 25.0f, Y = 11.0f } }, // Rainbow Lorikeet
-			{ 08583, new PositionInfo { X = 29.5f, Y = 11.4f } }, // Tot Aevis
-			{ 08584, new PositionInfo { X = 30.4f, Y = 10.6f } }, // Rabbit's Tail
-			{ 08585, new PositionInfo { X = 19.0f, Y = 32.0f } }, // Rosebear
-			{ 08586, new PositionInfo { X = 31.6f, Y = 06.4f } }, // Garden Crocota
-			{ 08587, new PositionInfo { X = 32.0f, Y = 05.8f } }, // Werewood
-			{ 08590, new PositionInfo { X = 09.4f, Y = 15.0f } }, // Killer Bee
-
-			// The Rak'tika Greatwood
-			{ 08596, new PositionInfo { X = 08.8f, Y = 35.6f } }, // Tomatl
-			{ 08597, new PositionInfo { X = 27.3f, Y = 25.6f } }, // Forest Echo
-			{ 08598, new PositionInfo { X = 25.1f, Y = 14.2f } }, // Cracked Ronkan Doll
-			{ 08599, new PositionInfo { X = 23.0f, Y = 14.0f } }, // Cracked Ronkan Thorn
-			{ 08600, new PositionInfo { X = 16.0f, Y = 32.0f } }, // Vampire Vine
-			{ 08601, new PositionInfo { X = 23.4f, Y = 07.6f } }, // Greatwood Rail
-			{ 08603, new PositionInfo { X = 29.4f, Y = 21.7f } }, // Snapweed
-			{ 08604, new PositionInfo { X = 12.0f, Y = 34.0f } }, // Atrociraptor
-			{ 08606, new PositionInfo { X = 27.7f, Y = 23.2f } }, // Gizamaluk
-			{ 08609, new PositionInfo { X = 16.9f, Y = 33.3f } }, // Helm Beetle
-			{ 08610, new PositionInfo { X = 34.1f, Y = 16.5f } }, // Floor Mandrill
-			{ 08611, new PositionInfo { X = 15.0f, Y = 19.4f } }, // Wild Swine
-			{ 08612, new PositionInfo { X = 24.9f, Y = 30.2f } }, // Caracal
-			{ 08614, new PositionInfo { X = 25.0f, Y = 07.2f } }, // Woodbat
-			{ 08616, new PositionInfo { X = 27.9f, Y = 21.2f } }, // Tarichuk
-			{ 08789, new PositionInfo { X = 21.1f, Y = 13.2f } }, // Cracked Ronkan Vessel
-
-			// The Tempest
-			{ 08618, new PositionInfo { X = 28.6f, Y = 06.2f } }, // Clinoid
-			{ 08619, new PositionInfo { X = 28.2f, Y = 18.3f } }, // Dagon
-			{ 08621, new PositionInfo { X = 22.6f, Y = 31.7f } }, // Cubus
-			{ 08622, new PositionInfo { X = 25.1f, Y = 18.6f } }, // Sea Anemone
-			{ 08623, new PositionInfo { X = 32.1f, Y = 11.7f } }, // Amphisbaena
-			{ 08625, new PositionInfo { X = 32.5f, Y = 21.5f } }, // Morgawr
-			{ 08626, new PositionInfo { X = 36.6f, Y = 16.6f } }, // Trilobite
-			{ 08629, new PositionInfo { X = 27.7f, Y = 08.7f } }, // Sea Gelatin
-			{ 08630, new PositionInfo { X = 29.0f, Y = 21.0f } }, // Tempest Swallow
-			{ 08631, new PositionInfo { X = 35.8f, Y = 07.2f } }, // Blue Swimmer
-
-			// Endwalker
-			// Labyrinthos
-			{ 10668, new PositionInfo { X = 28.8f, Y = 08.8f } }, // Troll
-			{ 10669, new PositionInfo { X = 31.0f, Y = 25.5f } }, // Genomos
-			{ 10670, new PositionInfo { X = 15.0f, Y = 06.5f } }, // Caribou
-			{ 10672, new PositionInfo { X = 32.0f, Y = 08.8f } }, // Limascabra
-			{ 10673, new PositionInfo { X = 21.5f, Y = 13.5f } }, // Luncheon Toad
-			{ 10674, new PositionInfo { X = 17.0f, Y = 12.0f } }, // Yakow
-			{ 10677, new PositionInfo { X = 34.0f, Y = 15.0f } }, // Labyrinth Screamer
-			{ 10678, new PositionInfo { X = 24.0f, Y = 10.7f } }, // Northern Snapweed
-			{ 10679, new PositionInfo { X = 26.0f, Y = 14.5f } }, // Pephredo
-			{ 10683, new PositionInfo { X = 37.5f, Y = 19.5f } }, // Mythrilcap
-
-			// Thavnair
-			{ 10697, new PositionInfo { X = 19.0f, Y = 23.9f } }, // Pisaca
-			{ 10698, new PositionInfo { X = 13.8f, Y = 18.5f } }, // Vajralangula
-			{ 10699, new PositionInfo { X = 19.2f, Y = 32.6f } }, // Kacchapa
-			{ 10700, new PositionInfo { X = 18.4f, Y = 26.7f } }, // Hamsa
-			{ 10701, new PositionInfo { X = 29.1f, Y = 12.2f } }, // Asvattha
-			{ 10702, new PositionInfo { X = 27.1f, Y = 27.8f } }, // Guhasaya
-			{ 10703, new PositionInfo { X = 27.0f, Y = 17.4f } }, // Bhujamga
-			{ 10704, new PositionInfo { X = 17.6f, Y = 17.8f } }, // Sotormurg
-			{ 10705, new PositionInfo { X = 22.7f, Y = 30.4f } }, // Gaja
-			{ 10706, new PositionInfo { X = 19.1f, Y = 11.7f } }, // Thavnairian Jhammel
-			{ 10707, new PositionInfo { X = 25.9f, Y = 19.0f } }, // Ufiti
-			{ 10709, new PositionInfo { X = 09.2f, Y = 12.8f } }, // Chamrosh
-			{ 10711, new PositionInfo { X = 16.1f, Y = 09.2f } }, // Starmite
-			{ 10712, new PositionInfo { X = 14.3f, Y = 12.7f } }, // Manjusaka
-			{ 10713, new PositionInfo { X = 23.3f, Y = 19.9f } }, // Odqan
-			{ 10715, new PositionInfo { X = 13.4f, Y = 28.5f } }, // Akyaali Crab
-			{ 10716, new PositionInfo { X = 08.2f, Y = 16.2f } }, // Valras
-
-			// Garlemald
-			{ 10648, new PositionInfo { X = 18.8f, Y = 09.8f } }, // Automated Satellite
-			{ 10649, new PositionInfo { X = 25.5f, Y = 17.5f } }, // Automated Death Machine
-			{ 10650, new PositionInfo { X = 15.5f, Y = 19.5f } }, // Automated Cavalry
-			{ 10651, new PositionInfo { X = 21.8f, Y = 17.4f } }, // Automated Bit
-			{ 10652, new PositionInfo { X = 15.7f, Y = 09.8f } }, // Automated Roader
-			{ 10653, new PositionInfo { X = 29.5f, Y = 13.7f } }, // Automated Slasher
-			{ 10654, new PositionInfo { X = 24.3f, Y = 14.9f } }, // Automated Colossus
-			{ 10655, new PositionInfo { X = 12.9f, Y = 11.7f } }, // Automated Avenger
-			{ 10656, new PositionInfo { X = 29.6f, Y = 30.3f } }, // Almasty
-			{ 10657, new PositionInfo { X = 14.6f, Y = 26.1f } }, // Eblan Bear
-			{ 10658, new PositionInfo { X = 31.3f, Y = 17.4f } }, // Eblan Icetrap
-			{ 10659, new PositionInfo { X = 19.8f, Y = 29.1f } }, // Ovibos
-			{ 10660, new PositionInfo { X = 22.3f, Y = 24.9f } }, // Jotunn
-			{ 10661, new PositionInfo { X = 28.4f, Y = 33.0f } }, // Ceruleum Zoblyn
-			{ 10662, new PositionInfo { X = 25.4f, Y = 31.5f } }, // Ilsabardian Tursus
-			{ 10663, new PositionInfo { X = 18.7f, Y = 24.8f } }, // Canis Lupinus
-			{ 10664, new PositionInfo { X = 26.1f, Y = 26.5f } }, // Overgrown Rose
-
-			// Mare Lamentorum
-			{ 10458, new PositionInfo { X = 23.9f, Y = 20.0f } }, // Daphnia
-			{ 10459, new PositionInfo { X = 23.7f, Y = 20.3f } }, // Osculator
-			{ 10460, new PositionInfo { X = 08.6f, Y = 35.5f } }, // Sweeper
-			{ 10461, new PositionInfo { X = 27.3f, Y = 26.0f } }, // Wanderer
-			{ 10462, new PositionInfo { X = 31.1f, Y = 32.2f } }, // Weeper
-			{ 10463, new PositionInfo { X = 19.8f, Y = 22.5f } }, // Thinker
-			{ 10464, new PositionInfo { X = 26.0f, Y = 34.0f } }, // Regolith
-			{ 10465, new PositionInfo { X = 21.4f, Y = 32.2f } }, // Trimmer
-			{ 10467, new PositionInfo { X = 12.0f, Y = 36.7f } }, // Panopt
-			{ 10468, new PositionInfo { X = 11.5f, Y = 22.3f } }, // Dynamite
-			{ 10469, new PositionInfo { X = 16.7f, Y = 31.8f } }, // Armalcolite
-			{ 10470, new PositionInfo { X = 12.9f, Y = 09.6f } }, // Caretaker
-			{ 10471, new PositionInfo { X = 16.1f, Y = 24.9f } }, // Mousse
-			{ 10473, new PositionInfo { X = 31.2f, Y = 27.0f } }, // Downfall Alarum
-			{ 10474, new PositionInfo { X = 33.6f, Y = 26.2f } }, // Downfall Droid
-			{ 10475, new PositionInfo { X = 34.5f, Y = 28.0f } }, // Downfall Hunter
-			{ 10476, new PositionInfo { X = 13.0f, Y = 10.0f } }, // Supporter
-			{ 10477, new PositionInfo { X = 30.1f, Y = 11.0f } }, // Scraper
-
-			// Elpis
-			{ 10590, new PositionInfo { X = 25.7f, Y = 33.9f } }, // Ophion
-			{ 10591, new PositionInfo { X = 16.5f, Y = 29.9f } }, // Yggdreant
-			{ 10592, new PositionInfo { X = 22.6f, Y = 20.0f } }, // Okyupete
-			{ 10594, new PositionInfo { X = 12.4f, Y = 31.8f } }, // Gryps
-			{ 10595, new PositionInfo { X = 26.6f, Y = 29.7f } }, // Monoceros
-			{ 10596, new PositionInfo { X = 10.1f, Y = 14.1f } }, // Pegasos
-			{ 10597, new PositionInfo { X = 28.7f, Y = 25.6f } }, // Bird of Elpis
-			{ 10599, new PositionInfo { X = 33.4f, Y = 14.3f } }, // Hippe
-			{ 10600, new PositionInfo { X = 14.1f, Y = 09.9f } }, // Harpuia
-			{ 10601, new PositionInfo { X = 25.0f, Y = 10.0f } }, // Morbol Marquis
-			{ 10602, new PositionInfo { X = 29.2f, Y = 09.3f } }, // Akantha
-			{ 10603, new PositionInfo { X = 24.4f, Y = 14.3f } }, // Lykopersikon
-			{ 10606, new PositionInfo { X = 21.5f, Y = 06.3f } }, // Lotis
-			{ 10607, new PositionInfo { X = 10.2f, Y = 34.6f } }, // Phanopsyche
-			{ 10608, new PositionInfo { X = 12.9f, Y = 23.4f } }, // Melanion
-			{ 10609, new PositionInfo { X = 12.9f, Y = 08.7f } }, // Ophiotauros
-			{ 10610, new PositionInfo { X = 13.3f, Y = 15.7f } }, // Elpis Minotaur
-			{ 10611, new PositionInfo { X = 30.7f, Y = 17.1f } }, // Remora
-
-			// Ultima Thule
-			{ 10419, new PositionInfo { X = 30.1f, Y = 25.9f } }, // Broken Omicron
-			{ 10420, new PositionInfo { X = 19.3f, Y = 11.8f } }, // Drifting Ea
-			{ 10421, new PositionInfo { X = 34.8f, Y = 28.8f } }, // Beta
-			{ 10422, new PositionInfo { X = 32.9f, Y = 28.8f } }, // Delta
-			{ 10423, new PositionInfo { X = 36.5f, Y = 25.9f } }, // Lambda
-			{ 10424, new PositionInfo { X = 32.1f, Y = 26.6f } }, // Level Tricker
-			{ 10427, new PositionInfo { X = 10.0f, Y = 30.0f } }, // Stellar Amphiptere
-			{ 10430, new PositionInfo { X = 14.4f, Y = 28.2f } }, // Stellar Brobinyak
-			{ 10435, new PositionInfo { X = 16.3f, Y = 14.1f } }, // Other One
-		};
-
-		public enum OpenType
-		{
-			None, // Just place marker
-			ShowOpen, // Show special map with radius
-			MarkerOpen // Show normal map
+		public float Y {
+			get;
+			init;
 		}
 
-		public static unsafe void CreateMapMarker(uint territoryType, uint mapId, uint mobHuntId, string? mobHuntName, OpenType openType = OpenType.MarkerOpen)
-		{
-			var map = FFXIVClientStructs.FFXIV.Client.UI.Agent.AgentMap.Instance();
-			
-			if (map == null)
-			{
-				return;
-			}
-			
-			var pos = MapToWorldCoordinates(Database[mobHuntId].Coordinate, mapId);
-
-			map->IsFlagMarkerSet = 0;
-			map->SetFlagMapMarker(territoryType, mapId, pos.X, pos.Y, 60004);
-
-			switch (openType)
-			{
-				case OpenType.None:
-					break;
-				case OpenType.ShowOpen:
-					map->AgentInterface.Hide();
-					map->AddGatheringTempMarker(pos.X, pos.Y, 150, 60004, 4, mobHuntName);
-					map->OpenMap(mapId, territoryType, mobHuntName, MapType.GatheringLog);
-					break;
-				case OpenType.MarkerOpen:
-					map->AgentInterface.Hide();
-					map->OpenMap(mapId, territoryType);
-					break;
-				default:
-					throw new ArgumentOutOfRangeException(nameof(openType), openType, null);
-			}
-		}
-		
-		private static (int X, int Y) MapToWorldCoordinates(Vector2 pos, uint mapId)
-		{
-			var scale = Service.DataManager.GetExcelSheet<Map>()?.GetRow(mapId)?.SizeFactor ?? 100;
-			var num = scale / 100f;
-			var x = (float)(((pos.X - 1.0) * num / 41.0 * 2048.0) - 1024.0) / num * 1000f;
-			var y = (float)(((pos.Y - 1.0) * num / 41.0 * 2048.0) - 1024.0) / num * 1000f;
-			x = (int)(MathF.Round(x, 3, MidpointRounding.AwayFromZero) * 1000) * 0.001f / 1000f;
-			y = (int)(MathF.Round(y, 3, MidpointRounding.AwayFromZero) * 1000) * 0.001f / 1000f;
-			return ((int)x, (int)y);
+		public Vector2 Coordinate => new(this.X, this.Y);
+	}
+
+	// MobHuntId as key
+	public static readonly Dictionary<uint, PositionInfo> Database = new() {
+		// Heavensward
+		// Coerthas Western Highlands
+		{ 03481, new PositionInfo { X = 15.0f, Y = 12.0f } }, // Archaeornis
+		{ 03472, new PositionInfo { X = 32.0f, Y = 24.0f } }, // Bergthurs
+		{ 03471, new PositionInfo { X = 30.0f, Y = 31.0f } }, // Deepeye
+		{ 03476, new PositionInfo { X = 28.0f, Y = 12.0f } }, // Frost Grenade
+		{ 03480, new PositionInfo { X = 11.0f, Y = 17.0f } }, // Gelato
+		{ 03484, new PositionInfo { X = 10.0f, Y = 14.0f } }, // Ice Commander
+		{ 03475, new PositionInfo { X = 23.0f, Y = 16.0f } }, // Icetrap
+		{ 03487, new PositionInfo { X = 28.0f, Y = 09.0f } }, // Inland Tursus
+		{ 03483, new PositionInfo { X = 19.0f, Y = 29.0f } }, // Lone Yeti
+		{ 03485, new PositionInfo { X = 22.0f, Y = 21.0f } }, // Polar Bear
+		{ 03482, new PositionInfo { X = 16.0f, Y = 20.0f } }, // Rheum
+		{ 03473, new PositionInfo { X = 26.0f, Y = 24.0f } }, // Silver Wolf
+		{ 03490, new PositionInfo { X = 25.0f, Y = 32.0f } }, // Slate Yeti
+		{ 03478, new PositionInfo { X = 25.0f, Y = 12.0f } }, // Slush Zoblyn
+		{ 03470, new PositionInfo { X = 30.0f, Y = 32.0f } }, // Steinbock
+		{ 03474, new PositionInfo { X = 31.0f, Y = 20.0f } }, // Upland Mylodon
+		{ 03493, new PositionInfo { X = 09.0f, Y = 09.0f } }, // Vindthurs
+		{ 03479, new PositionInfo { X = 15.0f, Y = 17.0f } }, // Wooly Yak
+
+		// The Sea of Clouds
+		{ 03524, new PositionInfo { X = 21.0f, Y = 06.0f } }, // Anzu
+		{ 03498, new PositionInfo { X = 28.0f, Y = 29.0f } }, // Cloudworm
+		{ 03496, new PositionInfo { X = 27.0f, Y = 30.0f } }, // Conodont
+		{ 03505, new PositionInfo { X = 19.0f, Y = 30.0f } }, // Dhalmel
+		{ 03511, new PositionInfo { X = 17.0f, Y = 10.0f } }, // Endymion
+		{ 03494, new PositionInfo { X = 11.0f, Y = 33.0f } }, // Gaelicat
+		{ 03495, new PositionInfo { X = 16.0f, Y = 36.0f } }, // Gastornis
+		{ 03512, new PositionInfo { X = 23.0f, Y = 09.0f } }, // Groundskeeper
+		{ 03506, new PositionInfo { X = 20.0f, Y = 30.0f } }, // Korrigan
+		{ 03501, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Lan'laii Gundu
+		{ 03502, new PositionInfo { X = 36.0f, Y = 20.0f } }, // Nat'laii Gundu
+		{ 03516, new PositionInfo { X = 28.0f, Y = 10.0f } }, // Nat'laii Vundu
+		{ 03497, new PositionInfo { X = 29.0f, Y = 30.0f } }, // Obdella
+		{ 03499, new PositionInfo { X = 20.0f, Y = 34.0f } }, // Paissa
+		{ 03500, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Sanuwa
+		{ 03514, new PositionInfo { X = 30.0f, Y = 14.0f } }, // Sanuwa Vundu
+		{ 03525, new PositionInfo { X = 21.0f, Y = 07.0f } }, // Toco Toco
+		{ 03523, new PositionInfo { X = 14.0f, Y = 07.0f } }, // Tsanahale
+		{ 03503, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Vuk'laii Gundu
+		{ 03513, new PositionInfo { X = 18.0f, Y = 17.0f } }, // Vundu Totem
+		{ 03509, new PositionInfo { X = 09.0f, Y = 16.0f } }, // Window Wamoura
+		{ 03510, new PositionInfo { X = 10.0f, Y = 17.0f } }, // Window Wamouracampa
+		{ 03504, new PositionInfo { X = 20.0f, Y = 38.0f } }, // Wisent
+
+		// The Dravanian Forelands
+		{ 03565, new PositionInfo { X = 30.0f, Y = 16.0f } }, // Bandersnatch
+		{ 03566, new PositionInfo { X = 26.0f, Y = 11.0f } }, // Brown Bear
+		{ 03570, new PositionInfo { X = 28.0f, Y = 22.0f } }, // Clearwater Nanka
+		{ 03569, new PositionInfo { X = 27.0f, Y = 25.0f } }, // Clearwater Ninki Nanka
+		{ 03572, new PositionInfo { X = 28.0f, Y = 32.0f } }, // Dragonfly Watcher
+		{ 03567, new PositionInfo { X = 27.0f, Y = 22.0f } }, // Dravanian Aevis
+		{ 03576, new PositionInfo { X = 16.0f, Y = 33.0f } }, // Dravanian Wyvern
+		{ 03563, new PositionInfo { X = 36.0f, Y = 24.0f } }, // Feather Flea
+		{ 03578, new PositionInfo { X = 17.0f, Y = 26.0f } }, // Forelands Hippocerf
+		{ 03579, new PositionInfo { X = 18.0f, Y = 12.0f } }, // Gallimimus
+		{ 03571, new PositionInfo { X = 25.0f, Y = 29.0f } }, // Loaghtan
+		{ 03592, new PositionInfo { X = 27.0f, Y = 35.0f } }, // Loth Cultivator
+		{ 03590, new PositionInfo { X = 27.0f, Y = 35.0f } }, // Loth Firedrone
+		{ 03591, new PositionInfo { X = 29.0f, Y = 36.0f } }, // Loth Steeldrone
+		{ 03568, new PositionInfo { X = 28.0f, Y = 25.0f } }, // Melia
+		{ 03577, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Miacid
+		{ 03555, new PositionInfo { X = 18.0f, Y = 12.0f } }, // Syricta
+		{ 03586, new PositionInfo { X = 31.0f, Y = 08.0f } }, // Thunder Dragon
+		{ 03582, new PositionInfo { X = 13.0f, Y = 15.0f } }, // Tyrannosaur
+		{ 03581, new PositionInfo { X = 13.0f, Y = 14.0f } }, // Vinegaroon
+		{ 03564, new PositionInfo { X = 35.0f, Y = 21.0f } }, // Wild Chocobo
+
+		// The Churning Mists
+		{ 03619, new PositionInfo { X = 17.0f, Y = 27.0f } }, // Amphiptere
+		{ 03620, new PositionInfo { X = 24.0f, Y = 26.0f } }, // Archaeosaur
+		{ 03625, new PositionInfo { X = 18.0f, Y = 24.0f } }, // Bladed Vinegaroon
+		{ 03630, new PositionInfo { X = 25.0f, Y = 10.0f } }, // Blood Dragon
+		{ 03631, new PositionInfo { X = 09.0f, Y = 36.0f } }, // Cloud Aevis
+		{ 03629, new PositionInfo { X = 08.0f, Y = 19.0f } }, // Diresaur
+		{ 03623, new PositionInfo { X = 20.0f, Y = 12.0f } }, // Dragonet
+		{ 03626, new PositionInfo { X = 34.0f, Y = 21.0f } }, // Elder Syricta
+		{ 03628, new PositionInfo { X = 25.0f, Y = 30.0f } }, // Elder Wyvern
+		{ 03668, new PositionInfo { X = 10.0f, Y = 20.0f } }, // Gnarled Melia
+		{ 03614, new PositionInfo { X = 34.0f, Y = 28.0f } }, // Hropken
+		{ 03621, new PositionInfo { X = 09.0f, Y = 12.0f } }, // Limestone Golem
+		{ 03618, new PositionInfo { X = 20.0f, Y = 28.0f } }, // Lower Skylord
+		{ 03627, new PositionInfo { X = 33.0f, Y = 31.0f } }, // Mists Biast
+		{ 03622, new PositionInfo { X = 10.0f, Y = 18.0f } }, // Mists Drake
+		{ 03617, new PositionInfo { X = 23.0f, Y = 25.0f } }, // Moss Dragon
+		{ 03613, new PositionInfo { X = 28.0f, Y = 32.0f } }, // Sankchinni
+		{ 03615, new PositionInfo { X = 32.0f, Y = 15.0f } }, // Tulihand
+		{ 03624, new PositionInfo { X = 38.0f, Y = 17.7f } }, // Vouivre
+		{ 03616, new PositionInfo { X = 26.0f, Y = 20.0f } }, // Wadjet
+
+		// The Dravanian Hinterlands
+		{ 03612, new PositionInfo { X = 25.0f, Y = 37.0f } }, // Bifericeras
+		{ 03609, new PositionInfo { X = 18.0f, Y = 36.0f } }, // Cockatrice
+		{ 03603, new PositionInfo { X = 12.0f, Y = 16.0f } }, // Crawler
+		{ 03594, new PositionInfo { X = 24.0f, Y = 21.0f } }, // Damselfly
+		{ 03598, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Brandisher
+		{ 03601, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Glider
+		{ 03600, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Sharpshooter
+		{ 03599, new PositionInfo { X = 31.0f, Y = 22.0f } }, // Goblin Tinkerer
+		{ 03605, new PositionInfo { X = 10.0f, Y = 21.0f } }, // Great Morbol
+		{ 03597, new PositionInfo { X = 37.0f, Y = 24.0f } }, // Narbrooi
+		{ 03610, new PositionInfo { X = 17.0f, Y = 33.0f } }, // Okeanis
+		{ 03608, new PositionInfo { X = 12.0f, Y = 33.0f } }, // Opken
+		{ 03604, new PositionInfo { X = 11.0f, Y = 27.0f } }, // Orn Kite
+		{ 03607, new PositionInfo { X = 09.0f, Y = 34.0f } }, // Poroggo
+		{ 03595, new PositionInfo { X = 28.0f, Y = 27.0f } }, // Ratel
+		{ 03611, new PositionInfo { X = 12.0f, Y = 32.0f } }, // Sun Leech
+		{ 03593, new PositionInfo { X = 21.0f, Y = 16.0f } }, // Tarantula Hawk
+		{ 03596, new PositionInfo { X = 34.0f, Y = 19.0f } }, // Wildebeest
+
+		// Azys Lla
+		{ 03545, new PositionInfo { X = 35.0f, Y = 24.0f } }, // 6th Legion Vanguard
+		{ 03552, new PositionInfo { X = 27.0f, Y = 33.0f } }, // Adamantite Claw
+		{ 03540, new PositionInfo { X = 31.0f, Y = 06.0f } }, // Allagan Chimera
+		{ 03534, new PositionInfo { X = 15.0f, Y = 13.0f } }, // Clockwork Engineer
+		{ 03536, new PositionInfo { X = 13.0f, Y = 08.0f } }, // Clockwork Harvestman
+		{ 03535, new PositionInfo { X = 18.0f, Y = 13.0f } }, // Clockwork Paladin
+		{ 03542, new PositionInfo { X = 35.0f, Y = 09.0f } }, // Corpse Flower
+		{ 03541, new PositionInfo { X = 29.5f, Y = 12.0f } }, // Empuse
+		{ 03537, new PositionInfo { X = 13.0f, Y = 17.0f } }, // Enforcement Droid
+		{ 03539, new PositionInfo { X = 27.0f, Y = 11.0f } }, // Lamia Cybrid
+		{ 03538, new PositionInfo { X = 28.0f, Y = 13.0f } }, // Lamia Thelytoke
+		{ 03580, new PositionInfo { X = 13.0f, Y = 33.0f } }, // Lesser Hydra
+		{ 03559, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Meracydian Amphiptere
+		{ 03557, new PositionInfo { X = 08.0f, Y = 32.0f } }, // Meracydian Brobinyak
+		{ 03560, new PositionInfo { X = 08.0f, Y = 27.0f } }, // Meracydian Dragon
+		{ 03558, new PositionInfo { X = 06.0f, Y = 35.0f } }, // Meracydian Dragonet
+		{ 03554, new PositionInfo { X = 15.0f, Y = 29.0f } }, // Meracydian Falak
+		{ 03556, new PositionInfo { X = 14.0f, Y = 35.0f } }, // Meracydian Vouivre
+		{ 03533, new PositionInfo { X = 12.0f, Y = 15.0f } }, // Owlbear
+		{ 03543, new PositionInfo { X = 35.0f, Y = 08.0f } }, // Proto-naga
+		{ 03544, new PositionInfo { X = 33.0f, Y = 13.0f } }, // Reptoid
+		{ 03532, new PositionInfo { X = 09.0f, Y = 12.0f } }, // Snapper-rook
+
+		// Stormblood
+		// The Fringes
+		{ 05685, new PositionInfo { X = 10.0f, Y = 27.0f } }, // Diakka
+		{ 05674, new PositionInfo { X = 22.0f, Y = 16.0f } }, // Foper
+		{ 05697, new PositionInfo { X = 25.0f, Y = 27.0f } }, // Gazelle
+		{ 05676, new PositionInfo { X = 11.6f, Y = 12.0f } }, // Gazelle Hawk
+		{ 05679, new PositionInfo { X = 25.0f, Y = 15.0f } }, // Gelid Bhoot
+		{ 05686, new PositionInfo { X = 10.0f, Y = 27.0f } }, // Goosefish
+		{ 05671, new PositionInfo { X = 11.0f, Y = 11.0f } }, // Leshy
+		{ 05687, new PositionInfo { X = 11.0f, Y = 17.0f } }, // Mossling
+		{ 05683, new PositionInfo { X = 12.0f, Y = 17.0f } }, // Mountain Grizzly
+		{ 05691, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Brahmin
+		{ 05689, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Kshatriya
+		{ 05690, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Qalyana Shudra
+		{ 05688, new PositionInfo { X = 35.0f, Y = 25.0f } }, // Sacred Marid
+		{ 05675, new PositionInfo { X = 10.0f, Y = 12.0f } }, // Sapria
+		{ 05677, new PositionInfo { X = 22.0f, Y = 11.0f } }, // Spinner
+		{ 05693, new PositionInfo { X = 29.0f, Y = 24.0f } }, // Teleoceras
+		{ 05678, new PositionInfo { X = 28.0f, Y = 15.0f } }, // Velodyna Pugil
+		{ 05680, new PositionInfo { X = 17.0f, Y = 10.0f } }, // Velodyna Sarcosuchus
+
+		// The Peaks
+		{ 05705, new PositionInfo { X = 25.0f, Y = 11.0f } }, // Crag Claw
+		{ 05701, new PositionInfo { X = 18.7f, Y = 12.9f } }, // Bloodglider
+		{ 05702, new PositionInfo { X = 14.0f, Y = 08.0f } }, // Fluturini
+		{ 05703, new PositionInfo { X = 12.0f, Y = 08.0f } }, // Gyr Abanian Hornbill
+		{ 05713, new PositionInfo { X = 25.0f, Y = 33.0f } }, // Highland Eruca
+		{ 05712, new PositionInfo { X = 24.0f, Y = 29.0f } }, // Jhammel
+		{ 05714, new PositionInfo { X = 15.0f, Y = 27.0f } }, // Kongamato
+		{ 05707, new PositionInfo { X = 34.0f, Y = 09.0f } }, // Marble Urolith
+		{ 05715, new PositionInfo { X = 09.0f, Y = 26.0f } }, // Pantera
+		{ 05708, new PositionInfo { X = 24.0f, Y = 14.0f } }, // Scarab Beetle
+		{ 05711, new PositionInfo { X = 24.0f, Y = 24.0f } }, // True Griffin
+
+		// The Ruby Sea
+		{ 05737, new PositionInfo { X = 31.0f, Y = 35.0f } }, // Bombfish
+		{ 05736, new PositionInfo { X = 34.0f, Y = 05.0f } }, // Coralshell
+		{ 05740, new PositionInfo { X = 26.0f, Y = 30.0f } }, // Flying Shark
+		{ 05742, new PositionInfo { X = 23.0f, Y = 33.0f } }, // Gasame
+		{ 05734, new PositionInfo { X = 14.0f, Y = 10.0f } }, // Gyuki
+		{ 05751, new PositionInfo { X = 25.0f, Y = 25.0f } }, // Naked Yumemi
+		{ 05743, new PositionInfo { X = 07.0f, Y = 30.0f } }, // Red Bukan
+		{ 05745, new PositionInfo { X = 08.0f, Y = 28.0f } }, // Red Honkan
+		{ 05744, new PositionInfo { X = 09.5f, Y = 25.2f } }, // Red Hyoe
+		{ 05738, new PositionInfo { X = 33.0f, Y = 11.0f } }, // Sea Serpent
+		{ 05739, new PositionInfo { X = 26.0f, Y = 06.0f } }, // Shiranui
+		{ 05746, new PositionInfo { X = 07.0f, Y = 27.0f } }, // Striped Ray
+		{ 05733, new PositionInfo { X = 29.0f, Y = 37.0f } }, // Tatsunoko
+		{ 05735, new PositionInfo { X = 35.0f, Y = 21.0f } }, // Unkiu
+		{ 05750, new PositionInfo { X = 25.0f, Y = 25.0f } }, // Yumemi
+
+		// Yanxia
+		{ 05761, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Bi Fang
+		{ 05769, new PositionInfo { X = 28.0f, Y = 08.0f } }, // Ebisu Catfish
+		{ 05752, new PositionInfo { X = 27.0f, Y = 34.0f } }, // Lupin Bladehand
+		{ 05754, new PositionInfo { X = 24.0f, Y = 32.0f } }, // Lupin Bowhand
+		{ 05753, new PositionInfo { X = 23.0f, Y = 28.0f } }, // Lupin Spearhand
+		{ 05768, new PositionInfo { X = 19.0f, Y = 11.0f } }, // Magatsu Kiyofusa
+		{ 05763, new PositionInfo { X = 33.0f, Y = 17.0f } }, // Minobi
+		{ 05757, new PositionInfo { X = 30.0f, Y = 23.0f } }, // Rhino Beetle
+		{ 05765, new PositionInfo { X = 30.0f, Y = 34.0f } }, // Taoquan
+		{ 05755, new PositionInfo { X = 24.0f, Y = 32.0f } }, // Tenaga
+		{ 05764, new PositionInfo { X = 23.0f, Y = 30.0f } }, // Vanara
+		{ 05762, new PositionInfo { X = 25.0f, Y = 26.0f } }, // Water Serpent
+
+		// The Azim Steppe
+		{ 05785, new PositionInfo { X = 15.0f, Y = 19.0f } }, // Baras
+		{ 05788, new PositionInfo { X = 17.0f, Y = 26.0f } }, // Chaochu
+		{ 05777, new PositionInfo { X = 23.0f, Y = 15.0f } }, // Halgai
+		{ 05778, new PositionInfo { X = 16.0f, Y = 11.0f } }, // Khun Chuluu
+		{ 05781, new PositionInfo { X = 31.0f, Y = 17.0f } }, // Mammoth
+		{ 05783, new PositionInfo { X = 12.0f, Y = 29.0f } }, // Manzasiri
+		{ 05775, new PositionInfo { X = 28.0f, Y = 13.0f } }, // Matamata
+		{ 05782, new PositionInfo { X = 09.0f, Y = 21.0f } }, // Matanga
+		{ 05779, new PositionInfo { X = 23.0f, Y = 10.0f } }, // Muu Shuwuu
+		{ 05780, new PositionInfo { X = 34.0f, Y = 18.0f } }, // Purbol
+		{ 05776, new PositionInfo { X = 26.0f, Y = 29.0f } }, // Steppe Dhole
+		{ 05773, new PositionInfo { X = 31.0f, Y = 32.0f } }, // Steppe Dzo
+
+		// The Lochs
+		{ 05723, new PositionInfo { X = 18.0f, Y = 32.0f } }, // Abaddon
+		{ 05725, new PositionInfo { X = 26.0f, Y = 11.0f } }, // Abalathian Minotaur
+		{ 05720, new PositionInfo { X = 25.0f, Y = 18.0f } }, // Chelone
+		{ 05727, new PositionInfo { X = 29.0f, Y = 15.0f } }, // Creeping Edila
+		{ 05729, new PositionInfo { X = 05.7f, Y = 26.7f } }, // Dark Clay Beast
+		{ 05732, new PositionInfo { X = 23.0f, Y = 10.0f } }, // Guard Bhoot
+		{ 05716, new PositionInfo { X = 08.0f, Y = 17.0f } }, // Kaluk
+		{ 05724, new PositionInfo { X = 16.0f, Y = 12.0f } }, // Loch Leech
+		{ 05730, new PositionInfo { X = 17.0f, Y = 16.0f } }, // Loch Nanka
+		{ 05717, new PositionInfo { X = 20.0f, Y = 18.0f } }, // Phoebad
+		{ 05721, new PositionInfo { X = 16.0f, Y = 21.0f } }, // Soblyn
+		{ 05722, new PositionInfo { X = 22.0f, Y = 23.0f } }, // Salt Dhruva
+		{ 05728, new PositionInfo { X = 17.0f, Y = 08.0f } }, // Specter
+		{ 05726, new PositionInfo { X = 25.0f, Y = 29.0f } }, // Vepar
+		{ 05719, new PositionInfo { X = 20.0f, Y = 25.0f } }, // Yabby
+		// Shadowbringers
+		// Lakeland
+		{ 08498, new PositionInfo { X = 19.0f, Y = 09.0f } }, // Chiliad Cama
+		{ 08502, new PositionInfo { X = 28.0f, Y = 23.2f } }, // Violet Triffid
+		{ 08503, new PositionInfo { X = 14.0f, Y = 16.5f } }, // Gnole
+		{ 08504, new PositionInfo { X = 24.4f, Y = 23.9f } }, // Wetland Warg
+		{ 08505, new PositionInfo { X = 33.2f, Y = 10.0f } }, // White Gremlin
+		{ 08507, new PositionInfo { X = 25.8f, Y = 23.3f } }, // Hoptrap
+		{ 08508, new PositionInfo { X = 28.5f, Y = 36.7f } }, // Wolverine
+		{ 08511, new PositionInfo { X = 11.3f, Y = 11.0f } }, // Smilodon
+		{ 08514, new PositionInfo { X = 34.2f, Y = 17.0f } }, // Ya-te-veo
+		{ 08515, new PositionInfo { X = 29.0f, Y = 17.6f } }, // Proterosuchus
+		{ 08786, new PositionInfo { X = 20.5f, Y = 25.3f } }, // Lake Viper
+
+		// Kholusia
+		{ 08517, new PositionInfo { X = 31.9f, Y = 18.9f } }, // Ironbeard
+		{ 08518, new PositionInfo { X = 36.4f, Y = 28.7f } }, // Hobgoblin
+		{ 08520, new PositionInfo { X = 17.0f, Y = 18.0f } }, // Defective Talos
+		{ 08522, new PositionInfo { X = 34.8f, Y = 10.5f } }, // Sulfur Byrgen
+		{ 08523, new PositionInfo { X = 35.4f, Y = 29.2f } }, // Maultasche
+		{ 08524, new PositionInfo { X = 14.3f, Y = 11.4f } }, // Huldu
+		{ 08525, new PositionInfo { X = 14.3f, Y = 27.1f } }, // Island Rail
+		{ 08527, new PositionInfo { X = 17.0f, Y = 11.0f } }, // Cliffkite
+		{ 08528, new PositionInfo { X = 27.1f, Y = 13.8f } }, // Cliffmole
+		{ 08529, new PositionInfo { X = 08.0f, Y = 18.0f } }, // Scree Gnome
+		{ 08532, new PositionInfo { X = 17.8f, Y = 26.5f } }, // Wood Eyes
+		{ 08533, new PositionInfo { X = 25.0f, Y = 23.5f } }, // Island Wolf
+		{ 08534, new PositionInfo { X = 10.1f, Y = 29.6f } }, // Kholusian Bison
+		{ 08536, new PositionInfo { X = 32.5f, Y = 26.2f } }, // Whiptail
+		{ 08538, new PositionInfo { X = 22.5f, Y = 09.6f } }, // Highland Hyssop
+		{ 08539, new PositionInfo { X = 19.9f, Y = 33.0f } }, // Tragopan
+		{ 08540, new PositionInfo { X = 13.0f, Y = 15.0f } }, // Saichania
+		{ 08541, new PositionInfo { X = 21.0f, Y = 08.7f } }, // Gulgnu
+		{ 08542, new PositionInfo { X = 21.6f, Y = 32.0f } }, // Germinant
+
+		// Amh Araeng
+		{ 08544, new PositionInfo { X = 11.4f, Y = 30.4f } }, // Masterless Talos
+		{ 08545, new PositionInfo { X = 19.1f, Y = 20.9f } }, // Evil Weapon
+		{ 08547, new PositionInfo { X = 30.4f, Y = 12.3f } }, // Gigantender
+		{ 08550, new PositionInfo { X = 29.4f, Y = 25.4f } }, // Ancient Lizard
+		{ 08556, new PositionInfo { X = 29.4f, Y = 21.7f } }, // Sand Mole
+		{ 08557, new PositionInfo { X = 12.7f, Y = 19.0f } }, // Thistle Mole
+		{ 08558, new PositionInfo { X = 30.9f, Y = 27.3f } }, // Scissorjaws
+		{ 08559, new PositionInfo { X = 21.5f, Y = 09.7f } }, // Gnome
+		{ 08561, new PositionInfo { X = 13.9f, Y = 18.2f } }, // Debitage
+		{ 08562, new PositionInfo { X = 27.1f, Y = 29.6f } }, // Ghilman
+		{ 08563, new PositionInfo { X = 25.0f, Y = 34.3f } }, // Flame Zonure
+		{ 08565, new PositionInfo { X = 15.2f, Y = 16.7f } }, // Phorusrhacos
+		{ 08566, new PositionInfo { X = 21.7f, Y = 09.8f } }, // Desert Coyote
+		{ 08567, new PositionInfo { X = 23.9f, Y = 31.8f } }, // Molamander
+
+		// Il Mheg
+		{ 08155, new PositionInfo { X = 08.4f, Y = 30.0f } }, // Flower Basket
+		{ 08569, new PositionInfo { X = 18.0f, Y = 31.0f } }, // Echevore
+		{ 08574, new PositionInfo { X = 31.0f, Y = 14.3f } }, // Garden Porxie
+		{ 08575, new PositionInfo { X = 19.9f, Y = 16.3f } }, // Phooka
+		{ 08576, new PositionInfo { X = 11.1f, Y = 26.0f } }, // Etainmoth
+		{ 08577, new PositionInfo { X = 29.4f, Y = 12.7f } }, // Green Glider
+		{ 08578, new PositionInfo { X = 21.0f, Y = 08.8f } }, // Moss Fungus
+		{ 08581, new PositionInfo { X = 07.8f, Y = 18.7f } }, // Hawker
+		{ 08582, new PositionInfo { X = 25.0f, Y = 11.0f } }, // Rainbow Lorikeet
+		{ 08583, new PositionInfo { X = 29.5f, Y = 11.4f } }, // Tot Aevis
+		{ 08584, new PositionInfo { X = 30.4f, Y = 10.6f } }, // Rabbit's Tail
+		{ 08585, new PositionInfo { X = 19.0f, Y = 32.0f } }, // Rosebear
+		{ 08586, new PositionInfo { X = 31.6f, Y = 06.4f } }, // Garden Crocota
+		{ 08587, new PositionInfo { X = 32.0f, Y = 05.8f } }, // Werewood
+		{ 08590, new PositionInfo { X = 09.4f, Y = 15.0f } }, // Killer Bee
+
+		// The Rak'tika Greatwood
+		{ 08596, new PositionInfo { X = 08.8f, Y = 35.6f } }, // Tomatl
+		{ 08597, new PositionInfo { X = 27.3f, Y = 25.6f } }, // Forest Echo
+		{ 08598, new PositionInfo { X = 25.1f, Y = 14.2f } }, // Cracked Ronkan Doll
+		{ 08599, new PositionInfo { X = 23.0f, Y = 14.0f } }, // Cracked Ronkan Thorn
+		{ 08600, new PositionInfo { X = 16.0f, Y = 32.0f } }, // Vampire Vine
+		{ 08601, new PositionInfo { X = 23.4f, Y = 07.6f } }, // Greatwood Rail
+		{ 08603, new PositionInfo { X = 29.4f, Y = 21.7f } }, // Snapweed
+		{ 08604, new PositionInfo { X = 12.0f, Y = 34.0f } }, // Atrociraptor
+		{ 08606, new PositionInfo { X = 27.7f, Y = 23.2f } }, // Gizamaluk
+		{ 08609, new PositionInfo { X = 16.9f, Y = 33.3f } }, // Helm Beetle
+		{ 08610, new PositionInfo { X = 34.1f, Y = 16.5f } }, // Floor Mandrill
+		{ 08611, new PositionInfo { X = 15.0f, Y = 19.4f } }, // Wild Swine
+		{ 08612, new PositionInfo { X = 24.9f, Y = 30.2f } }, // Caracal
+		{ 08614, new PositionInfo { X = 25.0f, Y = 07.2f } }, // Woodbat
+		{ 08616, new PositionInfo { X = 27.9f, Y = 21.2f } }, // Tarichuk
+		{ 08789, new PositionInfo { X = 21.1f, Y = 13.2f } }, // Cracked Ronkan Vessel
+
+		// The Tempest
+		{ 08618, new PositionInfo { X = 28.6f, Y = 06.2f } }, // Clinoid
+		{ 08619, new PositionInfo { X = 28.2f, Y = 18.3f } }, // Dagon
+		{ 08621, new PositionInfo { X = 22.6f, Y = 31.7f } }, // Cubus
+		{ 08622, new PositionInfo { X = 25.1f, Y = 18.6f } }, // Sea Anemone
+		{ 08623, new PositionInfo { X = 32.1f, Y = 11.7f } }, // Amphisbaena
+		{ 08625, new PositionInfo { X = 32.5f, Y = 21.5f } }, // Morgawr
+		{ 08626, new PositionInfo { X = 36.6f, Y = 16.6f } }, // Trilobite
+		{ 08629, new PositionInfo { X = 27.7f, Y = 08.7f } }, // Sea Gelatin
+		{ 08630, new PositionInfo { X = 29.0f, Y = 21.0f } }, // Tempest Swallow
+		{ 08631, new PositionInfo { X = 35.8f, Y = 07.2f } }, // Blue Swimmer
+
+		// Endwalker
+		// Labyrinthos
+		{ 10668, new PositionInfo { X = 28.8f, Y = 08.8f } }, // Troll
+		{ 10669, new PositionInfo { X = 31.0f, Y = 25.5f } }, // Genomos
+		{ 10670, new PositionInfo { X = 15.0f, Y = 06.5f } }, // Caribou
+		{ 10672, new PositionInfo { X = 32.0f, Y = 08.8f } }, // Limascabra
+		{ 10673, new PositionInfo { X = 21.5f, Y = 13.5f } }, // Luncheon Toad
+		{ 10674, new PositionInfo { X = 17.0f, Y = 12.0f } }, // Yakow
+		{ 10677, new PositionInfo { X = 34.0f, Y = 15.0f } }, // Labyrinth Screamer
+		{ 10678, new PositionInfo { X = 24.0f, Y = 10.7f } }, // Northern Snapweed
+		{ 10679, new PositionInfo { X = 26.0f, Y = 14.5f } }, // Pephredo
+		{ 10683, new PositionInfo { X = 37.5f, Y = 19.5f } }, // Mythrilcap
+
+		// Thavnair
+		{ 10697, new PositionInfo { X = 19.0f, Y = 23.9f } }, // Pisaca
+		{ 10698, new PositionInfo { X = 13.8f, Y = 18.5f } }, // Vajralangula
+		{ 10699, new PositionInfo { X = 19.2f, Y = 32.6f } }, // Kacchapa
+		{ 10700, new PositionInfo { X = 18.4f, Y = 26.7f } }, // Hamsa
+		{ 10701, new PositionInfo { X = 29.1f, Y = 12.2f } }, // Asvattha
+		{ 10702, new PositionInfo { X = 27.1f, Y = 27.8f } }, // Guhasaya
+		{ 10703, new PositionInfo { X = 27.0f, Y = 17.4f } }, // Bhujamga
+		{ 10704, new PositionInfo { X = 17.6f, Y = 17.8f } }, // Sotormurg
+		{ 10705, new PositionInfo { X = 22.7f, Y = 30.4f } }, // Gaja
+		{ 10706, new PositionInfo { X = 19.1f, Y = 11.7f } }, // Thavnairian Jhammel
+		{ 10707, new PositionInfo { X = 25.9f, Y = 19.0f } }, // Ufiti
+		{ 10709, new PositionInfo { X = 09.2f, Y = 12.8f } }, // Chamrosh
+		{ 10711, new PositionInfo { X = 16.1f, Y = 09.2f } }, // Starmite
+		{ 10712, new PositionInfo { X = 14.3f, Y = 12.7f } }, // Manjusaka
+		{ 10713, new PositionInfo { X = 23.3f, Y = 19.9f } }, // Odqan
+		{ 10715, new PositionInfo { X = 13.4f, Y = 28.5f } }, // Akyaali Crab
+		{ 10716, new PositionInfo { X = 08.2f, Y = 16.2f } }, // Valras
+
+		// Garlemald
+		{ 10648, new PositionInfo { X = 18.8f, Y = 09.8f } }, // Automated Satellite
+		{ 10649, new PositionInfo { X = 25.5f, Y = 17.5f } }, // Automated Death Machine
+		{ 10650, new PositionInfo { X = 15.5f, Y = 19.5f } }, // Automated Cavalry
+		{ 10651, new PositionInfo { X = 21.8f, Y = 17.4f } }, // Automated Bit
+		{ 10652, new PositionInfo { X = 15.7f, Y = 09.8f } }, // Automated Roader
+		{ 10653, new PositionInfo { X = 29.5f, Y = 13.7f } }, // Automated Slasher
+		{ 10654, new PositionInfo { X = 24.3f, Y = 14.9f } }, // Automated Colossus
+		{ 10655, new PositionInfo { X = 12.9f, Y = 11.7f } }, // Automated Avenger
+		{ 10656, new PositionInfo { X = 29.6f, Y = 30.3f } }, // Almasty
+		{ 10657, new PositionInfo { X = 14.6f, Y = 26.1f } }, // Eblan Bear
+		{ 10658, new PositionInfo { X = 31.3f, Y = 17.4f } }, // Eblan Icetrap
+		{ 10659, new PositionInfo { X = 19.8f, Y = 29.1f } }, // Ovibos
+		{ 10660, new PositionInfo { X = 22.3f, Y = 24.9f } }, // Jotunn
+		{ 10661, new PositionInfo { X = 28.4f, Y = 33.0f } }, // Ceruleum Zoblyn
+		{ 10662, new PositionInfo { X = 25.4f, Y = 31.5f } }, // Ilsabardian Tursus
+		{ 10663, new PositionInfo { X = 18.7f, Y = 24.8f } }, // Canis Lupinus
+		{ 10664, new PositionInfo { X = 26.1f, Y = 26.5f } }, // Overgrown Rose
+
+		// Mare Lamentorum
+		{ 10458, new PositionInfo { X = 23.9f, Y = 20.0f } }, // Daphnia
+		{ 10459, new PositionInfo { X = 23.7f, Y = 20.3f } }, // Osculator
+		{ 10460, new PositionInfo { X = 08.6f, Y = 35.5f } }, // Sweeper
+		{ 10461, new PositionInfo { X = 27.3f, Y = 26.0f } }, // Wanderer
+		{ 10462, new PositionInfo { X = 31.1f, Y = 32.2f } }, // Weeper
+		{ 10463, new PositionInfo { X = 19.8f, Y = 22.5f } }, // Thinker
+		{ 10464, new PositionInfo { X = 26.0f, Y = 34.0f } }, // Regolith
+		{ 10465, new PositionInfo { X = 21.4f, Y = 32.2f } }, // Trimmer
+		{ 10467, new PositionInfo { X = 12.0f, Y = 36.7f } }, // Panopt
+		{ 10468, new PositionInfo { X = 11.5f, Y = 22.3f } }, // Dynamite
+		{ 10469, new PositionInfo { X = 16.7f, Y = 31.8f } }, // Armalcolite
+		{ 10470, new PositionInfo { X = 12.9f, Y = 09.6f } }, // Caretaker
+		{ 10471, new PositionInfo { X = 16.1f, Y = 24.9f } }, // Mousse
+		{ 10473, new PositionInfo { X = 31.2f, Y = 27.0f } }, // Downfall Alarum
+		{ 10474, new PositionInfo { X = 33.6f, Y = 26.2f } }, // Downfall Droid
+		{ 10475, new PositionInfo { X = 34.5f, Y = 28.0f } }, // Downfall Hunter
+		{ 10476, new PositionInfo { X = 13.0f, Y = 10.0f } }, // Supporter
+		{ 10477, new PositionInfo { X = 30.1f, Y = 11.0f } }, // Scraper
+
+		// Elpis
+		{ 10590, new PositionInfo { X = 25.7f, Y = 33.9f } }, // Ophion
+		{ 10591, new PositionInfo { X = 16.5f, Y = 29.9f } }, // Yggdreant
+		{ 10592, new PositionInfo { X = 22.6f, Y = 20.0f } }, // Okyupete
+		{ 10594, new PositionInfo { X = 12.4f, Y = 31.8f } }, // Gryps
+		{ 10595, new PositionInfo { X = 26.6f, Y = 29.7f } }, // Monoceros
+		{ 10596, new PositionInfo { X = 10.1f, Y = 14.1f } }, // Pegasos
+		{ 10597, new PositionInfo { X = 28.7f, Y = 25.6f } }, // Bird of Elpis
+		{ 10599, new PositionInfo { X = 33.4f, Y = 14.3f } }, // Hippe
+		{ 10600, new PositionInfo { X = 14.1f, Y = 09.9f } }, // Harpuia
+		{ 10601, new PositionInfo { X = 25.0f, Y = 10.0f } }, // Morbol Marquis
+		{ 10602, new PositionInfo { X = 29.2f, Y = 09.3f } }, // Akantha
+		{ 10603, new PositionInfo { X = 24.4f, Y = 14.3f } }, // Lykopersikon
+		{ 10606, new PositionInfo { X = 21.5f, Y = 06.3f } }, // Lotis
+		{ 10607, new PositionInfo { X = 10.2f, Y = 34.6f } }, // Phanopsyche
+		{ 10608, new PositionInfo { X = 12.9f, Y = 23.4f } }, // Melanion
+		{ 10609, new PositionInfo { X = 12.9f, Y = 08.7f } }, // Ophiotauros
+		{ 10610, new PositionInfo { X = 13.3f, Y = 15.7f } }, // Elpis Minotaur
+		{ 10611, new PositionInfo { X = 30.7f, Y = 17.1f } }, // Remora
+
+		// Ultima Thule
+		{ 10419, new PositionInfo { X = 30.1f, Y = 25.9f } }, // Broken Omicron
+		{ 10420, new PositionInfo { X = 19.3f, Y = 11.8f } }, // Drifting Ea
+		{ 10421, new PositionInfo { X = 34.8f, Y = 28.8f } }, // Beta
+		{ 10422, new PositionInfo { X = 32.9f, Y = 28.8f } }, // Delta
+		{ 10423, new PositionInfo { X = 36.5f, Y = 25.9f } }, // Lambda
+		{ 10424, new PositionInfo { X = 32.1f, Y = 26.6f } }, // Level Tricker
+		{ 10427, new PositionInfo { X = 10.0f, Y = 30.0f } }, // Stellar Amphiptere
+		{ 10430, new PositionInfo { X = 14.4f, Y = 28.2f } }, // Stellar Brobinyak
+		{ 10435, new PositionInfo { X = 16.3f, Y = 14.1f } }, // Other One
+	};
+
+	public enum OpenType {
+		None, // Just place marker
+		ShowOpen, // Show special map with radius
+		MarkerOpen // Show normal map
+	}
+
+	public static unsafe void CreateMapMarker(uint territoryType, uint mapId, uint mobHuntId, string? mobHuntName,
+		OpenType openType = OpenType.MarkerOpen) {
+		AgentMap* map = AgentMap.Instance();
+
+		if (map == null) {
+			return;
 		}
 
-		private static Vector2 ConvertPixelPositionToMapCoordinate(int x, int y, float scale)
-		{
-			var num = scale / 100f;
-			return new Vector2(
-				ConvertRawPositionToMapCoordinate((int)((x - 1024) * num * 1000f), scale),
-				ConvertRawPositionToMapCoordinate((int)((y - 1024) * num * 1000f), scale));
+		(int X, int Y) pos = MapToWorldCoordinates(Database[mobHuntId].Coordinate, mapId);
+
+		map->IsFlagMarkerSet = 0;
+		map->SetFlagMapMarker(territoryType, mapId, pos.X, pos.Y, 60004);
+
+		switch (openType) {
+			case OpenType.None:
+				break;
+			case OpenType.ShowOpen:
+				map->AgentInterface.Hide();
+				map->AddGatheringTempMarker(pos.X, pos.Y, 150, 60004, 4, mobHuntName);
+				map->OpenMap(mapId, territoryType, mobHuntName, MapType.GatheringLog);
+				break;
+			case OpenType.MarkerOpen:
+				map->AgentInterface.Hide();
+				map->OpenMap(mapId, territoryType);
+				break;
+			default:
+				throw new ArgumentOutOfRangeException(nameof(openType), openType, null);
 		}
+	}
+
+	private static (int X, int Y) MapToWorldCoordinates(Vector2 pos, uint mapId) {
+		ushort scale = Service.DataManager.GetExcelSheet<Map>()?.GetRow(mapId)?.SizeFactor ?? 100;
+		float num = scale / 100f;
+		float x = (float)(((pos.X - 1.0) * num / 41.0 * 2048.0) - 1024.0) / num * 1000f;
+		float y = (float)(((pos.Y - 1.0) * num / 41.0 * 2048.0) - 1024.0) / num * 1000f;
+		x = (int)(MathF.Round(x, 3, MidpointRounding.AwayFromZero) * 1000) * 0.001f / 1000f;
+		y = (int)(MathF.Round(y, 3, MidpointRounding.AwayFromZero) * 1000) * 0.001f / 1000f;
+		return ((int)x, (int)y);
+	}
+
+	private static Vector2 ConvertPixelPositionToMapCoordinate(int x, int y, float scale) {
+		float num = scale / 100f;
+		return new Vector2(
+			ConvertRawPositionToMapCoordinate((int)((x - 1024) * num * 1000f), scale),
+			ConvertRawPositionToMapCoordinate((int)((y - 1024) * num * 1000f), scale));
+	}
 
-		private static float ConvertRawPositionToMapCoordinate(int pos, float scale)
-		{
-			var num1 = scale / 100f;
-			var num2 = (float)(pos * (double)num1 / 1000.0f);
-			return (40.96f / num1 * ((num2 + 1024.0f) / 2048.0f)) + 1.0f;
+	private static float ConvertRawPositionToMapCoordinate(int pos, float scale) {
+		float num1 = scale / 100f;
+		float num2 = (float)(pos * (double)num1 / 1000.0f);
+		return (40.96f / num1 * ((num2 + 1024.0f) / 2048.0f)) + 1.0f;
+	}
+
+	public static void TeleportToNearestAetheryte(uint territoryType, uint mapId, uint mobHuntId) {
+		Map? mapRow = Service.DataManager.Excel.GetSheet<Map>()?.GetRow(mapId);
+
+		if (mapRow == null) {
+			return;
 		}
 
-		public static void TeleportToNearestAetheryte(uint territoryType, uint mapId, uint mobHuntId)
-		{
-			var mapRow = Service.DataManager.Excel.GetSheet<Map>()?.GetRow(mapId);
-
-			if (mapRow == null)
-			{
-				return;
-			}
-
-			var nearestAetheryteId = Service.DataManager.Excel.GetSheet<MapMarker>()
-				?.Where(x => x.DataType == 3 && x.RowId == mapRow.MapMarkerRange)
-				.Select(
-					x => new
-					{
-						distance = Vector2.DistanceSquared(
-							Database[mobHuntId].Coordinate,
-							ConvertPixelPositionToMapCoordinate(x.X, x.Y, mapRow.SizeFactor)),
-						rowId = x.DataKey
-					})
-				.OrderBy(x => x.distance)
-				.FirstOrDefault()?.rowId;
-
-			var nearestAetheryte =
-				territoryType == 399 // Support the unique case of aetheryte not being in the same map
-					? mapRow.TerritoryType?.Value?.Aetheryte.Value
-					: Service.DataManager.Excel.GetSheet<Aetheryte>()?.FirstOrDefault(
-						x =>
-							x.IsAetheryte && x.Territory.Row == territoryType && x.RowId == nearestAetheryteId);
-
-			if (nearestAetheryte == null)
-			{
-				return;
-			}
-
-			Plugin.TeleportConsumer?.Teleport(nearestAetheryte.RowId);
+		ushort? nearestAetheryteId = Service.DataManager.Excel.GetSheet<MapMarker>()
+			?.Where(x => x.DataType == 3 && x.RowId == mapRow.MapMarkerRange)
+			.Select(
+				x => new {
+					distance = Vector2.DistanceSquared(
+						Database[mobHuntId].Coordinate,
+						ConvertPixelPositionToMapCoordinate(x.X, x.Y, mapRow.SizeFactor)),
+					rowId = x.DataKey
+				})
+			.OrderBy(x => x.distance)
+			.FirstOrDefault()?.rowId;
+
+		Aetheryte? nearestAetheryte =
+			territoryType == 399 // Support the unique case of aetheryte not being in the same map
+				? mapRow.TerritoryType?.Value?.Aetheryte.Value
+				: Service.DataManager.Excel.GetSheet<Aetheryte>()?.FirstOrDefault(
+					x =>
+						x.IsAetheryte && x.Territory.Row == territoryType && x.RowId == nearestAetheryteId);
+
+		if (nearestAetheryte == null) {
+			return;
 		}
+
+		Plugin.TeleportConsumer?.Teleport(nearestAetheryte.RowId);
 	}
-}
+}

+ 17 - 21
HuntBuddy/MobHuntEntry.cs

@@ -1,35 +1,31 @@
 using System;
+
 using Dalamud.Interface.Internal;
 
-namespace HuntBuddy
-{
-	public class MobHuntEntry : IDisposable
-	{
-		public string? Name { get; init; }
+namespace HuntBuddy;
+
+public class MobHuntEntry: IDisposable {
+	public string? Name { get; init; }
 
-		public string? TerritoryName { get; init; }
+	public string? TerritoryName { get; init; }
 
-		public string? ExpansionName { get; init; }
+	public string? ExpansionName { get; init; }
 
-		public uint ExpansionId { get; init; }
+	public uint ExpansionId { get; init; }
 
-		public uint MapId { get; init; }
+	public uint MapId { get; init; }
 
-		public uint TerritoryType { get; init; }
+	public uint TerritoryType { get; init; }
 
-		public uint MobHuntId { get; init; }
+	public uint MobHuntId { get; init; }
 
-		public bool IsEliteMark { get; init; }
+	public bool IsEliteMark { get; init; }
 
-		public uint CurrentKillsOffset { get; init; }
+	public uint CurrentKillsOffset { get; init; }
 
-		public uint NeededKills { get; set; }
+	public uint NeededKills { get; set; }
 
-		public IDalamudTextureWrap Icon { get; init; } = null!;
+	public IDalamudTextureWrap Icon { get; init; } = null!;
 
-		public void Dispose()
-		{
-			this.Icon.Dispose();
-		}
-	}
-}
+	public void Dispose() => this.Icon.Dispose();
+}

+ 278 - 275
HuntBuddy/Plugin.cs

@@ -5,334 +5,337 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Threading.Tasks;
+
 using Dalamud.Interface.Internal;
 using Dalamud.Interface.Windowing;
 using Dalamud.Plugin;
 using Dalamud.Plugin.Services;
 using Dalamud.Utility;
+
 using Lumina.Excel.GeneratedSheets;
+
 using HuntBuddy.Attributes;
 using HuntBuddy.Ipc;
 using HuntBuddy.Structs;
 using HuntBuddy.Windows;
+
 using ImGuiNET;
+
+using Lumina.Data.Files;
+using Lumina.Excel;
 using Lumina.Extensions;
+using Lumina.Text;
 
-namespace HuntBuddy
-{
-	public class Plugin : IDalamudPlugin
-	{
-		public string Name => "Hunt Buddy";
-
-		private readonly PluginCommandManager<Plugin> commandManager;
-		private ObtainedBillEnum lastState;
-		// Dictionary<string ExpansionName, Dictionary<KeyValuePair<uint MobTerritoryType, string MobTerritoryName>, List<MobHuntEntry MobsInZone>>>
-		public readonly Dictionary<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>> MobHuntEntries;
-		public readonly ConcurrentBag<MobHuntEntry> CurrentAreaMobHuntEntries;
-		public bool MobHuntEntriesReady = true;
-		public readonly unsafe MobHuntStruct* MobHuntStruct;
-		public readonly Configuration Configuration;
-		public static TeleportConsumer? TeleportConsumer;
-		
-		private WindowSystem WindowSystem { get; }
-		
-		private MainWindow MainWindow { get; }
-		private ConfigurationWindow ConfigurationWindow { get; }
-
-		public static Plugin Instance { get; internal set; } = null!;
-
-		public Plugin(DalamudPluginInterface pluginInterface)
-		{
-			Instance = this;
-
-			pluginInterface.Create<Service>();
-
-			this.commandManager = new PluginCommandManager<Plugin>(this, Service.Commands);
-			this.MobHuntEntries = new Dictionary<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>>();
-			this.CurrentAreaMobHuntEntries = new ConcurrentBag<MobHuntEntry>();
-			this.Configuration = (Configuration)(Service.PluginInterface.GetPluginConfig() ?? new Configuration());
-			this.Configuration.IconBackgroundColourU32 =
-				ImGui.ColorConvertFloat4ToU32(this.Configuration.IconBackgroundColour);
-
-			unsafe
-			{
-				this.MobHuntStruct =
-					(MobHuntStruct*)Service.SigScanner.GetStaticAddressFromSig(
-						"48 8D 0D ?? ?? ?? ?? 8B D8 0F B6 52");
-			}
-			
-			this.MainWindow = new MainWindow();
-			this.ConfigurationWindow = new ConfigurationWindow();
-			
-			this.WindowSystem = new WindowSystem("HuntBuddy");
-			this.WindowSystem.AddWindow(this.MainWindow);
-			this.WindowSystem.AddWindow(new LocalHuntsWindow());
-			this.WindowSystem.AddWindow(this.ConfigurationWindow);
-
-			Plugin.TeleportConsumer = new TeleportConsumer();
-			Service.ClientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
-			Service.PluginInterface.UiBuilder.Draw += this.WindowSystem.Draw;
-			Service.PluginInterface.UiBuilder.OpenConfigUi += this.OpenConfigUi;
-			Service.Framework.Update += this.FrameworkOnUpdate;
-		}
+namespace HuntBuddy;
 
-		private unsafe void FrameworkOnUpdate(IFramework framework)
-		{
-			if (this.lastState == this.MobHuntStruct->ObtainedBillEnumFlags)
-			{
-				return;
-			}
+public class Plugin: IDalamudPlugin {
+	public string Name => "Hunt Buddy";
 
-			this.lastState = this.MobHuntStruct->ObtainedBillEnumFlags;
-			this.PluginCommand(string.Empty, "reload");
-		}
+	private readonly PluginCommandManager<Plugin> commandManager;
 
-		private void ClientStateOnTerritoryChanged(ushort e)
-		{
-			this.CurrentAreaMobHuntEntries.Clear();
+	private ObtainedBillEnum lastState;
 
-			foreach (var mobHuntEntry in this.MobHuntEntries.SelectMany(
-				         expansionEntry => expansionEntry.Value
-					         .Where(entry => entry.Key.Key == Service.ClientState.TerritoryType)
-					         .SelectMany(entry => entry.Value)))
-			{
-				this.CurrentAreaMobHuntEntries.Add(mobHuntEntry);
-			}
+	// Dictionary<string ExpansionName, Dictionary<KeyValuePair<uint MobTerritoryType, string MobTerritoryName>, List<MobHuntEntry MobsInZone>>>
+	public readonly Dictionary<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>> MobHuntEntries;
+	public readonly ConcurrentBag<MobHuntEntry> CurrentAreaMobHuntEntries;
+	public bool MobHuntEntriesReady = true;
+	public readonly unsafe MobHuntStruct* MobHuntStruct;
+	public readonly Configuration Configuration;
+	public static TeleportConsumer? TeleportConsumer;
+
+	private WindowSystem WindowSystem {
+		get;
+	}
+
+	private MainWindow MainWindow {
+		get;
+	}
+
+	private ConfigurationWindow ConfigurationWindow {
+		get;
+	}
+
+	public static Plugin Instance {
+		get;
+		internal set;
+	} = null!;
+
+	public Plugin(DalamudPluginInterface pluginInterface) {
+		Instance = this;
+
+		pluginInterface.Create<Service>();
+
+		this.commandManager = new PluginCommandManager<Plugin>(this, Service.Commands);
+		this.MobHuntEntries = new Dictionary<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>>();
+		this.CurrentAreaMobHuntEntries = new ConcurrentBag<MobHuntEntry>();
+		this.Configuration = (Configuration)(Service.PluginInterface.GetPluginConfig() ?? new Configuration());
+		this.Configuration.IconBackgroundColourU32 =
+			ImGui.ColorConvertFloat4ToU32(this.Configuration.IconBackgroundColour);
+
+		unsafe {
+			this.MobHuntStruct =
+				(MobHuntStruct*)Service.SigScanner.GetStaticAddressFromSig(
+					"48 8D 0D ?? ?? ?? ?? 8B D8 0F B6 52");
 		}
 
-		private void DrawInterface()
-		{
-			this.MainWindow.Toggle();
+		this.MainWindow = new MainWindow();
+		this.ConfigurationWindow = new ConfigurationWindow();
+
+		this.WindowSystem = new WindowSystem("HuntBuddy");
+		this.WindowSystem.AddWindow(this.MainWindow);
+		this.WindowSystem.AddWindow(new LocalHuntsWindow());
+		this.WindowSystem.AddWindow(this.ConfigurationWindow);
+
+		Plugin.TeleportConsumer = new TeleportConsumer();
+		Service.ClientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
+		Service.PluginInterface.UiBuilder.Draw += this.WindowSystem.Draw;
+		Service.PluginInterface.UiBuilder.OpenConfigUi += this.OpenConfigUi;
+		Service.Framework.Update += this.FrameworkOnUpdate;
+	}
+
+	private unsafe void FrameworkOnUpdate(IFramework framework) {
+		if (this.lastState == this.MobHuntStruct->ObtainedBillEnumFlags) {
+			return;
 		}
 
-		public void OpenConfigUi()
-		{
-			this.ConfigurationWindow.Toggle();
+		this.lastState = this.MobHuntStruct->ObtainedBillEnumFlags;
+		this.PluginCommand(string.Empty, "reload");
+	}
+
+	private void ClientStateOnTerritoryChanged(ushort e) {
+		this.CurrentAreaMobHuntEntries.Clear();
+
+		foreach (MobHuntEntry mobHuntEntry in this.MobHuntEntries.SelectMany(
+			         expansionEntry => expansionEntry.Value
+				         .Where(entry => entry.Key.Key == Service.ClientState.TerritoryType)
+				         .SelectMany(entry => entry.Value))) {
+			this.CurrentAreaMobHuntEntries.Add(mobHuntEntry);
 		}
+	}
 
-		private void Dispose(bool disposing)
-		{
-			if (!disposing)
-			{
-				return;
-			}
+	private void DrawInterface() => this.MainWindow.Toggle();
 
-			this.MobHuntEntriesReady = false;
-			Service.ClientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
-			Service.Framework.Update -= this.FrameworkOnUpdate;
-			Service.PluginInterface.UiBuilder.Draw -= this.WindowSystem.Draw;
-			Service.PluginInterface.UiBuilder.OpenConfigUi -= this.OpenConfigUi;
-			
-			this.WindowSystem.RemoveAllWindows();
+	public void OpenConfigUi() => this.ConfigurationWindow.Toggle();
 
-			this.commandManager.Dispose();
+	private void Dispose(bool disposing) {
+		if (!disposing) {
+			return;
 		}
 
-		[Command("/phb")]
-		[HelpMessage("Toggles UI\nArguments:\nreload - Reloads data\nlocal - Toggles the local hunt marks window\nnext - Flags the next hunt target to find\nlist - list all hunt targets by expansion")]
-		public unsafe void PluginCommand(string command, string args)
-		{
-			try
-			{
-				switch (args.Trim().ToLower()) {
-					case "reload":
-						this.MobHuntEntriesReady = false;
-						Task.Run(this.ReloadData);
-						break;
-					case "local":
-						this.Configuration.ShowLocalHunts = !this.Configuration.ShowLocalHunts;
-						this.Configuration.Save();
-						break;
-					case "next":
-						if (this.MobHuntEntries.Count > 0)
-						{
-							var filterPredicate = (MobHuntEntry entry) => entry.IsEliteMark || this.MobHuntStruct->CurrentKills[entry.CurrentKillsOffset] < entry.NeededKills;
-							var openType = Location.OpenType.None;
-							var playerLocation = Service.ClientState.LocalPlayer!.Position;
-							var map = Service.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(Service.ClientState.TerritoryType)!.Map!.Value!;
-							var playerVec2 = MapUtil.WorldToMap(new Vector2(playerLocation.X, playerLocation.Z), map);
-							var chosen = this.CurrentAreaMobHuntEntries
-								.Where(filterPredicate)
-								.OrderBy(entry => entry.IsEliteMark ? float.MaxValue : Vector2.Distance(Location.Database[entry.MobHuntId].Coordinate, playerVec2))
-								.FirstOrDefault();
-							if (chosen == null)
-							{
-								Service.PluginLog.Information("No marks in current zone, looking in current expansion");
-								openType = this.Configuration.IncludeAreaOnMap ? Location.OpenType.ShowOpen : Location.OpenType.MarkerOpen;
-								var expansion = Service.DataManager.Excel.GetSheet<TerritoryType>()!.GetRow(Service.ClientState.TerritoryType)!.ExVersion.Value!.Name;
-								Service.PluginLog.Information($"Player is in a zone from {expansion}; known expansions are {string.Join(", ", this.MobHuntEntries.Keys)}");
-								var candidates = this.MobHuntEntries.ContainsKey(expansion)
-									? this.MobHuntEntries[expansion]
-										.Values
+		this.MobHuntEntriesReady = false;
+		Service.ClientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
+		Service.Framework.Update -= this.FrameworkOnUpdate;
+		Service.PluginInterface.UiBuilder.Draw -= this.WindowSystem.Draw;
+		Service.PluginInterface.UiBuilder.OpenConfigUi -= this.OpenConfigUi;
+
+		this.WindowSystem.RemoveAllWindows();
+
+		this.commandManager.Dispose();
+	}
+
+	[Command("/phb")]
+	[HelpMessage(
+		"Toggles UI\nArguments:\nreload - Reloads data\nlocal - Toggles the local hunt marks window\nnext - Flags the next hunt target to find\nlist - list all hunt targets by expansion")]
+	public unsafe void PluginCommand(string command, string args) {
+		try {
+			switch (args.Trim().ToLower()) {
+				case "reload":
+					this.MobHuntEntriesReady = false;
+					Task.Run(this.ReloadData);
+					break;
+				case "local":
+					this.Configuration.ShowLocalHunts = !this.Configuration.ShowLocalHunts;
+					this.Configuration.Save();
+					break;
+				case "next":
+					if (this.MobHuntEntries.Count > 0) {
+						Func<MobHuntEntry, bool> filterPredicate = (MobHuntEntry entry) => entry.IsEliteMark ||
+							this.MobHuntStruct->CurrentKills[
+								entry.CurrentKillsOffset] <
+							entry.NeededKills;
+						Location.OpenType openType = Location.OpenType.None;
+						Vector3 playerLocation = Service.ClientState.LocalPlayer!.Position;
+						Map map = Service.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(Service.ClientState
+							.TerritoryType)!.Map!.Value!;
+						Vector2 playerVec2 = MapUtil.WorldToMap(new Vector2(playerLocation.X, playerLocation.Z), map);
+						MobHuntEntry? chosen = this.CurrentAreaMobHuntEntries
+							.Where(filterPredicate)
+							.OrderBy(entry =>
+								entry.IsEliteMark
+									? float.MaxValue
+									: Vector2.Distance(Location.Database[entry.MobHuntId].Coordinate, playerVec2))
+							.FirstOrDefault();
+						if (chosen == null) {
+							Service.PluginLog.Information("No marks in current zone, looking in current expansion");
+							openType = this.Configuration.IncludeAreaOnMap
+								? Location.OpenType.ShowOpen
+								: Location.OpenType.MarkerOpen;
+							SeString? expansion =
+								Service.DataManager.Excel.GetSheet<TerritoryType>()!.GetRow(Service.ClientState
+									.TerritoryType)!.ExVersion.Value!.Name;
+							Service.PluginLog.Information(
+								$"Player is in a zone from {expansion}; known expansions are {string.Join(", ", this.MobHuntEntries.Keys)}");
+							List<MobHuntEntry> candidates = this.MobHuntEntries.ContainsKey(expansion)
+								? this.MobHuntEntries[expansion]
+									.Values
+									.SelectMany(l => l)
+									.Where(filterPredicate)
+									.ToList()
+								: new List<MobHuntEntry>();
+							// if we didn't find any candidates, we try a different method to fill it
+							if (candidates.Count == 0) {
+								Service.PluginLog.Information(
+									"Nothing available in current expansion, looking globally");
+								candidates =
+									this.MobHuntEntries.Values
+										.SelectMany(dict => dict.Values)
 										.SelectMany(l => l)
 										.Where(filterPredicate)
-										.ToList()
-									: new List<MobHuntEntry>();
-								// if we didn't find any candidates, we try a different method to fill it
-								if (candidates.Count == 0)
-								{
-									Service.PluginLog.Information("Nothing available in current expansion, looking globally");
-									candidates =
-										this.MobHuntEntries.Values
-											.SelectMany(dict => dict.Values)
-											.SelectMany(l => l)
-											.Where(filterPredicate)
-											.ToList();
-								}
-								// regardless of HOW we got our candidates, assuming we did in fact get them, we pick one
-								// note that this can't be merged into the above block because the above MAY run, and if so MUST run first,
-								// but this block must ALWAYS run, regardless
-								if (candidates.Count >= 1)
-								{
-									Service.PluginLog.Information($"Found {candidates.Count}");
-									chosen = candidates[new Random().Next(candidates.Count)];
-								}
-							}
-							if (chosen != null)
-							{
-								if (chosen.IsEliteMark)
-								{
-									Service.Chat.Print($"Hunting elite mark {chosen.Name} in {chosen.TerritoryName}");
-								}
-								else
-								{
-									var remaining = chosen.NeededKills - this.MobHuntStruct->CurrentKills[chosen.CurrentKillsOffset];
-									Service.Chat.Print($"Hunting {remaining}x {chosen.Name} in {chosen.TerritoryName}");
-									Location.CreateMapMarker(
-										chosen.TerritoryType,
-										chosen.MapId,
-										chosen.MobHuntId,
-										chosen.Name,
-										openType);
-								}
+										.ToList();
 							}
-							else
-							{
-								Service.PluginLog.Information("Unable to find a hunt mark to target");
-								Service.Chat.Print("Couldn't find any hunt marks. Either you have no bills, or this is a bug.");
+
+							// regardless of HOW we got our candidates, assuming we did in fact get them, we pick one
+							// note that this can't be merged into the above block because the above MAY run, and if so MUST run first,
+							// but this block must ALWAYS run, regardless
+							if (candidates.Count >= 1) {
+								Service.PluginLog.Information($"Found {candidates.Count}");
+								chosen = candidates[new Random().Next(candidates.Count)];
 							}
 						}
-						break;
-					case "ls":
-					case "list":
-						if (this.MobHuntEntries.Count < 1) {
-							Service.Chat.Print("No hunt marks found. If this doesn't sound right, please use `/phb reload` and try again.");
-							break;
+
+						if (chosen != null) {
+							if (chosen.IsEliteMark) {
+								Service.Chat.Print($"Hunting elite mark {chosen.Name} in {chosen.TerritoryName}");
+							}
+							else {
+								long remaining = chosen.NeededKills -
+								                 this.MobHuntStruct->CurrentKills[chosen.CurrentKillsOffset];
+								Service.Chat.Print($"Hunting {remaining}x {chosen.Name} in {chosen.TerritoryName}");
+								Location.CreateMapMarker(
+									chosen.TerritoryType,
+									chosen.MapId,
+									chosen.MobHuntId,
+									chosen.Name,
+									openType);
+							}
 						}
-						foreach (string expac in this.MobHuntEntries.Keys) {
-							Service.Chat.Print($"{expac}: {string.Join(", ", this.MobHuntEntries[expac].Values.SelectMany(e => e).OrderBy(s => s.Name).Select(m => m.Name))}");
+						else {
+							Service.PluginLog.Information("Unable to find a hunt mark to target");
+							Service.Chat.Print(
+								"Couldn't find any hunt marks. Either you have no bills, or this is a bug.");
 						}
+					}
+
+					break;
+				case "ls":
+				case "list":
+					if (this.MobHuntEntries.Count < 1) {
+						Service.Chat.Print(
+							"No hunt marks found. If this doesn't sound right, please use `/phb reload` and try again.");
 						break;
-					default:
-						this.DrawInterface();
-						break;
-				}
-			}
-			catch (Exception e)
-			{
-				Service.PluginLog.Error("Error in command handler: " + e.ToString());
+					}
+
+					foreach (string expac in this.MobHuntEntries.Keys) {
+						Service.Chat.Print(
+							$"{expac}: {string.Join(", ", this.MobHuntEntries[expac].Values.SelectMany(e => e).OrderBy(s => s.Name).Select(m => m.Name))}");
+					}
+
+					break;
+				default:
+					this.DrawInterface();
+					break;
 			}
 		}
+		catch (Exception e) {
+			Service.PluginLog.Error($"Error in command handler: {e}");
+		}
+	}
 
-		public unsafe void ReloadData()
-		{
-			this.MobHuntEntries.Clear();
-			var mobHuntList = new List<MobHuntEntry>();
-			var mobHuntOrderSheet = Service.DataManager.Excel.GetSheet<MobHuntOrder>()!;
-
-			foreach (var billNumber in Enum.GetValues<BillEnum>())
-			{
-				if (!this.MobHuntStruct->ObtainedBillEnumFlags.HasFlag((ObtainedBillEnum)(1 << (int)billNumber)))
-				{
-					continue;
-				}
+	public unsafe void ReloadData() {
+		this.MobHuntEntries.Clear();
+		List<MobHuntEntry> mobHuntList = new List<MobHuntEntry>();
+		ExcelSheet<MobHuntOrder>? mobHuntOrderSheet = Service.DataManager.Excel.GetSheet<MobHuntOrder>()!;
+
+		foreach (BillEnum billNumber in Enum.GetValues<BillEnum>()) {
+			if (!this.MobHuntStruct->ObtainedBillEnumFlags.HasFlag((ObtainedBillEnum)(1 << (int)billNumber))) {
+				continue;
+			}
 
-				var mobHuntOrderTypeRow =
-					Service.DataManager.Excel.GetSheet<MobHuntOrderType>()!.GetRow((uint)billNumber)!;
+			MobHuntOrderType mobHuntOrderTypeRow =
+				Service.DataManager.Excel.GetSheet<MobHuntOrderType>()!.GetRow((uint)billNumber)!;
 
-				var rowId = mobHuntOrderTypeRow.OrderStart.Value!.RowId +
-				            (uint)(this.MobHuntStruct->BillOffset[mobHuntOrderTypeRow.RowId] - 1);
+			uint rowId = mobHuntOrderTypeRow.OrderStart.Value!.RowId +
+			             (uint)(this.MobHuntStruct->BillOffset[mobHuntOrderTypeRow.RowId] - 1);
 
-				if (rowId > mobHuntOrderSheet.RowCount)
-				{
-					continue;
-				}
+			if (rowId > mobHuntOrderSheet.RowCount) {
+				continue;
+			}
 
-				var mobHuntOrderRows = mobHuntOrderSheet.Where(x => x.RowId == rowId);
-
-				foreach (var mobHuntOrderRow in mobHuntOrderRows)
-				{
-					var mobHuntEntry =
-						mobHuntList.FirstOrDefault(x => x.MobHuntId == mobHuntOrderRow.Target.Value!.Name.Row);
-
-					if (mobHuntEntry == null)
-					{
-						mobHuntList.Add(
-							new MobHuntEntry
-							{
-								Name = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(
-									mobHuntOrderRow.Target.Value!.Name.Value!.Singular),
-								TerritoryName =
-									mobHuntOrderRow.Target.Value!.TerritoryType.Value!.PlaceName.Value!.Name,
-								ExpansionName = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Value!
-									.ExVersion.Value!.Name,
-								ExpansionId = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Value!
-									.ExVersion.Row,
-								MapId = mobHuntOrderRow.Target.Value!.TerritoryType.Row,
-								TerritoryType = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Row,
-								MobHuntId = mobHuntOrderRow.Target.Value!.Name.Row,
-								IsEliteMark = billNumber is BillEnum.ArrElite or BillEnum.HwElite or BillEnum.SbElite
-									or BillEnum.ShbElite or BillEnum.EwElite,
-								CurrentKillsOffset = (5 * (uint)billNumber) + mobHuntOrderRow.SubRowId,
-								NeededKills = mobHuntOrderRow.NeededKills,
-								Icon = Plugin.LoadIcon(mobHuntOrderRow.Target.Value.Icon)
-							});
-					}
-					else
-					{
-						if (mobHuntEntry.NeededKills < mobHuntOrderRow.NeededKills)
-						{
-							mobHuntEntry.NeededKills = mobHuntOrderRow.NeededKills;
-						}
+			IEnumerable<MobHuntOrder> mobHuntOrderRows = mobHuntOrderSheet.Where(x => x.RowId == rowId);
+
+			foreach (MobHuntOrder mobHuntOrderRow in mobHuntOrderRows) {
+				MobHuntEntry? mobHuntEntry =
+					mobHuntList.FirstOrDefault(x => x.MobHuntId == mobHuntOrderRow.Target.Value!.Name.Row);
+
+				if (mobHuntEntry == null) {
+					mobHuntList.Add(
+						new MobHuntEntry {
+							Name = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(
+								mobHuntOrderRow.Target.Value!.Name.Value!.Singular),
+							TerritoryName =
+								mobHuntOrderRow.Target.Value!.TerritoryType.Value!.PlaceName.Value!.Name,
+							ExpansionName = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Value!
+								.ExVersion.Value!.Name,
+							ExpansionId = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Value!
+								.ExVersion.Row,
+							MapId = mobHuntOrderRow.Target.Value!.TerritoryType.Row,
+							TerritoryType = mobHuntOrderRow.Target.Value!.TerritoryType.Value.TerritoryType.Row,
+							MobHuntId = mobHuntOrderRow.Target.Value!.Name.Row,
+							IsEliteMark = billNumber is BillEnum.ArrElite or BillEnum.HwElite or BillEnum.SbElite
+								or BillEnum.ShbElite or BillEnum.EwElite,
+							CurrentKillsOffset = (5 * (uint)billNumber) + mobHuntOrderRow.SubRowId,
+							NeededKills = mobHuntOrderRow.NeededKills,
+							Icon = Plugin.LoadIcon(mobHuntOrderRow.Target.Value.Icon)
+						});
+				}
+				else {
+					if (mobHuntEntry.NeededKills < mobHuntOrderRow.NeededKills) {
+						mobHuntEntry.NeededKills = mobHuntOrderRow.NeededKills;
 					}
 				}
 			}
+		}
 
-			foreach (var entry in mobHuntList)
-			{
-				var key = entry.ExpansionName ?? "Unknown";
-				var subKey = new KeyValuePair<uint, string>(entry.TerritoryType, entry.TerritoryName ?? "Unknown");
-
-				if (!this.MobHuntEntries.ContainsKey(key))
-				{
-					this.MobHuntEntries[key] = new Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>();
-				}
-
-				if (!this.MobHuntEntries[key].ContainsKey(subKey))
-				{
-					this.MobHuntEntries[key][subKey] = new List<MobHuntEntry>();
-				}
+		foreach (MobHuntEntry entry in mobHuntList) {
+			string key = entry.ExpansionName ?? "Unknown";
+			KeyValuePair<uint, string> subKey =
+				new KeyValuePair<uint, string>(entry.TerritoryType, entry.TerritoryName ?? "Unknown");
 
-				this.MobHuntEntries[key][subKey].Add(entry);
+			if (!this.MobHuntEntries.ContainsKey(key)) {
+				this.MobHuntEntries[key] = new Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>();
 			}
 
-			this.ClientStateOnTerritoryChanged(0);
+			if (!this.MobHuntEntries[key].ContainsKey(subKey)) {
+				this.MobHuntEntries[key][subKey] = new List<MobHuntEntry>();
+			}
 
-			this.MobHuntEntriesReady = true;
+			this.MobHuntEntries[key][subKey].Add(entry);
 		}
 
-		private static IDalamudTextureWrap LoadIcon(uint id)
-		{
-			var icon = Service.DataManager.GameData.GetHqIcon(id) ?? Service.DataManager.GameData.GetIcon(id)!;
-			var iconData = icon.GetRgbaImageData();
+		this.ClientStateOnTerritoryChanged(0);
 
-			return Service.PluginInterface.UiBuilder.LoadImageRaw(iconData, icon.Header.Width, icon.Header.Height, 4);
-		}
+		this.MobHuntEntriesReady = true;
+	}
 
-		public void Dispose()
-		{
-			this.Dispose(true);
-			GC.SuppressFinalize(this);
-		}
+	private static IDalamudTextureWrap LoadIcon(uint id) {
+		TexFile icon = Service.DataManager.GameData.GetHqIcon(id) ?? Service.DataManager.GameData.GetIcon(id)!;
+		byte[] iconData = icon.GetRgbaImageData();
+
+		return Service.PluginInterface.UiBuilder.LoadImageRaw(iconData, icon.Header.Width, icon.Header.Height, 4);
+	}
+
+	public void Dispose() {
+		this.Dispose(true);
+		GC.SuppressFinalize(this);
 	}
 }

+ 66 - 75
HuntBuddy/PluginCommandManager.cs

@@ -2,93 +2,84 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
+
 using Dalamud.Game.Command;
 using Dalamud.Plugin.Services;
+
 using HuntBuddy.Attributes;
 
-namespace HuntBuddy
-{
-	public class PluginCommandManager<THost> : IDisposable
-	{
-		private readonly ICommandManager commandManager;
-		private readonly (string, CommandInfo)[] pluginCommands;
-		private readonly THost host;
-
-		public PluginCommandManager(THost host, ICommandManager commandManager)
-		{
-			this.commandManager = commandManager;
-			this.host = host;
-
-			this.pluginCommands = host!.GetType().GetMethods(
-					BindingFlags.NonPublic | BindingFlags.Public |
-					BindingFlags.Static | BindingFlags.Instance)
-				.Where(method => method.GetCustomAttribute<CommandAttribute>() != null)
-				.SelectMany(this.GetCommandInfoTuple)
-				.ToArray();
-
-			this.AddCommandHandlers();
-		}
+namespace HuntBuddy;
+
+public class PluginCommandManager<THost>: IDisposable {
+	private readonly ICommandManager commandManager;
+	private readonly (string, CommandInfo)[] pluginCommands;
+	private readonly THost host;
+
+	public PluginCommandManager(THost host, ICommandManager commandManager) {
+		this.commandManager = commandManager;
+		this.host = host;
+
+		this.pluginCommands = host!.GetType().GetMethods(
+				BindingFlags.NonPublic | BindingFlags.Public |
+				BindingFlags.Static | BindingFlags.Instance)
+			.Where(method => method.GetCustomAttribute<CommandAttribute>() != null)
+			.SelectMany(this.GetCommandInfoTuple)
+			.ToArray();
+
+		this.AddCommandHandlers();
+	}
 
-		// http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances/
-		// Benchmarking this myself gave similar results, so I'm doing this to somewhat counteract using reflection to access command attributes.
-		// I like the convenience of attributes, but in principle it's a bit slower to use them as opposed to just initializing CommandInfos directly.
-		// It's usually sub-1 millisecond anyways, though. It probably doesn't matter at all.
-		private void AddCommandHandlers()
-		{
-			foreach (var t in this.pluginCommands)
-			{
-				var (command, commandInfo) = t;
-				this.commandManager.AddHandler(command, commandInfo);
-			}
+	// http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances/
+	// Benchmarking this myself gave similar results, so I'm doing this to somewhat counteract using reflection to access command attributes.
+	// I like the convenience of attributes, but in principle it's a bit slower to use them as opposed to just initializing CommandInfos directly.
+	// It's usually sub-1 millisecond anyways, though. It probably doesn't matter at all.
+	private void AddCommandHandlers() {
+		foreach ((string, CommandInfo) t in this.pluginCommands) {
+			(string command, CommandInfo commandInfo) = t;
+			this.commandManager.AddHandler(command, commandInfo);
 		}
+	}
 
-		private void RemoveCommandHandlers()
-		{
-			foreach (var t in this.pluginCommands)
-			{
-				var (command, _) = t;
-				this.commandManager.RemoveHandler(command);
-			}
+	private void RemoveCommandHandlers() {
+		foreach ((string, CommandInfo) t in this.pluginCommands) {
+			(string command, _) = t;
+			this.commandManager.RemoveHandler(command);
 		}
+	}
+
+	private IEnumerable<(string, CommandInfo)> GetCommandInfoTuple(MethodInfo method) {
+		CommandInfo.HandlerDelegate handlerDelegate = (CommandInfo.HandlerDelegate)Delegate.CreateDelegate(
+			typeof(CommandInfo.HandlerDelegate),
+			this.host,
+			method);
+
+		CommandAttribute? command = handlerDelegate.Method.GetCustomAttribute<CommandAttribute>();
+		AliasesAttribute? aliases = handlerDelegate.Method.GetCustomAttribute<AliasesAttribute>();
+		HelpMessageAttribute? helpMessage = handlerDelegate.Method.GetCustomAttribute<HelpMessageAttribute>();
+		DoNotShowInHelpAttribute? doNotShowInHelp =
+			handlerDelegate.Method.GetCustomAttribute<DoNotShowInHelpAttribute>();
 
-		private IEnumerable<(string, CommandInfo)> GetCommandInfoTuple(MethodInfo method)
-		{
-			var handlerDelegate = (CommandInfo.HandlerDelegate)Delegate.CreateDelegate(
-				typeof(CommandInfo.HandlerDelegate),
-				this.host,
-				method);
-
-			var command = handlerDelegate.Method.GetCustomAttribute<CommandAttribute>();
-			var aliases = handlerDelegate.Method.GetCustomAttribute<AliasesAttribute>();
-			var helpMessage = handlerDelegate.Method.GetCustomAttribute<HelpMessageAttribute>();
-			var doNotShowInHelp = handlerDelegate.Method.GetCustomAttribute<DoNotShowInHelpAttribute>();
-
-			var commandInfo = new CommandInfo(handlerDelegate)
-			{
-				HelpMessage = helpMessage?.HelpMessage ?? string.Empty,
-				ShowInHelp = doNotShowInHelp == null,
-			};
-
-			// Create list of tuples that will be filled with one tuple per alias, in addition to the base command tuple.
-			var commandInfoTuples = new List<(string, CommandInfo)> { (command!.Command, commandInfo) };
-			if (aliases == null)
-			{
-				return commandInfoTuples;
-			}
-
-			// ReSharper disable once LoopCanBeConvertedToQuery
-			foreach (var t in aliases.Aliases)
-			{
-				commandInfoTuples.Add((t, commandInfo));
-			}
+		CommandInfo commandInfo = new CommandInfo(handlerDelegate) {
+			HelpMessage = helpMessage?.HelpMessage ?? string.Empty, ShowInHelp = doNotShowInHelp == null,
+		};
 
+		// Create list of tuples that will be filled with one tuple per alias, in addition to the base command tuple.
+		List<(string, CommandInfo)> commandInfoTuples =
+			new List<(string, CommandInfo)> { (command!.Command, commandInfo) };
+		if (aliases == null) {
 			return commandInfoTuples;
 		}
 
-		public void Dispose()
-		{
-			this.RemoveCommandHandlers();
-			GC.SuppressFinalize(this);
+		// ReSharper disable once LoopCanBeConvertedToQuery
+		foreach (string t in aliases.Aliases) {
+			commandInfoTuples.Add((t, commandInfo));
 		}
+
+		return commandInfoTuples;
+	}
+
+	public void Dispose() {
+		this.RemoveCommandHandlers();
+		GC.SuppressFinalize(this);
 	}
-}
+}

+ 55 - 20
HuntBuddy/Service.cs

@@ -5,23 +5,58 @@ using Dalamud.Plugin.Services;
 
 namespace HuntBuddy;
 
-public class Service
-{
-    [PluginService] public static DalamudPluginInterface PluginInterface { get; set; } = null!;
-
-    [PluginService] public static ICommandManager Commands { get; set; } = null!;
-
-    [PluginService] public static IChatGui Chat { get; set; } = null!;
-
-    [PluginService] public static IDataManager DataManager { get; set; } = null!;
-
-    [PluginService] public static ISigScanner SigScanner { get; set; } = null!;
-
-    [PluginService] public static IGameGui GameGui { get; set; } = null!;
-
-    [PluginService] public static IClientState ClientState { get; set; } = null!;
-
-    [PluginService] public static IFramework Framework { get; set; } = null!;
-
-    [PluginService] public static IPluginLog PluginLog { get; set; } = null!;
-}
+public class Service {
+	[PluginService]
+	public static DalamudPluginInterface PluginInterface {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static ICommandManager Commands {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IChatGui Chat {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IDataManager DataManager {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static ISigScanner SigScanner {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IGameGui GameGui {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IClientState ClientState {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IFramework Framework {
+		get;
+		set;
+	} = null!;
+
+	[PluginService]
+	public static IPluginLog PluginLog {
+		get;
+		set;
+	} = null!;
+}

+ 52 - 56
HuntBuddy/Structs/MobHuntStruct.cs

@@ -1,60 +1,56 @@
 using System;
 using System.Runtime.InteropServices;
 
-namespace HuntBuddy.Structs
-{
-	public enum BillEnum : uint
-	{
-		ArrRank1,
-		HwRank1,
-		HwRank2,
-		HwRank3,
-		ArrElite,
-		HwElite,
-		SbRank1,
-		SbRank2,
-		SbRank3,
-		SbElite,
-		ShbRank1,
-		ShbRank2,
-		ShbRank3,
-		ShbElite,
-		EwRank1,
-		EwRank2,
-		EwRank3,
-		EwElite,
-	}
-	
-	[Flags]
-	public enum ObtainedBillEnum : uint
-	{
-		ArrRank1 = 1,
-		HwRank1 = 1 << 1,
-		HwRank2 = 1 << 2,
-		HwRank3 = 1 << 3,
-		ArrElite = 1 << 4,
-		HwElite = 1 << 5,
-		SbRank1 = 1 << 6,
-		SbRank2 = 1 << 7,
-		SbRank3 = 1 << 8,
-		SbElite = 1 << 9,
-		ShbRank1 = 1 << 10,
-		ShbRank2 = 1 << 11,
-		ShbRank3 = 1 << 12,
-		ShbElite = 1 << 13,
-		EwRank1 = 1 << 14,
-		EwRank2 = 1 << 15,
-		EwRank3 = 1 << 16,
-		EwElite = 1 << 17,
-	}
+namespace HuntBuddy.Structs;
 
-	// Signature to get struct address
-	// D1 48 8D 0D ? ? ? ? 48 83 C4 20 5F E9 ? ? ? ?
-	[StructLayout(LayoutKind.Explicit, Size = 0x198)]
-	public unsafe struct MobHuntStruct
-	{
-		[FieldOffset(0x1A)] public fixed byte BillOffset[18];
-		[FieldOffset(0x2C)] public fixed int CurrentKills[5 * 18];
-		[FieldOffset(0x194)] public readonly ObtainedBillEnum ObtainedBillEnumFlags;
-	}
-}
+public enum BillEnum: uint {
+	ArrRank1,
+	HwRank1,
+	HwRank2,
+	HwRank3,
+	ArrElite,
+	HwElite,
+	SbRank1,
+	SbRank2,
+	SbRank3,
+	SbElite,
+	ShbRank1,
+	ShbRank2,
+	ShbRank3,
+	ShbElite,
+	EwRank1,
+	EwRank2,
+	EwRank3,
+	EwElite,
+}
+
+[Flags]
+public enum ObtainedBillEnum: uint {
+	ArrRank1 = 1,
+	HwRank1 = 1 << 1,
+	HwRank2 = 1 << 2,
+	HwRank3 = 1 << 3,
+	ArrElite = 1 << 4,
+	HwElite = 1 << 5,
+	SbRank1 = 1 << 6,
+	SbRank2 = 1 << 7,
+	SbRank3 = 1 << 8,
+	SbElite = 1 << 9,
+	ShbRank1 = 1 << 10,
+	ShbRank2 = 1 << 11,
+	ShbRank3 = 1 << 12,
+	ShbElite = 1 << 13,
+	EwRank1 = 1 << 14,
+	EwRank2 = 1 << 15,
+	EwRank3 = 1 << 16,
+	EwElite = 1 << 17,
+}
+
+// Signature to get struct address
+// D1 48 8D 0D ? ? ? ? 48 83 C4 20 5F E9 ? ? ? ?
+[StructLayout(LayoutKind.Explicit, Size = 0x198)]
+public unsafe struct MobHuntStruct {
+	[FieldOffset(0x1A)] public fixed byte BillOffset[18];
+	[FieldOffset(0x2C)] public fixed int CurrentKills[5 * 18];
+	[FieldOffset(0x194)] public readonly ObtainedBillEnum ObtainedBillEnumFlags;
+}

+ 51 - 54
HuntBuddy/Utils/InterfaceUtil.cs

@@ -1,5 +1,7 @@
 using System.Numerics;
+
 using Dalamud.Interface;
+
 using ImGuiNET;
 
 namespace HuntBuddy.Utils;
@@ -7,67 +9,62 @@ namespace HuntBuddy.Utils;
 /// <summary>
 /// Interface utilities class.
 /// </summary>
-public static class InterfaceUtil
-{
-    /// <summary>
-    /// Draws hunt icons from game images.
-    /// </summary>
-    /// <param name="mobHuntEntry"><see cref="MobHuntEntry"/> containing relevant information.</param>
-    public static void DrawHuntIcon(MobHuntEntry mobHuntEntry)
-    {
-        var cursorPos = ImGui.GetCursorScreenPos();
-        var imageSize = mobHuntEntry.ExpansionId < 3 ? new Vector2(192f, 128f) : new Vector2(210f);
-        imageSize *= ImGui.GetIO().FontGlobalScale * Plugin.Instance.Configuration.IconScale;
+public static class InterfaceUtil {
+	/// <summary>
+	/// Draws hunt icons from game images.
+	/// </summary>
+	/// <param name="mobHuntEntry"><see cref="MobHuntEntry"/> containing relevant information.</param>
+	public static void DrawHuntIcon(MobHuntEntry mobHuntEntry) {
+		Vector2 cursorPos = ImGui.GetCursorScreenPos();
+		Vector2 imageSize = mobHuntEntry.ExpansionId < 3 ? new Vector2(192f, 128f) : new Vector2(210f);
+		imageSize *= ImGui.GetIO().FontGlobalScale * Plugin.Instance.Configuration.IconScale;
 
-        ImGui.InvisibleButton("canvas", imageSize);
+		ImGui.InvisibleButton("canvas", imageSize);
 
-        var drawList = ImGui.GetWindowDrawList();
-        if (mobHuntEntry is { ExpansionId: 4, IsEliteMark: false }) // Endwalker uses circle for non elite mobs
-        {
-            drawList.AddCircleFilled(
-                cursorPos + (imageSize / 2f),
-                imageSize.X / 2f,
-                Plugin.Instance.Configuration.IconBackgroundColourU32);
-        }
-        else
-        {
-            drawList.AddRectFilled(
-                cursorPos,
-                cursorPos + imageSize,
-                Plugin.Instance.Configuration.IconBackgroundColourU32);
-        }
+		ImDrawListPtr drawList = ImGui.GetWindowDrawList();
+		if (mobHuntEntry is { ExpansionId: 4, IsEliteMark: false }) // Endwalker uses circle for non elite mobs
+		{
+			drawList.AddCircleFilled(
+				cursorPos + (imageSize / 2f),
+				imageSize.X / 2f,
+				Plugin.Instance.Configuration.IconBackgroundColourU32);
+		}
+		else {
+			drawList.AddRectFilled(
+				cursorPos,
+				cursorPos + imageSize,
+				Plugin.Instance.Configuration.IconBackgroundColourU32);
+		}
 
-        drawList.AddImage(mobHuntEntry.Icon.ImGuiHandle, cursorPos, cursorPos + imageSize);
-    }
+		drawList.AddImage(mobHuntEntry.Icon.ImGuiHandle, cursorPos, cursorPos + imageSize);
+	}
 
-    /// <summary>
-    /// Renders a button with an icon.
-    /// </summary>
-    /// <param name="icon">Desired <see cref="FontAwesomeIcon"/> to be rendered.</param>
-    /// <param name="id">Button ID.</param>
-    /// <returns>True if pressed.</returns>
-    public static bool IconButton(FontAwesomeIcon icon, string? id)
-    {
-        ImGui.PushFont(UiBuilder.IconFont);
+	/// <summary>
+	/// Renders a button with an icon.
+	/// </summary>
+	/// <param name="icon">Desired <see cref="FontAwesomeIcon"/> to be rendered.</param>
+	/// <param name="id">Button ID.</param>
+	/// <returns>True if pressed.</returns>
+	public static bool IconButton(FontAwesomeIcon icon, string? id) {
+		ImGui.PushFont(UiBuilder.IconFont);
 
-        var text = icon.ToIconString();
+		string? text = icon.ToIconString();
 
-        if (id != null)
-        {
-            text += $"##{id}";
-        }
+		if (id != null) {
+			text += $"##{id}";
+		}
 
-        var result = ImGui.Button(text);
+		bool result = ImGui.Button(text);
 
-        ImGui.PopFont();
+		ImGui.PopFont();
 
-        return result;
-    }
+		return result;
+	}
 
-    /// <summary>
-    /// Renders a button with an icon.
-    /// </summary>
-    /// <param name="icon">Desired <see cref="FontAwesomeIcon"/> to be rendered.</param>
-    /// <returns>True if pressed.</returns>
-    public static bool IconButton(FontAwesomeIcon icon) => IconButton(icon, null);
-}
+	/// <summary>
+	/// Renders a button with an icon.
+	/// </summary>
+	/// <param name="icon">Desired <see cref="FontAwesomeIcon"/> to be rendered.</param>
+	/// <returns>True if pressed.</returns>
+	public static bool IconButton(FontAwesomeIcon icon) => IconButton(icon, null);
+}

+ 46 - 52
HuntBuddy/Windows/ConfigurationWindow.cs

@@ -1,5 +1,7 @@
 using System.Numerics;
+
 using Dalamud.Interface.Windowing;
+
 using ImGuiNET;
 
 namespace HuntBuddy.Windows;
@@ -7,59 +9,51 @@ namespace HuntBuddy.Windows;
 /// <summary>
 /// Configuration window.
 /// </summary>
-public class ConfigurationWindow : Window
-{
-    public ConfigurationWindow() : base(
-        $"{Plugin.Instance.Name} configuration",
-        ImGuiWindowFlags.NoDocking,
-        true)
-    {
-        this.Size = Vector2.Zero;
-        this.SizeCondition = ImGuiCond.Always;
-    }
+public class ConfigurationWindow: Window {
+	public ConfigurationWindow(): base(
+		$"{Plugin.Instance.Name} configuration",
+		ImGuiWindowFlags.NoDocking,
+		true) {
+		this.Size = Vector2.Zero;
+		this.SizeCondition = ImGuiCond.Always;
+	}
 
-    public override void PreOpenCheck()
-    {
-        if (Plugin.Instance.Configuration.LockWindowPositions)
-        {
-            if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove))
-            {
-                this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
-            }
-        }
-        else
-        {
-            this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
-        }
-    }
+	public override void PreOpenCheck() {
+		if (Plugin.Instance.Configuration.LockWindowPositions) {
+			if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove)) {
+				this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
+			}
+		}
+		else {
+			this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
+		}
+	}
 
-    public override void Draw()
-    {
-        var save = false;
+	public override void Draw() {
+		bool save = false;
 
-        save |= ImGui.Checkbox("Lock plugin window positions", ref Plugin.Instance.Configuration.LockWindowPositions);
-        save |= ImGui.Checkbox("Include hunt area on map by default", ref Plugin.Instance.Configuration.IncludeAreaOnMap);
-        save |= ImGui.Checkbox("Show hunts in local area", ref Plugin.Instance.Configuration.ShowLocalHunts);
-        save |= ImGui.Checkbox(
-            "Show icons of hunts in local area",
-            ref Plugin.Instance.Configuration.ShowLocalHuntIcons);
-        save |= ImGui.Checkbox(
-            "Hide background of local hunts window",
-            ref Plugin.Instance.Configuration.HideLocalHuntBackground);
-        save |= ImGui.Checkbox(
-            "Hide completed targets in local hunts window",
-            ref Plugin.Instance.Configuration.HideCompletedHunts);
-        save |= ImGui.SliderFloat("Hunt icon scale", ref Plugin.Instance.Configuration.IconScale, 0.2f, 2f, "%.2f");
-        if (ImGui.ColorEdit4("Hunt icon background colour", ref Plugin.Instance.Configuration.IconBackgroundColour))
-        {
-            Plugin.Instance.Configuration.IconBackgroundColourU32 =
-                ImGui.ColorConvertFloat4ToU32(Plugin.Instance.Configuration.IconBackgroundColour);
-            save = true;
-        }
+		save |= ImGui.Checkbox("Lock plugin window positions", ref Plugin.Instance.Configuration.LockWindowPositions);
+		save |= ImGui.Checkbox("Include hunt area on map by default",
+			ref Plugin.Instance.Configuration.IncludeAreaOnMap);
+		save |= ImGui.Checkbox("Show hunts in local area", ref Plugin.Instance.Configuration.ShowLocalHunts);
+		save |= ImGui.Checkbox(
+			"Show icons of hunts in local area",
+			ref Plugin.Instance.Configuration.ShowLocalHuntIcons);
+		save |= ImGui.Checkbox(
+			"Hide background of local hunts window",
+			ref Plugin.Instance.Configuration.HideLocalHuntBackground);
+		save |= ImGui.Checkbox(
+			"Hide completed targets in local hunts window",
+			ref Plugin.Instance.Configuration.HideCompletedHunts);
+		save |= ImGui.SliderFloat("Hunt icon scale", ref Plugin.Instance.Configuration.IconScale, 0.2f, 2f, "%.2f");
+		if (ImGui.ColorEdit4("Hunt icon background colour", ref Plugin.Instance.Configuration.IconBackgroundColour)) {
+			Plugin.Instance.Configuration.IconBackgroundColourU32 =
+				ImGui.ColorConvertFloat4ToU32(Plugin.Instance.Configuration.IconBackgroundColour);
+			save = true;
+		}
 
-        if (save)
-        {
-            Plugin.Instance.Configuration.Save();
-        }
-    }
-}
+		if (save) {
+			Plugin.Instance.Configuration.Save();
+		}
+	}
+}

+ 117 - 135
HuntBuddy/Windows/LocalHuntsWindow.cs

@@ -1,8 +1,11 @@
 using System.Linq;
 using System.Numerics;
+
 using Dalamud.Interface;
 using Dalamud.Interface.Windowing;
+
 using HuntBuddy.Utils;
+
 using ImGuiNET;
 
 namespace HuntBuddy.Windows;
@@ -10,138 +13,117 @@ namespace HuntBuddy.Windows;
 /// <summary>
 /// Local hunts window.
 /// </summary>
-public class LocalHuntsWindow : Window
-{
-    public LocalHuntsWindow() : base(
-        "Hunts in current area",
-        ImGuiWindowFlags.NoNavInputs | ImGuiWindowFlags.NoDocking,
-        true)
-    {
-        this.Size = Vector2.Zero;
-        this.SizeCondition = ImGuiCond.Always;
-
-        this.IsOpen = true;
-        this.ShowCloseButton = false;
-        this.RespectCloseHotkey = false;
-    }
-
-    public override void PreOpenCheck()
-    {
-        if (Plugin.Instance.Configuration.HideLocalHuntBackground)
-        {
-            if (!this.Flags.HasFlag(ImGuiWindowFlags.NoBackground))
-            {
-                this.Flags |= ImGuiWindowFlags.NoBackground;
-            }
-        }
-        else
-        {
-            this.Flags &= ~ImGuiWindowFlags.NoBackground;
-        }
-
-        if (Plugin.Instance.Configuration.LockWindowPositions)
-        {
-            if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove))
-            {
-                this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
-            }
-        }
-        else
-        {
-            this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
-        }
-    }
-
-    public override unsafe bool DrawConditions() =>
-        Plugin.Instance.Configuration.ShowLocalHunts &&
-        !Plugin.Instance.CurrentAreaMobHuntEntries.IsEmpty &&
-        Plugin.Instance.CurrentAreaMobHuntEntries.Count(
-            x => Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] == x.NeededKills) !=
-        Plugin.Instance.CurrentAreaMobHuntEntries.Count;
-
-    public override unsafe void Draw()
-    {
-        foreach (var mobHuntEntry in Plugin.Instance.CurrentAreaMobHuntEntries)
-        {
-            var currentKills = Plugin.Instance.MobHuntStruct->CurrentKills[mobHuntEntry.CurrentKillsOffset];
-
-            if (Plugin.Instance.Configuration.HideCompletedHunts && currentKills == mobHuntEntry.NeededKills)
-            {
-                continue;
-            }
-
-            if (Location.Database.ContainsKey(mobHuntEntry.MobHuntId))
-            {
-                if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkerAlt, $"pin##{mobHuntEntry.MobHuntId}"))
-                {
-                    Location.CreateMapMarker(
-                        mobHuntEntry.TerritoryType,
-                        mobHuntEntry.MapId,
-                        mobHuntEntry.MobHuntId,
-                        mobHuntEntry.Name,
-                        Location.OpenType.None);
-                }
-
-                if (ImGui.IsItemHovered())
-                {
-                    ImGui.BeginTooltip();
-                    ImGui.Text("Place marker on the map");
-                    ImGui.EndTooltip();
-                }
-
-                ImGui.SameLine();
-
-                if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkedAlt, $"open##{mobHuntEntry.MobHuntId}"))
-                {
-                    var includeArea = Plugin.Instance.Configuration.IncludeAreaOnMap;
-                    if (ImGui.IsKeyDown(ImGuiKey.ModShift))
-                    {
-                        includeArea = !includeArea;
-                    }
-
-                    Location.CreateMapMarker(
-                        mobHuntEntry.TerritoryType,
-                        mobHuntEntry.MapId,
-                        mobHuntEntry.MobHuntId,
-                        mobHuntEntry.Name,
-                        includeArea ? Location.OpenType.ShowOpen : Location.OpenType.MarkerOpen);
-                }
-
-                if (ImGui.IsItemHovered())
-                {
-                    var color = ImGui.IsKeyDown(ImGuiKey.ModShift)
-                        ? new Vector4(0f, 0.7f, 0f, 1f)
-                        : new Vector4(0.7f, 0.7f, 0.7f, 1f);
-                    ImGui.BeginTooltip();
-                    if (Plugin.Instance.Configuration.IncludeAreaOnMap)
-                    {
-                        ImGui.Text("Show hunt area on the map");
-                        ImGui.TextColored(
-                            color,
-                            "Hold [SHIFT] to show the location only");
-                    }
-                    else
-                    {
-                        ImGui.Text("Show hunt location on the map");
-                        ImGui.TextColored(
-                            color,
-                            "Hold [SHIFT] to include the area");
-                    }
-
-                    ImGui.EndTooltip();
-                }
-
-                ImGui.SameLine();
-            }
-
-            ImGui.Text($"{mobHuntEntry.Name} ({currentKills}/{mobHuntEntry.NeededKills})");
-
-            if (!Plugin.Instance.Configuration.ShowLocalHuntIcons)
-            {
-                continue;
-            }
-
-            InterfaceUtil.DrawHuntIcon(mobHuntEntry);
-        }
-    }
-}
+public class LocalHuntsWindow: Window {
+	public LocalHuntsWindow(): base(
+		"Hunts in current area",
+		ImGuiWindowFlags.NoNavInputs | ImGuiWindowFlags.NoDocking,
+		true) {
+		this.Size = Vector2.Zero;
+		this.SizeCondition = ImGuiCond.Always;
+
+		this.IsOpen = true;
+		this.ShowCloseButton = false;
+		this.RespectCloseHotkey = false;
+	}
+
+	public override void PreOpenCheck() {
+		if (Plugin.Instance.Configuration.HideLocalHuntBackground) {
+			if (!this.Flags.HasFlag(ImGuiWindowFlags.NoBackground)) {
+				this.Flags |= ImGuiWindowFlags.NoBackground;
+			}
+		}
+		else {
+			this.Flags &= ~ImGuiWindowFlags.NoBackground;
+		}
+
+		if (Plugin.Instance.Configuration.LockWindowPositions) {
+			if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove)) {
+				this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
+			}
+		}
+		else {
+			this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
+		}
+	}
+
+	public override unsafe bool DrawConditions() =>
+		Plugin.Instance.Configuration.ShowLocalHunts &&
+		!Plugin.Instance.CurrentAreaMobHuntEntries.IsEmpty &&
+		Plugin.Instance.CurrentAreaMobHuntEntries.Count(
+			x => Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] == x.NeededKills) !=
+		Plugin.Instance.CurrentAreaMobHuntEntries.Count;
+
+	public override unsafe void Draw() {
+		foreach (MobHuntEntry? mobHuntEntry in Plugin.Instance.CurrentAreaMobHuntEntries) {
+			int currentKills = Plugin.Instance.MobHuntStruct->CurrentKills[mobHuntEntry.CurrentKillsOffset];
+
+			if (Plugin.Instance.Configuration.HideCompletedHunts && currentKills == mobHuntEntry.NeededKills) {
+				continue;
+			}
+
+			if (Location.Database.ContainsKey(mobHuntEntry.MobHuntId)) {
+				if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkerAlt, $"pin##{mobHuntEntry.MobHuntId}")) {
+					Location.CreateMapMarker(
+						mobHuntEntry.TerritoryType,
+						mobHuntEntry.MapId,
+						mobHuntEntry.MobHuntId,
+						mobHuntEntry.Name,
+						Location.OpenType.None);
+				}
+
+				if (ImGui.IsItemHovered()) {
+					ImGui.BeginTooltip();
+					ImGui.Text("Place marker on the map");
+					ImGui.EndTooltip();
+				}
+
+				ImGui.SameLine();
+
+				if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkedAlt, $"open##{mobHuntEntry.MobHuntId}")) {
+					bool includeArea = Plugin.Instance.Configuration.IncludeAreaOnMap;
+					if (ImGui.IsKeyDown(ImGuiKey.ModShift)) {
+						includeArea = !includeArea;
+					}
+
+					Location.CreateMapMarker(
+						mobHuntEntry.TerritoryType,
+						mobHuntEntry.MapId,
+						mobHuntEntry.MobHuntId,
+						mobHuntEntry.Name,
+						includeArea ? Location.OpenType.ShowOpen : Location.OpenType.MarkerOpen);
+				}
+
+				if (ImGui.IsItemHovered()) {
+					Vector4 color = ImGui.IsKeyDown(ImGuiKey.ModShift)
+						? new Vector4(0f, 0.7f, 0f, 1f)
+						: new Vector4(0.7f, 0.7f, 0.7f, 1f);
+					ImGui.BeginTooltip();
+					if (Plugin.Instance.Configuration.IncludeAreaOnMap) {
+						ImGui.Text("Show hunt area on the map");
+						ImGui.TextColored(
+							color,
+							"Hold [SHIFT] to show the location only");
+					}
+					else {
+						ImGui.Text("Show hunt location on the map");
+						ImGui.TextColored(
+							color,
+							"Hold [SHIFT] to include the area");
+					}
+
+					ImGui.EndTooltip();
+				}
+
+				ImGui.SameLine();
+			}
+
+			ImGui.Text($"{mobHuntEntry.Name} ({currentKills}/{mobHuntEntry.NeededKills})");
+
+			if (!Plugin.Instance.Configuration.ShowLocalHuntIcons) {
+				continue;
+			}
+
+			InterfaceUtil.DrawHuntIcon(mobHuntEntry);
+		}
+	}
+}

+ 175 - 201
HuntBuddy/Windows/MainWindow.cs

@@ -1,9 +1,13 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
 using System.Numerics;
 using System.Threading.Tasks;
+
 using Dalamud.Interface;
 using Dalamud.Interface.Windowing;
+
 using ImGuiNET;
+
 using HuntBuddy.Utils;
 
 namespace HuntBuddy.Windows;
@@ -11,203 +15,173 @@ namespace HuntBuddy.Windows;
 /// <summary>
 /// Main plugin window.
 /// </summary>
-public class MainWindow : Window
-{
-    public MainWindow() : base(
-        $"{Plugin.Instance.Name}",
-        ImGuiWindowFlags.NoDocking,
-        true)
-    {
-        this.Size = new Vector2(400 * ImGui.GetIO().FontGlobalScale, 500);
-        this.SizeCondition = ImGuiCond.Once;
-    }
-
-    public override void PreOpenCheck()
-    {
-        if (Plugin.Instance.Configuration.LockWindowPositions)
-        {
-            if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove))
-            {
-                this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
-            }
-        }
-        else
-        {
-            this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
-        }
-    }
-
-    public override unsafe void Draw()
-    {
-        if (!Plugin.Instance.MobHuntEntriesReady)
-        {
-            ImGui.Text("Reloading data ...");
-            return;
-        }
-
-        if (InterfaceUtil.IconButton(FontAwesomeIcon.Redo, "Reload"))
-        {
-            Plugin.Instance.MobHuntEntriesReady = false;
-            Task.Run(Plugin.Instance.ReloadData);
-            return;
-        }
-
-        if (ImGui.IsItemHovered())
-        {
-            ImGui.BeginTooltip();
-            ImGui.Text("Click this button to reload daily hunt data");
-            ImGui.EndTooltip();
-        }
-
-        ImGui.SameLine();
-
-        if (InterfaceUtil.IconButton(FontAwesomeIcon.Cog, "Config"))
-        {
-            Plugin.Instance.OpenConfigUi();
-        }
-
-        foreach (var expansionEntry in Plugin.Instance.MobHuntEntries.Where(
-                     expansionEntry =>
-                         ImGui.TreeNode(expansionEntry.Key)))
-        {
-            foreach (var entry in expansionEntry.Value.Where(
-                         entry =>
-                         {
-                             var treeOpen = ImGui.TreeNodeEx(entry.Key.Value, ImGuiTreeNodeFlags.AllowItemOverlap);
-                             ImGui.SameLine();
-                             var killedCount = entry.Value.Count(
-                                 x =>
-                                     Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] ==
-                                     x.NeededKills);
-
-                             if (killedCount != entry.Value.Count)
-                             {
-                                 ImGui.Text($"({killedCount}/{entry.Value.Count})");
-                             }
-                             else
-                             {
-                                 ImGui.TextColored(
-                                     new Vector4(0f, 1f, 0f, 1f),
-                                     $"({killedCount}/{entry.Value.Count})");
-                             }
-
-                             return treeOpen;
-                         }))
-            {
-                foreach (var mobHuntEntry in entry.Value)
-                {
-                    if (Location.Database.ContainsKey(mobHuntEntry.MobHuntId))
-                    {
-                        if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkerAlt, $"pin##{mobHuntEntry.MobHuntId}"))
-                        {
-                            Location.CreateMapMarker(
-                                mobHuntEntry.TerritoryType,
-                                mobHuntEntry.MapId,
-                                mobHuntEntry.MobHuntId,
-                                mobHuntEntry.Name,
-                                Location.OpenType.None);
-                        }
-
-                        if (ImGui.IsItemHovered())
-                        {
-                            ImGui.BeginTooltip();
-                            ImGui.Text("Place marker on the map");
-                            ImGui.EndTooltip();
-                        }
-
-                        ImGui.SameLine();
-
-                        if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkedAlt, $"open##{mobHuntEntry.MobHuntId}"))
-                        {
-                            var includeArea = Plugin.Instance.Configuration.IncludeAreaOnMap;
-                            if (ImGui.IsKeyDown(ImGuiKey.ModShift))
-                            {
-                                includeArea = !includeArea;
-                            }
-
-                            Location.CreateMapMarker(
-                                mobHuntEntry.TerritoryType,
-                                mobHuntEntry.MapId,
-                                mobHuntEntry.MobHuntId,
-                                mobHuntEntry.Name,
-                                includeArea ? Location.OpenType.ShowOpen : Location.OpenType.MarkerOpen);
-                        }
-
-                        if (ImGui.IsItemHovered())
-                        {
-                            var color = ImGui.IsKeyDown(ImGuiKey.ModShift)
-                                ? new Vector4(0f, 0.7f, 0f, 1f)
-                                : new Vector4(0.7f, 0.7f, 0.7f, 1f);
-                            ImGui.BeginTooltip();
-                            if (Plugin.Instance.Configuration.IncludeAreaOnMap)
-                            {
-                                ImGui.Text("Show hunt area on the map");
-                                ImGui.TextColored(
-                                    color,
-                                    "Hold [SHIFT] to show the location only");
-                            }
-                            else
-                            {
-                                ImGui.Text("Show hunt location on the map");
-                                ImGui.TextColored(
-                                    color,
-                                    "Hold [SHIFT] to include the area");
-                            }
-
-                            ImGui.EndTooltip();
-                        }
-
-                        ImGui.SameLine();
-
-                        if (Plugin.TeleportConsumer?.IsAvailable == true)
-                        {
-                            if (InterfaceUtil.IconButton(FontAwesomeIcon.StreetView, $"t##{mobHuntEntry.MobHuntId}"))
-                            {
-                                Location.TeleportToNearestAetheryte(
-                                    mobHuntEntry.TerritoryType,
-                                    mobHuntEntry.MapId,
-                                    mobHuntEntry.MobHuntId);
-                            }
-
-                            if (ImGui.IsItemHovered())
-                            {
-                                ImGui.BeginTooltip();
-                                ImGui.Text("Teleport to nearest aetheryte");
-                                ImGui.EndTooltip();
-                            }
-
-                            ImGui.SameLine();
-                        }
-                    }
-
-                    var currentKills = Plugin.Instance.MobHuntStruct->CurrentKills[mobHuntEntry.CurrentKillsOffset];
-                    ImGui.Text(mobHuntEntry.Name);
-                    if (ImGui.IsItemHovered())
-                    {
-                        ImGui.PushStyleColor(ImGuiCol.PopupBg, Vector4.Zero);
-                        ImGui.BeginTooltip();
-                        InterfaceUtil.DrawHuntIcon(mobHuntEntry);
-                        ImGui.PopStyleColor();
-                        ImGui.EndTooltip();
-                    }
-
-                    ImGui.SameLine();
-                    if (currentKills != mobHuntEntry.NeededKills)
-                    {
-                        ImGui.Text($"({currentKills}/{mobHuntEntry.NeededKills})");
-                    }
-                    else
-                    {
-                        ImGui.TextColored(
-                            new Vector4(0f, 1f, 0f, 1f),
-                            $"({currentKills}/{mobHuntEntry.NeededKills})");
-                    }
-                }
-
-                ImGui.TreePop();
-            }
-
-            ImGui.TreePop();
-        }
-    }
-}
+public class MainWindow: Window {
+	public MainWindow(): base(
+		$"{Plugin.Instance.Name}",
+		ImGuiWindowFlags.NoDocking,
+		true) {
+		this.Size = new Vector2(400 * ImGui.GetIO().FontGlobalScale, 500);
+		this.SizeCondition = ImGuiCond.Once;
+	}
+
+	public override void PreOpenCheck() {
+		if (Plugin.Instance.Configuration.LockWindowPositions) {
+			if (!this.Flags.HasFlag(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove)) {
+				this.Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
+			}
+		}
+		else {
+			this.Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
+		}
+	}
+
+	public override unsafe void Draw() {
+		if (!Plugin.Instance.MobHuntEntriesReady) {
+			ImGui.Text("Reloading data ...");
+			return;
+		}
+
+		if (InterfaceUtil.IconButton(FontAwesomeIcon.Redo, "Reload")) {
+			Plugin.Instance.MobHuntEntriesReady = false;
+			Task.Run(Plugin.Instance.ReloadData);
+			return;
+		}
+
+		if (ImGui.IsItemHovered()) {
+			ImGui.BeginTooltip();
+			ImGui.Text("Click this button to reload daily hunt data");
+			ImGui.EndTooltip();
+		}
+
+		ImGui.SameLine();
+
+		if (InterfaceUtil.IconButton(FontAwesomeIcon.Cog, "Config")) {
+			Plugin.Instance.OpenConfigUi();
+		}
+
+		foreach (KeyValuePair<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>> expansionEntry in
+		         Plugin.Instance.MobHuntEntries.Where(
+			         expansionEntry =>
+				         ImGui.TreeNode(expansionEntry.Key))) {
+			foreach (KeyValuePair<KeyValuePair<uint, string>, List<MobHuntEntry>> entry in expansionEntry.Value.Where(
+				         entry => {
+					         bool treeOpen = ImGui.TreeNodeEx(entry.Key.Value, ImGuiTreeNodeFlags.AllowItemOverlap);
+					         ImGui.SameLine();
+					         int killedCount = entry.Value.Count(
+						         x =>
+							         Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] ==
+							         x.NeededKills);
+
+					         if (killedCount != entry.Value.Count) {
+						         ImGui.Text($"({killedCount}/{entry.Value.Count})");
+					         }
+					         else {
+						         ImGui.TextColored(
+							         new Vector4(0f, 1f, 0f, 1f),
+							         $"({killedCount}/{entry.Value.Count})");
+					         }
+
+					         return treeOpen;
+				         })) {
+				foreach (MobHuntEntry? mobHuntEntry in entry.Value) {
+					if (Location.Database.ContainsKey(mobHuntEntry.MobHuntId)) {
+						if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkerAlt, $"pin##{mobHuntEntry.MobHuntId}")) {
+							Location.CreateMapMarker(
+								mobHuntEntry.TerritoryType,
+								mobHuntEntry.MapId,
+								mobHuntEntry.MobHuntId,
+								mobHuntEntry.Name,
+								Location.OpenType.None);
+						}
+
+						if (ImGui.IsItemHovered()) {
+							ImGui.BeginTooltip();
+							ImGui.Text("Place marker on the map");
+							ImGui.EndTooltip();
+						}
+
+						ImGui.SameLine();
+
+						if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkedAlt, $"open##{mobHuntEntry.MobHuntId}")) {
+							bool includeArea = Plugin.Instance.Configuration.IncludeAreaOnMap;
+							if (ImGui.IsKeyDown(ImGuiKey.ModShift)) {
+								includeArea = !includeArea;
+							}
+
+							Location.CreateMapMarker(
+								mobHuntEntry.TerritoryType,
+								mobHuntEntry.MapId,
+								mobHuntEntry.MobHuntId,
+								mobHuntEntry.Name,
+								includeArea ? Location.OpenType.ShowOpen : Location.OpenType.MarkerOpen);
+						}
+
+						if (ImGui.IsItemHovered()) {
+							Vector4 color = ImGui.IsKeyDown(ImGuiKey.ModShift)
+								? new Vector4(0f, 0.7f, 0f, 1f)
+								: new Vector4(0.7f, 0.7f, 0.7f, 1f);
+							ImGui.BeginTooltip();
+							if (Plugin.Instance.Configuration.IncludeAreaOnMap) {
+								ImGui.Text("Show hunt area on the map");
+								ImGui.TextColored(
+									color,
+									"Hold [SHIFT] to show the location only");
+							}
+							else {
+								ImGui.Text("Show hunt location on the map");
+								ImGui.TextColored(
+									color,
+									"Hold [SHIFT] to include the area");
+							}
+
+							ImGui.EndTooltip();
+						}
+
+						ImGui.SameLine();
+
+						if (Plugin.TeleportConsumer?.IsAvailable == true) {
+							if (InterfaceUtil.IconButton(FontAwesomeIcon.StreetView, $"t##{mobHuntEntry.MobHuntId}")) {
+								Location.TeleportToNearestAetheryte(
+									mobHuntEntry.TerritoryType,
+									mobHuntEntry.MapId,
+									mobHuntEntry.MobHuntId);
+							}
+
+							if (ImGui.IsItemHovered()) {
+								ImGui.BeginTooltip();
+								ImGui.Text("Teleport to nearest aetheryte");
+								ImGui.EndTooltip();
+							}
+
+							ImGui.SameLine();
+						}
+					}
+
+					int currentKills = Plugin.Instance.MobHuntStruct->CurrentKills[mobHuntEntry.CurrentKillsOffset];
+					ImGui.Text(mobHuntEntry.Name);
+					if (ImGui.IsItemHovered()) {
+						ImGui.PushStyleColor(ImGuiCol.PopupBg, Vector4.Zero);
+						ImGui.BeginTooltip();
+						InterfaceUtil.DrawHuntIcon(mobHuntEntry);
+						ImGui.PopStyleColor();
+						ImGui.EndTooltip();
+					}
+
+					ImGui.SameLine();
+					if (currentKills != mobHuntEntry.NeededKills) {
+						ImGui.Text($"({currentKills}/{mobHuntEntry.NeededKills})");
+					}
+					else {
+						ImGui.TextColored(
+							new Vector4(0f, 1f, 0f, 1f),
+							$"({currentKills}/{mobHuntEntry.NeededKills})");
+					}
+				}
+
+				ImGui.TreePop();
+			}
+
+			ImGui.TreePop();
+		}
+	}
+}

BIN
HuntBuddy/settings.stylecop