diff --git a/Locales/Locale_deDE.lua b/Locales/Locale_deDE.lua index 1a99fcd..28aa6aa 100644 --- a/Locales/Locale_deDE.lua +++ b/Locales/Locale_deDE.lua @@ -1,142 +1,37 @@ --- Locale_deDE.lua - German Localization for ModernMapMarkers -ModernMapMarkers_Locale:RegisterZones("deDE", { - -- Continent names - ["Kalimdor"] = "Kalimdor", - ["Eastern Kingdoms"] = "Östliche Königreiche", - ["Ashenvale"] = "Eschental", - ["Azshara"] = "Azshara", - ["Badlands"] = "Ödland", - ["Balor"] = "Balor", - ["Blasted Lands"] = "Verwüstete Lande", - ["Burning Steppes"] = "Brennende Steppe", - ["Darkshore"] = "Dunkelküste", - ["Deadwind Pass"] = "Gebirgspass der Totenwinde", - ["Desolace"] = "Desolace", - ["Dun Morogh"] = "Dun Morogh", - ["Durotar"] = "Durotar", - ["Duskwood"] = "Dämmerwald", - ["Dustwallow Marsh"] = "Düstermarschen", - ["Eastern Plaguelands"] = "Östliche Pestländer", - ["Elwynn Forest"] = "Wald von Elwynn", - ["Feralas"] = "Feralas", - ["Gilneas"] = "Gilneas", - ["Hyjal"] = "Hyjal", - ["Ironforge"] = "Eisenschmiede", - ["Moonwhisper Coast"] = "Mondflüsterküste", - ["Orgrimmar"] = "Orgrimmar", - ["Searing Gorge"] = "Sengende Schlucht", - ["Silithus"] = "Silithus", - ["Silverpine Forest"] = "Silberwald", - ["Stormwind City"] = "Sturmwind", - ["Stranglethorn Vale"] = "Schlingendorntal", - ["Swamp of Sorrows"] = "Sümpfe des Elends", - ["Tanaris"] = "Tanaris", - ["Teldrassil"] = "Teldrassil", - ["The Barrens"] = "Brachland", - ["The Hinterlands"] = "Hinterland", - ["Thunder Bluff"] = "Donnerfels", - ["Tirisfal Glades"] = "Tirisfal", - ["Western Plaguelands"] = "Westliche Pestländer", - ["Westfall"] = "Westfall", - ["Wetlands"] = "Sumpfland", - ["Alah'Thalas"] = "Alah'Thalas", -}) - -ModernMapMarkers_Locale:RegisterMarkers("deDE", { - -- Dungeons - ["Blackfathom Deeps"] = "Tiefschwarze Grotte", - ["Crescent Grove"] = "Mondsichelhain", - ["Maraudon"] = "Maraudon", - ["Ragefire Chasm"] = "Der Flammenschlund", - ["Dire Maul"] = "Düsterbruch", - ["Dire Maul - East"] = "Düsterbruch - Ost", - ["Dire Maul - North"] = "Düsterbruch - Nord", - ["Dire Maul - West"] = "Düsterbruch - West", - ["Razorfen Downs"] = "Hügel der Klingenhauer", - ["Razorfen Kraul"] = "Kral der Klingenhauer", - ["Wailing Caverns"] = "Höhlen des Wehklagens", - ["Zul'Farrak"] = "Zul'Farrak", - ["Black Morass"] = "Höhlen der Zeit: Schwarzer Morast", - ["Gnomeregan"] = "Gnomeregan", - ["Stormwrought Ruins"] = "Ruine von Sturmschmied", - ["Stormwrought Ruins - Back Entrance"] = "Ruine von Sturmschmied - Hintereingang", - ["Blackrock Depths"] = "Schwarzfelstiefen", - ["Hateforge Quarry"] = "Hassschmieden Steinbruch", - ["Lower Blackrock Spire"] = "Untere Schwarzfelsspitze", - ["Upper Blackrock Spire"] = "Obere Schwarzfelsspitze", - ["Karazhan Crypt"] = "Karazhan Krypta", - ["Scarlet Monastery"] = "Das Scharlachrote Kloster", - ["Scarlet Monastery - Armory"] = "Das Scharlachrote Kloster - Waffenkammer", - ["Scarlet Monastery - Cathedral"] = "Das Scharlachrote Kloster - Kathedrale", - ["Scarlet Monastery - Graveyard"] = "Das Scharlachrote Kloster - Friedhof", - ["Scarlet Monastery - Library"] = "Das Scharlachrote Kloster - Bibliothek", - ["Scholomance"] = "Scholomance", - ["Shadowfang Keep"] = "Burg Schattenfang", - ["Stratholme"] = "Stratholme", - ["Stratholme - Back Gate"] = "Stratholme - Hintertor", - ["The Deadmines"] = "Die Todesminen", - ["The Stockade"] = "Das Verlies", - ["Stormwind Vault"] = "Tresor von Sturmwind", - ["Stormwind Vault - Horde Entrance"] = "Tresor von Sturmwind - Horde-Eingang", - ["Gilneas City"] = "Stadt von Gilneas", - ["The Sunken Temple"] = "Der Versunkene Tempel", - ["Dragonmaw Retreat"] = "Zuflucht des Drachenmals", - ["Uldaman"] = "Uldaman", - ["Uldaman - Main Entrance"] = "Uldaman - Haupteingang", - ["Uldaman - Back Entrance"] = "Uldaman - Hintereingang", - ["Frostmane Hollow"] = "Frostmane Hollow", - ["Windhorn Canyon"] = "Schlucht der heulenden Winde", - - -- Raids - ["Onyxia's Lair"] = "Onyxias Hort", - ["Emerald Sanctum"] = "Smaragdsanktum", - ["Ruins of Ahn'Qiraj"] = "Ruinen von Ahn'Qiraj", - ["Temple of Ahn'Qiraj"] = "Tempel von Ahn'Qiraj", - ["Blackwing Lair"] = "Pechschwingenhort", - ["Molten Core"] = "Geschmolzener Kern", - ["Lower Karazhan Halls"] = "Untere Hallen von Karazhan", - ["Tower of Karazhan"] = "Turm von Karazhan", - ["Naxxramas"] = "Naxxramas", - ["Zul'Gurub"] = "Zul'Gurub", - ["Timbermaw Hold"] = "Holzschlundfeste", - - -- World Bosses - ["Taerar"] = "Taerar", - ["Lethon"] = "Lethon", - ["Emeriss"] = "Emeriss", - ["Ysondre"] = "Ysondre", - ["Azuregos"] = "Azuregos", - ["Cla'ckora"] = "Cla'ckora", - ["Concavius"] = "Concavius", - ["Father Lycan"] = "Vater Lycan", - ["Lord Kazzak"] = "Lord Kazzak", - ["Ostarius"] = "Ostarius", - ["Dark Reaver of Karazhan"] = "Dunkler Plünderer von Karazhan", - ["Nerubian Overseer"] = "Nerubischer Aufseher", - - -- Transports - ["Boat to Stormwind"] = "Schiff nach Sturmwind", - ["Boat to Alah'Thalas"] = "Schiff nach Alah'Thalas", - ["Boat to Rut'Theran Village"] = "Schiff nach Rut'Theran", - ["Boat to Auberdine"] = "Schiff nach Auberdine", - ["Boat to Menethil Harbor"] = "Schiff zum Hafen von Menethil", - ["Boat to Theramore Isle"] = "Schiff zur Insel Theramore", - ["Boat to Booty Bay"] = "Schiff zur Beutebucht", - ["Boat to Ratchet"] = "Schiff nach Ratschet", - ["Boat to Forgotten Coast"] = "Schiff zur Vergessenen Küste", - ["Boat to Sardor Isle"] = "Schiff zur Sardor-Insel", - ["Boat to Revantusk Village"] = "Schiff zum Dorf der Bruchhauer", - ["Boat to Sparkwater Port"] = "Schiff zum Funkelwasserhafen", - ["Boat to Shadowprey Village"] = "Schiff nach Schattenflucht", - ["Boat to Moonhoof Village"] = "Schiff nach Mondhuf", - ["Zeppelins to UC & Grom'Gol"] = "Zeppeline nach Unterstadt & Grom’gol", - ["Zeppelins to TB & Kargath"] = "Zeppeline nach Donnerfels & Kargath", - ["Zeppelin to Orgrimmar"] = "Zeppelin nach Orgrimmar", - ["Zeppelins to Orgrimmar & Grom'Gol"] = "Zeppeline nach Orgrimmar & Grom'Gol", - ["Zeppelins to UC & Orgrimmar"] = "Zeppeline nach Unterstadt & Orgrimmar", - ["Tram to Stormwind"] = "Tiefenbahn nach Sturmwind", - ["Tram to Ironforge"] = "Tiefenbahn nach Eisenschmiede", +ModernMapMarkers_Locale:RegisterDictionary("deDE", { + ["Kalimdor"] = "Kalimdor", + ["Eastern Kingdoms"] = "Östliche Königreiche", + -- Dungeon masks + -- %s will get substituted with the localized Dungeon name + ["%s - East"] = "%s - Ost", -- Dire Maul + ["%s - West"] = "%s - West", -- Dire Maul + ["%s - North"] = "%s - Nord", -- Dire Maul + ["%s - Back Entrance"] = "%s - Hintereingang", -- Stormwrought Ruins, Uldaman + ["Lower %s"] = "Untere %s", -- Lower Blackrock Spire + ["Upper %s"] = "Obere %s", -- Upper Blackrock Spire + ["%s - Armory"] = "%s - Waffenkammer", -- Scarlet Monastery + ["%s - Cathedral"] = "%s - Kathedrale", -- Scarlet Monastery + ["%s - Graveyard"] = "%s - Friedhof", -- Scarlet Monastery + ["%s - Library"] = "%s - Bibliothek", -- Scarlet Monastery + ["%s - Back Gate"] = "%s - Hintertor", -- Stratholme + ["%s - Horde Entrance"] = "%s - Horde-Eingang", -- Stormwind Vault + ["%s - Main Entrance"] = "%s - Haupteingang", -- Uldaman + + -- Transport masks + -- %s will get substituted with the destination's localized name + ["Boat to %s"] = "Schiff nach %s", + ["Zeppelin to %s"] = "Zeppelin nach %s", + ["Tram to %s"] = "Tiefenbahn nach %s", + -- translations that need manual adjustment + ["Boat to Menethil Harbor"] = "Schiff zum Hafen von Menethil", + ["Boat to Theramore Isle"] = "Schiff zur Insel Theramore", + ["Boat to Sparkwater Port"] = "Schiff zum Funkelwasserhafen", + ["Boat to The Forgotten Coast"] = "Schiff zur Vergessenen Küste", + ["Boat to Sardor Isle"] = "Schiff zur Insel Sardor", + ["Boat to Revantusk Village"] = "Schiff zum Dorf der Bruchhauer", + ["Zeppelin to Grom'gol Base Camp"] = "Zeppelin zum Basislager von Grom'gol", -- Tooltip labels ["Level"] = "Stufe", diff --git a/Locales/Locale_esES.lua b/Locales/Locale_esES.lua index 6b2320e..8ab86d2 100644 --- a/Locales/Locale_esES.lua +++ b/Locales/Locale_esES.lua @@ -1,140 +1,29 @@ --- Locale_esES.lua - Spanish Localization for ModernMapMarkers -ModernMapMarkers_Locale:RegisterZones("esES", { - -- Continent names +ModernMapMarkers_Locale:RegisterDictionary("esES", { ["Kalimdor"] = "Kalimdor", ["Eastern Kingdoms"] = "Reinos del Este", - ["Ashenvale"] = "Vallefresno", - ["Azshara"] = "Azshara", - ["Badlands"] = "Tierras Inhóspitas", - ["Balor"] = "Balor", - ["Blasted Lands"] = "Las Tierras Devastadas", - ["Burning Steppes"] = "Las Estepas Ardientes", - ["Darkshore"] = "Costa Oscura", - ["Deadwind Pass"] = "Paso de la Muerte", - ["Desolace"] = "Desolace", - ["Dun Morogh"] = "Dun Morogh", - ["Durotar"] = "Durotar", - ["Duskwood"] = "Bosque del Ocaso", - ["Dustwallow Marsh"] = "Marjal Revolcafango", - ["Eastern Plaguelands"] = "Tierras de la Peste del Este", - ["Elwynn Forest"] = "Bosque de Elwynn", - ["Feralas"] = "Feralas", - ["Gilneas"] = "Gilneas", - ["Hyjal"] = "Hyjal", - ["Ironforge"] = "Forjaz", - ["Moonwhisper Coast"] = "Costa del Susurro de Luna", - ["Orgrimmar"] = "Orgrimmar", - ["Searing Gorge"] = "La Garganta de Fuego", - ["Silithus"] = "Silithus", - ["Silverpine Forest"] = "Bosque de Argénteos", - ["Stormwind City"] = "Ciudad de Ventormenta", - ["Stranglethorn Vale"] = "Vega de Tuercespina", - ["Swamp of Sorrows"] = "Pantano de las Penas", - ["Tanaris"] = "Tanaris", - ["Teldrassil"] = "Teldrassil", - ["The Barrens"] = "Los Baldíos", - ["The Hinterlands"] = "Tierras del Interior", - ["Thunder Bluff"] = "Cima del Trueno", - ["Tirisfal Glades"] = "Claros de Tirisfal", - ["Western Plaguelands"] = "Tierras de la Peste del Oeste", - ["Westfall"] = "Páramos de Poniente", - ["Wetlands"] = "Los Humedales", - ["Alah'Thalas"] = "Alah'Thalas", -}) - -ModernMapMarkers_Locale:RegisterMarkers("esES", { - -- Dungeons - ["Blackfathom Deeps"] = "Cavernas de Brazanegra", - ["Crescent Grove"] = "Arboleda de la Media Luna", - ["Maraudon"] = "Maraudon", - ["Ragefire Chasm"] = "Sima Ígnea", - ["Dire Maul"] = "La Masacre", - ["Dire Maul - East"] = "La Masacre - Este", - ["Dire Maul - North"] = "La Masacre - Norte", - ["Dire Maul - West"] = "La Masacre - Oeste", - ["Razorfen Downs"] = "Zahúrda Rajacieno", - ["Razorfen Kraul"] = "Madriguera de Rajacieno", - ["Wailing Caverns"] = "Cuevas de los Lamentos", - ["Zul'Farrak"] = "Zul'Farrak", - ["Black Morass"] = "La Ciénaga Negra", - ["Gnomeregan"] = "Gnomeregan", - ["Stormwrought Ruins"] = "Ruinas Forjatormenta", - ["Stormwrought Ruins - Back Entrance"] = "Ruinas Forjatormenta - Entrada Trasera", - ["Blackrock Depths"] = "Profundidades de Roca Negra", - ["Hateforge Quarry"] = "Cantera Hateforge", - ["Lower Blackrock Spire"] = "Cumbre de Roca Negra Inferior", - ["Upper Blackrock Spire"] = "Cumbre de Roca Negra Superior", - ["Karazhan Crypt"] = "Cripta de Karazhan", - ["Scarlet Monastery"] = "Monasterio Escarlata", - ["Scarlet Monastery - Armory"] = "Monasterio Escarlata - Armería", - ["Scarlet Monastery - Cathedral"] = "Monasterio Escarlata - Catedral", - ["Scarlet Monastery - Graveyard"] = "Monasterio Escarlata - Cementerio", - ["Scarlet Monastery - Library"] = "Monasterio Escarlata - Biblioteca", - ["Scholomance"] = "Scholomance", - ["Shadowfang Keep"] = "Fortaleza Colmillo Oscuro", - ["Stratholme"] = "Stratholme", - ["Stratholme - Back Gate"] = "Stratholme - Puerta Trasera", - ["The Deadmines"] = "Las Minas de la Muerte", - ["The Stockade"] = "La Mazmorras", - ["Stormwind Vault"] = "Bóveda de Ventormenta", - ["Stormwind Vault - Horde Entrance"] = "Bóveda de Ventormenta - Entrada Horda", - ["Gilneas City"] = "Ciudad Gilneas", - ["The Sunken Temple"] = "El Templo Sumergido", - ["Dragonmaw Retreat"] = "Refugio Faucedrago", - ["Uldaman"] = "Uldaman", - ["Uldaman - Main Entrance"] = "Uldaman - Entrada Principal", - ["Uldaman - Back Entrance"] = "Uldaman - Entrada Trasera", - ["Frostmane Hollow"] = "Frostmane Hollow", - ["Windhorn Canyon"] = "Windhorn Canyon", - - -- Raids - ["Onyxia's Lair"] = "Guarida de Onyxia", - ["Emerald Sanctum"] = "Sanctum Esmeralda", - ["Ruins of Ahn'Qiraj"] = "Ruinas de Ahn'Qiraj", - ["Temple of Ahn'Qiraj"] = "Templo de Ahn'Qiraj", - ["Blackwing Lair"] = "Guarida Alanegra", - ["Molten Core"] = "Núcleo de Magma", - ["Lower Karazhan Halls"] = "Salas Inferiores de Karazhan", - ["Tower of Karazhan"] = "Torre de Karazhan", - ["Naxxramas"] = "Naxxramas", - ["Zul'Gurub"] = "Zul'Gurub", - ["Timbermaw Hold"] = "Timbermaw Hold", - - -- World Bosses - ["Taerar"] = "Taerar", - ["Lethon"] = "Lethon", - ["Emeriss"] = "Emeriss", - ["Ysondre"] = "Ysondre", - ["Azuregos"] = "Azuregos", - ["Cla'ckora"] = "Cla'ckora", - ["Concavius"] = "Concavius", - ["Father Lycan"] = "Padre Lycan", - ["Lord Kazzak"] = "Lord Kazzak", - ["Ostarius"] = "Ostarius", - ["Dark Reaver of Karazhan"] = "Saqueador Oscuro de Karazhan", - ["Nerubian Overseer"] = "Supervisor Nerubiano", - - -- Transports - ["Boat to Stormwind"] = "Barco a Ventormenta", - ["Boat to Alah'Thalas"] = "Barco a Alah'Thalas", - ["Boat to Rut'Theran Village"] = "Barco a Aldea Rut'Theran", - ["Boat to Auberdine"] = "Barco a Auberdine", - ["Boat to Menethil Harbor"] = "Barco a Puerto de Menethil", - ["Boat to Theramore Isle"] = "Barco a Isla Theramore", - ["Boat to Booty Bay"] = "Barco a Bahía del Botín", - ["Boat to Ratchet"] = "Barco a Trinquete", - ["Boat to Forgotten Coast"] = "Barco a Costa Olvidada", - ["Boat to Sardor Isle"] = "Barco a Isla Sardor", - ["Boat to Revantusk Village"] = "Barco a Aldea Revantusk", - ["Boat to Sparkwater Port"] = "Barco a Puerto Chispeagua", - ["Zeppelins to UC & Grom'Gol"] = "Zepelines a UC y Grom'Gol", - ["Zeppelins to TB & Kargath"] = "Zepelines a TB y Kargath", - ["Zeppelin to Orgrimmar"] = "Zepelín a Orgrimmar", - ["Zeppelins to Orgrimmar & Grom'Gol"] = "Zepelines a Orgrimmar y Grom'Gol", - ["Zeppelins to UC & Orgrimmar"] = "Zepelines a UC y Orgrimmar", - ["Tram to Stormwind"] = "Tranvía a Ventormenta", - ["Tram to Ironforge"] = "Tranvía a Forjaz", + -- Dungeon masks + -- %s will get substituted with the localized Dungeon name + ["%s - East"] = "%s - Este", -- Dire Maul + ["%s - West"] = "%s - Oeste", -- Dire Maul + ["%s - North"] = "%s - Norte", -- Dire Maul + ["%s - Back Entrance"] = "%s - Entrada Trasera", -- Stormwrought Ruins, Uldaman + ["Lower %s"] = "%s Inferior", -- Lower Blackrock Spire + ["Upper %s"] = "%s Superior", -- Upper Blackrock Spire + ["%s - Armory"] = "%s - Armería", -- Scarlet Monastery + ["%s - Cathedral"] = "%s - Catedral", -- Scarlet Monastery + ["%s - Graveyard"] = "%s - Cementerio", -- Scarlet Monastery + ["%s - Library"] = "%s - Biblioteca", -- Scarlet Monastery + ["%s - Back Gate"] = "%s - Puerta Trasera", -- Stratholme + ["%s - Horde Entrance"] = "%s - Entrada Horda", -- Stormwind Vault + ["%s - Main Entrance"] = "%s - Entrada Principal", -- Uldaman + + -- Transport masks + -- %s will get substituted with the destination's localized name + ["Boat to %s"] = "Barco a %s", + ["Zeppelin to %s"] = "Zepelín a %s", + ["Tram to %s"] = "Tranvía a %s", -- Tooltip labels ["Level"] = "Nivel", diff --git a/Locales/Locale_ptBR.lua b/Locales/Locale_ptBR.lua index 64a78db..3371536 100644 --- a/Locales/Locale_ptBR.lua +++ b/Locales/Locale_ptBR.lua @@ -1,140 +1,29 @@ --- Locale_ptBR.lua - Portuguese (Brazil) Localization for ModernMapMarkers -ModernMapMarkers_Locale:RegisterZones("ptBR", { - -- Continent names +ModernMapMarkers_Locale:RegisterDictionary("ptBR", { ["Kalimdor"] = "Kalimdor", ["Eastern Kingdoms"] = "Reinos do Leste", - ["Ashenvale"] = "Vale Gris", - ["Azshara"] = "Azshara", - ["Badlands"] = "Ermos", - ["Balor"] = "Balor", - ["Blasted Lands"] = "Barreira do Inferno", - ["Burning Steppes"] = "Estepes Ardentes", - ["Darkshore"] = "Costa Negra", - ["Deadwind Pass"] = "Trilha do Vento Morto", - ["Desolace"] = "Desolação", - ["Dun Morogh"] = "Dun Morogh", - ["Durotar"] = "Durotar", - ["Duskwood"] = "Floresta do Crepúsculo", - ["Dustwallow Marsh"] = "Pântano Vadeoso", - ["Eastern Plaguelands"] = "Terras Pestilentas Orientais", - ["Elwynn Forest"] = "Floresta de Elwynn", - ["Feralas"] = "Feralas", - ["Gilneas"] = "Gilneas", - ["Hyjal"] = "Hyjal", - ["Ironforge"] = "Altaforja", - ["Moonwhisper Coast"] = "Costa do Sussurro da Lua", - ["Orgrimmar"] = "Orgrimmar", - ["Searing Gorge"] = "Garganta Abrasadora", - ["Silithus"] = "Silithus", - ["Silverpine Forest"] = "Floresta de Pinhaprata", - ["Stormwind City"] = "Ventobravo", - ["Stranglethorn Vale"] = "Selva do Espinhaço", - ["Swamp of Sorrows"] = "Pântano das Mágoas", - ["Tanaris"] = "Tanaris", - ["Teldrassil"] = "Teldrassil", - ["The Barrens"] = "Sertões", - ["The Hinterlands"] = "Terras Agrestes", - ["Thunder Bluff"] = "Penhasco do Trovão", - ["Tirisfal Glades"] = "Clareiras de Tirisfal", - ["Western Plaguelands"] = "Terras Pestilentas Ocidentais", - ["Westfall"] = "Cerro Oeste", - ["Wetlands"] = "Pantanal", - ["Alah'Thalas"] = "Alah'Thalas", -}) - -ModernMapMarkers_Locale:RegisterMarkers("ptBR", { - -- Dungeons - ["Blackfathom Deeps"] = "Profundezas Negras", - ["Crescent Grove"] = "Bosque do Crescente", - ["Maraudon"] = "Maraudon", - ["Ragefire Chasm"] = "Cavernas Ragefire", - ["Dire Maul"] = "Gládio Cruel", - ["Dire Maul - East"] = "Gládio Cruel - Leste", - ["Dire Maul - North"] = "Gládio Cruel - Norte", - ["Dire Maul - West"] = "Gládio Cruel - Oeste", - ["Razorfen Downs"] = "Urzal dos Mortos", - ["Razorfen Kraul"] = "Razorfen Kraul", - ["Wailing Caverns"] = "Cavernas Uivantes", - ["Zul'Farrak"] = "Zul'Farrak", - ["Black Morass"] = "O Morass Negro", - ["Gnomeregan"] = "Gnomeregan", - ["Stormwrought Ruins"] = "Ruínas da Tempestade", - ["Stormwrought Ruins - Back Entrance"] = "Ruínas da Tempestade - Entrada Traseira", - ["Blackrock Depths"] = "Abismo Rocha Negra", - ["Hateforge Quarry"] = "Pedreira Forja do Ódio", - ["Lower Blackrock Spire"] = "Pico da Rocha Negra Inferior", - ["Upper Blackrock Spire"] = "Pico da Rocha Negra Superior", - ["Karazhan Crypt"] = "Cripta Karazhan", - ["Scarlet Monastery"] = "Monastério Scarlet", - ["Scarlet Monastery - Armory"] = "Monastério Scarlet - Arsenal", - ["Scarlet Monastery - Cathedral"] = "Monastério Scarlet - Catedral", - ["Scarlet Monastery - Graveyard"] = "Monastério Scarlet - Cemitério", - ["Scarlet Monastery - Library"] = "Monastério Scarlet - Biblioteca", - ["Scholomance"] = "Scholomance", - ["Shadowfang Keep"] = "Fortaleza Shadowfang", - ["Stratholme"] = "Stratholme", - ["Stratholme - Back Gate"] = "Stratholme - Portão Traseiro", - ["The Deadmines"] = "As Minas Mortas", - ["The Stockade"] = "A Prisão", - ["Stormwind Vault"] = "Cofre Stormwind", - ["Stormwind Vault - Horde Entrance"] = "Cofre Stormwind - Entrada da Horda", - ["Gilneas City"] = "Cidade de Gilneas", - ["The Sunken Temple"] = "O Templo Abaixo d'Água", - ["Dragonmaw Retreat"] = "Refúgio Presa do Dragão", - ["Uldaman"] = "Uldaman", - ["Uldaman - Main Entrance"] = "Uldaman - Entrada Principal", - ["Uldaman - Back Entrance"] = "Uldaman - Entrada Traseira", - ["Frostmane Hollow"] = "Frostmane Hollow", - ["Windhorn Canyon"] = "Windhorn Canyon", - - -- Raids - ["Onyxia's Lair"] = "Caverna de Onyxia", - ["Emerald Sanctum"] = "Santuário Esmeralda", - ["Ruins of Ahn'Qiraj"] = "Ruínas de Ahn'Qiraj", - ["Temple of Ahn'Qiraj"] = "Templo de Ahn'Qiraj", - ["Blackwing Lair"] = "Covil Asa Negra", - ["Molten Core"] = "Núcleo Derretido", - ["Lower Karazhan Halls"] = "Salões Inferiores de Karazhan", - ["Tower of Karazhan"] = "Torre de Karazhan", - ["Naxxramas"] = "Naxxramas", - ["Zul'Gurub"] = "Zul'Gurub", - ["Timbermaw Hold"] = "Timbermaw Hold", - - -- World Bosses - ["Taerar"] = "Taerar", - ["Lethon"] = "Lethon", - ["Emeriss"] = "Emeriss", - ["Ysondre"] = "Ysondre", - ["Azuregos"] = "Azuregos", - ["Cla'ckora"] = "Cla'ckora", - ["Concavius"] = "Concavius", - ["Father Lycan"] = "Pai Lycan", - ["Lord Kazzak"] = "Lorde Kazzak", - ["Ostarius"] = "Ostarius", - ["Dark Reaver of Karazhan"] = "Saqueador Sombrio de Karazhan", - ["Nerubian Overseer"] = "Supervisor Nerubiano", - - -- Transports - ["Boat to Stormwind"] = "Barco para Ventobravo", - ["Boat to Alah'Thalas"] = "Barco para Alah'Thalas", - ["Boat to Rut'Theran Village"] = "Barco para Aldeia Rut'Theran", - ["Boat to Auberdine"] = "Barco para Auberdine", - ["Boat to Menethil Harbor"] = "Barco para Puerto Menethil", - ["Boat to Theramore Isle"] = "Barco para Ilha Theramore", - ["Boat to Booty Bay"] = "Barco para Angra do Butim", - ["Boat to Ratchet"] = "Barco para Carroça", - ["Boat to Forgotten Coast"] = "Barco para Costa Esquecida", - ["Boat to Sardor Isle"] = "Barco para Ilha Sardor", - ["Boat to Revantusk Village"] = "Barco para Aldeia Revantusk", - ["Boat to Sparkwater Port"] = "Barco para Porto Sparkwater", - ["Zeppelins to UC & Grom'Gol"] = "Zepelins para UC e Grom'Gol", - ["Zeppelins to TB & Kargath"] = "Zepelins para TB e Kargath", - ["Zeppelin to Orgrimmar"] = "Zepelim para Orgrimmar", - ["Zeppelins to Orgrimmar & Grom'Gol"] = "Zepelins para Orgrimmar e Grom'Gol", - ["Zeppelins to UC & Orgrimmar"] = "Zepelins para UC e Orgrimmar", - ["Tram to Stormwind"] = "Trem para Ventobravo", - ["Tram to Ironforge"] = "Trem para Altaforja", + -- Dungeon masks + -- %s will get substituted with the localized Dungeon name + ["%s - East"] = "%s - Leste", -- Dire Maul + ["%s - West"] = "%s - Oeste", -- Dire Maul + ["%s - North"] = "%s - Norte", -- Dire Maul + ["%s - Back Entrance"] = "%s - Entrada Traseira", -- Stormwrought Ruins, Uldaman + ["Lower %s"] = "%s Inferior", -- Lower Blackrock Spire + ["Upper %s"] = "%s Superior", -- Upper Blackrock Spire + ["%s - Armory"] = "%s - Arsenal", -- Scarlet Monastery + ["%s - Cathedral"] = "%s - Catedral", -- Scarlet Monastery + ["%s - Graveyard"] = "%s - Cemitério", -- Scarlet Monastery + ["%s - Library"] = "%s - Biblioteca", -- Scarlet Monastery + ["%s - Back Gate"] = "%s - Portão Traseiro", -- Stratholme + ["%s - Horde Entrance"] = "%s - Entrada da Horda", -- Stormwind Vault + ["%s - Main Entrance"] = "%s - Entrada Principal", -- Uldaman + + -- Transport masks + -- %s will get substituted with the destination's localized name + ["Boat to %s"] = "Barco para %s", + ["Zeppelin to %s"] = "Zepelim para %s", + ["Tram to %s"] = "Trem para %s", -- Tooltip labels ["Level"] = "Nível", diff --git a/Locales/Locale_zhCN.lua b/Locales/Locale_zhCN.lua index 91bcc5a..b8f9bd6 100644 --- a/Locales/Locale_zhCN.lua +++ b/Locales/Locale_zhCN.lua @@ -1,140 +1,29 @@ --- Locale_zhCN.lua - Simplified Chinese Localization for ModernMapMarkers -ModernMapMarkers_Locale:RegisterZones("zhCN", { - -- Continent names +ModernMapMarkers_Locale:RegisterDictionary("zhCN", { ["Kalimdor"] = "卡利姆多", ["Eastern Kingdoms"] = "东部王国", - ["Ashenvale"] = "灰谷", - ["Azshara"] = "艾萨拉", - ["Badlands"] = "荒芜之地", - ["Balor"] = "巴洛", - ["Blasted Lands"] = "诅咒之地", - ["Burning Steppes"] = "燃烧平原", - ["Darkshore"] = "黑海岸", - ["Deadwind Pass"] = "逆风小径", - ["Desolace"] = "凄凉之地", - ["Dun Morogh"] = "丹莫罗", - ["Durotar"] = "杜隆塔尔", - ["Duskwood"] = "暮色森林", - ["Dustwallow Marsh"] = "尘泥沼泽", - ["Eastern Plaguelands"] = "东瘟疫之地", - ["Elwynn Forest"] = "艾尔文森林", - ["Feralas"] = "菲拉斯", - ["Gilneas"] = "吉尔尼斯", - ["Hyjal"] = "海加尔山", - ["Ironforge"] = "铁炉堡", - ["Moonwhisper Coast"] = "月语海岸", - ["Orgrimmar"] = "奥格瑞玛", - ["Searing Gorge"] = "灼热峡谷", - ["Silithus"] = "希利苏斯", - ["Silverpine Forest"] = "银松森林", - ["Stormwind City"] = "暴风城", - ["Stranglethorn Vale"] = "荆棘谷", - ["Swamp of Sorrows"] = "悲伤沼泽", - ["Tanaris"] = "塔纳利斯", - ["Teldrassil"] = "泰达希尔", - ["The Barrens"] = "贫瘠之地", - ["The Hinterlands"] = "辛特兰", - ["Thunder Bluff"] = "雷霆崖", - ["Tirisfal Glades"] = "提瑞斯法林地", - ["Western Plaguelands"] = "西瘟疫之地", - ["Westfall"] = "西部荒野", - ["Wetlands"] = "湿地", - ["Alah'Thalas"] = "阿尔萨拉斯", -}) - -ModernMapMarkers_Locale:RegisterMarkers("zhCN", { - -- Dungeons - ["Blackfathom Deeps"] = "黑暗深渊", - ["Crescent Grove"] = "新月林地", - ["Maraudon"] = "玛拉顿", - ["Ragefire Chasm"] = "怒焰裂谷", - ["Dire Maul"] = "厄运之槌", - ["Dire Maul - East"] = "厄运之槌 - 东", - ["Dire Maul - North"] = "厄运之槌 - 北", - ["Dire Maul - West"] = "厄运之槌 - 西", - ["Razorfen Downs"] = "剃刀高地", - ["Razorfen Kraul"] = "剃刀沼泽", - ["Wailing Caverns"] = "哀嚎洞穴", - ["Zul'Farrak"] = "祖尔法拉克", - ["Black Morass"] = "黑色沼泽", - ["Gnomeregan"] = "诺莫瑞根", - ["Stormwrought Ruins"] = "风暴废墟", - ["Stormwrought Ruins - Back Entrance"] = "风暴废墟 - 后门", - ["Blackrock Depths"] = "黑石深渊", - ["Hateforge Quarry"] = "仇恨熔炉采石场", - ["Lower Blackrock Spire"] = "黑石塔下层", - ["Upper Blackrock Spire"] = "黑石塔上层", - ["Karazhan Crypt"] = "卡拉赞墓穴", - ["Scarlet Monastery"] = "血色修道院", - ["Scarlet Monastery - Armory"] = "血色修道院 - 兵器库", - ["Scarlet Monastery - Cathedral"] = "血色修道院 - 教堂", - ["Scarlet Monastery - Graveyard"] = "血色修道院 - 墓地", - ["Scarlet Monastery - Library"] = "血色修道院 - 图书馆", - ["Scholomance"] = "通灵学院", - ["Shadowfang Keep"] = "影牙城堡", - ["Stratholme"] = "斯坦索姆", - ["Stratholme - Back Gate"] = "斯坦索姆 - 后门", - ["The Deadmines"] = "死亡矿井", - ["The Stockade"] = "监狱", - ["Stormwind Vault"] = "暴风城地牢", - ["Stormwind Vault - Horde Entrance"] = "暴风城地牢 - 部落入口", - ["Gilneas City"] = "吉尔尼斯城", - ["The Sunken Temple"] = "沉没的神庙", - ["Dragonmaw Retreat"] = "龙喉居所", - ["Uldaman"] = "奥达曼", - ["Uldaman - Main Entrance"] = "奥达曼 - 主入口", - ["Uldaman - Back Entrance"] = "奥达曼 - 后入口", - ["Frostmane Hollow"] = "霜鬃谷", - ["Windhorn Canyon"] = "风角峡谷", - - -- Raids - ["Onyxia's Lair"] = "奥妮克希亚的巢穴", - ["Emerald Sanctum"] = "翡翠圣殿", - ["Ruins of Ahn'Qiraj"] = "安其拉废墟", - ["Temple of Ahn'Qiraj"] = "安其拉神殿", - ["Blackwing Lair"] = "黑翼之巢", - ["Molten Core"] = "熔火之心", - ["Lower Karazhan Halls"] = "卡拉赞下层大厅", - ["Tower of Karazhan"] = "卡拉赞之塔", - ["Naxxramas"] = "纳克萨玛斯", - ["Zul'Gurub"] = "祖尔格拉布", - ["Timbermaw Hold"] = "木喉要塞", - - -- World Bosses - ["Taerar"] = "塔拉尔", - ["Lethon"] = "莱索恩", - ["Emeriss"] = "艾莫莉丝", - ["Ysondre"] = "伊森德雷", - ["Azuregos"] = "艾索雷葛斯", - ["Cla'ckora"] = "克拉科拉", - ["Concavius"] = "空卡维斯", - ["Father Lycan"] = "人狼神父", - ["Lord Kazzak"] = "卡扎克", - ["Ostarius"] = "奥兹塔里亚斯", - ["Dark Reaver of Karazhan"] = "卡拉赞黑暗掠夺者", - ["Nerubian Overseer"] = "蛛怪监工", - - -- Transports - ["Boat to Stormwind"] = "前往暴风城", - ["Boat to Alah'Thalas"] = "前往阿尔萨拉斯", - ["Boat to Rut'Theran Village"] = "前往鲁瑟兰村", - ["Boat to Auberdine"] = "前往奥伯丁", - ["Boat to Menethil Harbor"] = "前往米奈希尔港", - ["Boat to Theramore Isle"] = "前往塞拉摩岛", - ["Boat to Booty Bay"] = "前往藏宝海湾", - ["Boat to Ratchet"] = "前往棘齿城", - ["Boat to Forgotten Coast"] = "前往被遗忘的海岸", - ["Boat to Sardor Isle"] = "前往萨多尔岛", - ["Boat to Revantusk Village"] = "前往恶齿村", - ["Boat to Sparkwater Port"] = "前往怒水港", - ["Zeppelins to UC & Grom'Gol"] = "飞艇前往幽暗城和格罗姆高", - ["Zeppelins to TB & Kargath"] = "飞艇前往雷霆崖和卡加斯", - ["Zeppelin to Orgrimmar"] = "飞艇前往奥格瑞玛", - ["Zeppelins to Orgrimmar & Grom'Gol"] = "飞艇前往奥格瑞玛和格罗姆高", - ["Zeppelins to UC & Orgrimmar"] = "飞艇前往幽暗城和奥格瑞玛", - ["Tram to Stormwind"] = "地铁前往暴风城", - ["Tram to Ironforge"] = "地铁前往铁炉堡", + -- Dungeon masks + -- %s will get substituted with the localized Dungeon name + ["%s - East"] = "%s - 东", -- Dire Maul + ["%s - West"] = "%s - 西", -- Dire Maul + ["%s - North"] = "%s - 北", -- Dire Maul + ["%s - Back Entrance"] = "%s - 后门", -- Stormwrought Ruins, Uldaman + ["Lower %s"] = "%s下层", -- Lower Blackrock Spire + ["Upper %s"] = "%s上层", -- Upper Blackrock Spire + ["%s - Armory"] = "%s - 军械库", -- Scarlet Monastery + ["%s - Cathedral"] = "%s - 大教堂", -- Scarlet Monastery + ["%s - Graveyard"] = "%s - 墓地", -- Scarlet Monastery + ["%s - Library"] = "%s - 图书馆", -- Scarlet Monastery + ["%s - Back Gate"] = "%s - 后门", -- Stratholme + ["%s - Horde Entrance"] = "%s - 部落入口", -- Stormwind Vault + ["%s - Main Entrance"] = "%s - 主入口", -- Uldaman + + -- Transport masks + -- %s will get substituted with the destination's localized name + ["Boat to %s"] = "乘船前往%s", + ["Zeppelin to %s"] = "乘飞艇前往%s", + ["Tram to %s"] = "地铁前往%s", -- Tooltip labels ["Level"] = "等级", diff --git a/Localization.lua b/Localization.lua index 0a95d27..4033b32 100644 --- a/Localization.lua +++ b/Localization.lua @@ -1,77 +1,117 @@ ---- Localization.lua - ModernMapMarkers Localization Core ---- Provides zone name reverse-lookup (localized -> English) and ---- marker name translation (English -> localized) for non-English clients. - -ModernMapMarkers_Locale = {} - --- Registered locale tables: ["deDE"] = { Zones = {}, Markers = {} }, ... -local LocaleData = {} - --- Active locale tables (set on VARIABLES_LOADED) -local ActiveZones = nil -- English -> Localized zone names -local ReverseZones = nil -- Localized -> English zone names -local ActiveMarkers = nil -- English -> Localized marker/instance names - -local detectedLocale = nil - ---- Register a locale's zone translations. -function ModernMapMarkers_Locale:RegisterZones(locale, tbl) - if not LocaleData[locale] then LocaleData[locale] = {} end - LocaleData[locale].Zones = tbl -end - ---- Register a locale's marker/instance name translations. -function ModernMapMarkers_Locale:RegisterMarkers(locale, tbl) - if not LocaleData[locale] then LocaleData[locale] = {} end - LocaleData[locale].Markers = tbl -end - -function ModernMapMarkers_Locale:Initialize() - detectedLocale = GetLocale() or "enUS" - - local data = LocaleData[detectedLocale] - - if data and data.Zones then - ActiveZones = data.Zones - ReverseZones = {} - for eng, loc in pairs(ActiveZones) do - ReverseZones[loc] = eng - end - end - - if data and data.Markers then - ActiveMarkers = data.Markers - end -end - ---- Given a localized zone name (from GetMapZones), return the English key ---- used in MarkerData.lua. Returns the input unchanged for enUS or unknown names. -function ModernMapMarkers_Locale:GetEnglishZoneName(localizedName) - if ReverseZones and ReverseZones[localizedName] then - return ReverseZones[localizedName] - end - return localizedName -end - ---- Given an English zone name, return the localized display name. ---- Falls back to the English name if no translation exists. -function ModernMapMarkers_Locale:GetLocalizedZoneName(englishName) - if ActiveZones and ActiveZones[englishName] then - return ActiveZones[englishName] - end - return englishName -end - ---- Given an English marker/instance name, return the localized display name. ---- Falls back to the English name if no translation exists. -function ModernMapMarkers_Locale:GetLocalizedMarkerName(englishName) - if ActiveMarkers and ActiveMarkers[englishName] then - return ActiveMarkers[englishName] - end - return englishName -end - -function ModernMapMarkers_Locale:GetLocale() - return detectedLocale or "enUS" - -end +--- Localization.lua - ModernMapMarkers Localization Core +--- Provides zone name reverse-lookup (localized -> English) and +--- all other translations (English -> localized) for non-English clients. See ./Locales + +ModernMapMarkers_Locale = {} + +-- Registered locale tables: ["deDE"] = { Zones = {}, Markers = {} }, ... +local LocaleData = {} + +-- Active locale tables (set on VARIABLES_LOADED) +local Dictionary = nil -- English -> Localized + +local detectedLocale = nil + +--- Register a locale's dictionary containing all translations from ./Locales/Locale_xxXX.lua +function ModernMapMarkers_Locale:RegisterDictionary(locale, tbl) + if not LocaleData[locale] then LocaleData[locale] = {} end + LocaleData[locale].Dictionary = tbl +end + +function ModernMapMarkers_Locale:Initialize() + detectedLocale = GetLocale() + if not detectedLocale or detectedLocale == "enGB" then + detectedLocale = "enUS" -- trusty enUS fallback. working out greatly atm + end + + local data = LocaleData[detectedLocale] + if data and data.Dictionary then + Dictionary = data.Dictionary + end +end + +--- Given a localized zone name (from GetMapZones), return the English key +--- used in MarkerData.lua. Returns the input unchanged for enUS or unknown names. +function ModernMapMarkers_Locale:GetEnglishZoneName(localizedName) + local zoneId = MMM_PfDBHelper:GetZoneId(localizedName, detectedLocale) + if not zoneId then + return localizedName + end + local zoneName = MMM_PfDBHelper:GetZoneName(zoneId, "enUS") + --self:Print("GetEnglishZoneName - localizedName: '" .. tostring(localizedName) .. "' --> '" .. tostring(zoneName) .. "'(id:" .. zoneId .. ")") + return zoneName +end + +--- Given an English zone name, return the localized display name. +--- Falls back to the English name if no translation exists. +function ModernMapMarkers_Locale:GetLocalizedZoneName(englishName) + local zoneId = MMM_PfDBHelper:GetZoneId(englishName, "enUS") + if not zoneId then + return englishName + end + local zoneName = MMM_PfDBHelper:GetZoneName(zoneId, detectedLocale) + --self:Print("GetLocalizedZoneName - englishName: '" .. tostring(englishName) .. "' --> '" .. tostring(zoneName) .. "'(id:" .. zoneId .. ")") + return zoneName +end + +--- Given an English string, returns the localized equivalent, either from pfDB or the Dictionary. Applies a string mask. +--- Falls back to the English name if no translation exists. +-- englishName : the string in English +-- type : type can be "dungeon", "raid", "worldboss", "boat", "zepp", "tram" +-- mask : string mask that should be applied like "Boat to %s" +function ModernMapMarkers_Locale:GetLocalizedString(englishName, type, mask) + --self:Print("GetLocalizedString - englishName: " .. tostring(englishName) .. ", type: " .. tostring(type) .. ", mask: " .. tostring(mask)) + local localizedName = nil + if not mask then -- see if we automatically need to choose a mask because of the type + if type == "BOAT" then + mask = "Boat to %s" + elseif type == "ZEPP" or type == "ZEPPELIN" then + mask = "Zeppelin to %s" + elseif type == "TRAM" then + mask = "Tram to %s" + end + end + if Dictionary then + local englishNameEnglishMask = englishName + if mask then -- apply non-localized english mask if it exists + englishNameEnglishMask = string.format(mask, englishName) + end + if Dictionary[englishNameEnglishMask] then + return Dictionary[englishNameEnglishMask] -- we have a custom translation for this string, use it + end + end + if type == "WORLDBOSS" then -- worldboss is the only type that is a unit name + local unitId = MMM_PfDBHelper:GetUnitId(englishName, "enUS") -- first we get the unit id from pfDB + if unitId then + localizedName = MMM_PfDBHelper:GetUnitName(unitId, detectedLocale) -- now get localized unit name from pfDB + end + else -- all other types are zone names + local zoneId = MMM_PfDBHelper:GetZoneId(englishName, "enUS") -- first we get the zone id from pfDB + if zoneId then + localizedName = MMM_PfDBHelper:GetZoneName(zoneId, detectedLocale) -- get localized zone name from pfDB + end + end + if not localizedName and Dictionary then -- couldn't find it in zone or unit tables, try to get custom translation from ./Locales + localizedName = Dictionary[englishName] + end + if mask then -- apply mask + local localizedMask = mask + if Dictionary and Dictionary[mask] then + localizedMask = Dictionary[mask] -- we have a localized mask + end + if localizedName then -- all good. we have a localized name + localizedName = string.format(localizedMask, localizedName) + else -- second best option. we have no localized name. fallback to english name + localizedName = string.format(localizedMask, englishName) + end + end + if not localizedName then -- couldn't find anything anywhere. fall back to original english name + localizedName = englishName + end + return localizedName +end + +-- Safe call helper for listener +function ModernMapMarkers_Locale:Print(msg) + DEFAULT_CHAT_FRAME:AddMessage("ModernMapMarkers_Locale: " .. tostring(msg)) +end \ No newline at end of file diff --git a/MarkerData.lua b/MarkerData.lua index 8857aa0..1938ccb 100644 --- a/MarkerData.lua +++ b/MarkerData.lua @@ -14,31 +14,33 @@ ModernMapMarkers_Points = { { x=0.385, y=0.34, name="Timbermaw Hold", type="raid", info="60" }, }, ["Darkshore"] = { - { x=0.324, y=0.44, name="Boat to Stormwind", type="boat", info="Alliance" }, - { x=0.304, y=0.41, name="Boat to Alah'Thalas", type="boat", info="Alliance" }, - { x=0.333, y=0.399, name="Boat to Rut'Theran Village", type="boat", info="Alliance" }, + { x=0.324, y=0.44, name="Stormwind City", destContinentId=2, destZone="Stormwind City", type="boat", info="Alliance" }, + { x=0.304, y=0.41, name="Alah'Thalas", destContinentId=2, destZone="Alah'Thalas", type="boat", info="Alliance" }, + { x=0.333, y=0.399, name="Rut'theran Village", destContinentId=1, destZone="Teldrassil", type="boat", info="Alliance" }, }, ["Desolace"] = { { x=0.29, y=0.629, name="Maraudon", type="dungeon", info="46-55" }, { x=0.82, y=0.80, name="Concavius", type="worldboss", info="60" }, - { x=0.205, y=0.75, name="Boat to Moonhoof Village", type="boat", info="Horde" }, + { x=0.205, y=0.75, name="Moonhoof Village", destContinentId=1, destZone="Moonwhisper Coast", type="boat", info="Horde" }, }, ["Durotar"] = { - { x=0.512, y=0.135, name="Zeppelins to UC & Grom'Gol", type="zepp", info="Horde" }, - { x=0.415, y=0.184, name="Zeppelins to TB & Kargath", type="zepp", info="Horde" }, - { x=0.598, y=0.236, name="Boat to Revantusk Village", type="boat", info="Horde" }, + { x=0.508, y=0.15, name="Undercity", destContinentId=2, destZone="Tirisfal Glades", type="zepp", info="Horde" }, + { x=0.505, y=0.124, name="Grom'gol Base Camp", destContinentId=2, destZone="Stranglethorn Vale", type="zepp", info="Horde" }, + { x=0.412, y=0.195, name="Thunder Bluff", destContinentId=1, destZone="Thunder Bluff", type="zepp", info="Horde" }, + { x=0.413, y=0.165, name="Kargath", destContinentId=2, destZone="Badlands", type="zepp", info="Horde" }, + { x=0.598, y=0.236, name="Revantusk Village", destContinentId=2, destZone="The Hinterlands", type="boat", info="Horde" }, }, ["Dustwallow Marsh"] = { { x=0.53, y=0.76, name="Onyxia's Lair", type="raid", info="60" }, - { x=0.718, y=0.566, name="Boat to Menethil Harbor", type="boat", info="Alliance" }, + { x=0.718, y=0.566, name="Menethil Harbor", destContinentId=2, destZone="Wetlands", type="boat", info="Alliance" }, }, ["Feralas"] = { - { x=0.648, y=0.303, name="Dire Maul - East", type="dungeon", info="55-58" }, - { x=0.624, y=0.249, name="Dire Maul - North", type="dungeon", info="57-60" }, - { x=0.604, y=0.311, name="Dire Maul - West", type="dungeon", info="57-60" }, + { x=0.648, y=0.303, name="Dire Maul", mask="%s - East", type="dungeon", info="55-58" }, + { x=0.624, y=0.249, name="Dire Maul", mask="%s - North", type="dungeon", info="57-60" }, + { x=0.604, y=0.311, name="Dire Maul", mask="%s - West", type="dungeon", info="57-60" }, { x=0.512, y=0.108, name="Lethon", type="worldboss", info="60" }, - { x=0.311, y=0.395, name="Boat to Forgotten Coast", type="boat", info="Alliance" }, - { x=0.431, y=0.428, name="Boat to Sardor Isle", type="boat", info="Alliance" }, + { x=0.311, y=0.395, name="The Forgotten Coast", type="boat", info="Alliance" }, + { x=0.431, y=0.428, name="Sardor Isle", type="boat", info="Alliance" }, }, ["Hyjal"] = { { x=0.207, y=0.592, name="Emerald Sanctum", type="raid", info="60" }, @@ -46,22 +48,22 @@ ModernMapMarkers_Points = { }, ["Moonwhisper Coast"] = { { x=0.506, y=0.959, name="Timbermaw Hold", type="raid", info="60" }, - { x=0.71, y=0.38, name="Boat to Shadowprey Village", type="boat", info="Horde" }, + { x=0.71, y=0.38, name="Shadowprey Village", destContinentId=1, destZone="Desolace", type="boat", info="Horde" }, }, ["Orgrimmar"] = { { x=0.53, y=0.486, name="Ragefire Chasm", type="dungeon", info="13-18" }, }, ["Silithus"] = { { x=0.296, y=0.960, name="Ruins of Ahn'Qiraj", type="raid", info="60" }, - { x=0.282, y=0.956, name="Temple of Ahn'Qiraj", type="raid", info="60" }, + { x=0.282, y=0.956, name="Ahn'Qiraj", type="raid", info="60" }, }, ["Tanaris"] = { - { x=0.66, y=0.49, name="Black Morass", type="dungeon", info="60" }, + { x=0.66, y=0.49, name="The Black Morass", type="dungeon", info="60" }, { x=0.389, y=0.184, name="Zul'Farrak", type="dungeon", info="44-54" }, { x=0.361, y=0.762, name="Ostarius", type="worldboss", info="60" }, }, ["Teldrassil"] = { - { x=0.552, y=0.949, name="Boat to Auberdine", type="boat", info="Alliance" }, + { x=0.552, y=0.949, name="Auberdine", destContinentId=1, destZone="Darkshore", type="boat", info="Alliance" }, }, ["Thousand Needles"] = { { x=0.648, y=0.460, name="Windhorn Canyon", type="dungeon", info="26-30" }, @@ -70,24 +72,24 @@ ModernMapMarkers_Points = { { x=0.488, y=0.919, name="Razorfen Downs", type="dungeon", info="37-46" }, { x=0.407, y=0.873, name="Razorfen Kraul", type="dungeon", info="29-38" }, { x=0.462, y=0.357, name="Wailing Caverns", type="dungeon", info="17-24" }, - { x=0.636, y=0.389, name="Boat to Booty Bay", type="boat", info="Neutral" }, + { x=0.644, y=0.388, name="Booty Bay", destContinentId=2, destZone="Stranglethorn Vale", type="boat", info="Neutral" }, }, ["Thunder Bluff"] = { - { x=0.165, y=0.230, name="Zeppelin to Orgrimmar", type="zepp", info="Horde" }, + { x=0.165, y=0.230, name="Orgrimmar", destContinentId=1, destZone="Durotar", type="zepp", info="Horde" }, }, }, [2] = { -- Eastern Kingdoms ["Alah'Thalas"] = { - { x=0.531, y=0.047, name="Boat to Auberdine", type="boat", info="Alliance" }, + { x=0.531, y=0.047, name="Auberdine", destContinentId=1, destZone="Darkshore", type="boat", info="Alliance" }, }, ["Badlands"] = { - { x=0.429, y=0.130, name="Uldaman - Main Entrance", type="dungeon", info="41-51" }, - { x=0.657, y=0.438, name="Uldaman - Back Entrance", type="dungeon", info="41-51" }, - { x=0.075, y=0.480, name="Zeppelin to Orgrimmar", type="zepp", info="Horde" }, + { x=0.429, y=0.130, name="Uldaman", mask="%s - Main Entrance", type="dungeon", info="41-51" }, + { x=0.657, y=0.438, name="Uldaman", mask="%s - Back Entrance", type="dungeon", info="41-51" }, + { x=0.075, y=0.480, name="Orgrimmar", destContinentId=1, destZone="Durotar", type="zepp", info="Horde" }, }, ["Balor"] = { { x=0.57, y=0.598, name="Stormwrought Ruins", type="dungeon", info="35-41" }, - { x=0.561, y=0.846, name="Stormwrought Ruins - Back Entrance", type="dungeon", info="35-41" }, + { x=0.561, y=0.846, name="Stormwrought Ruins", mask="%s - Back Entrance", type="dungeon", info="35-41" }, }, ["Blasted Lands"] = { { x=0.36, y=0.753, name="Lord Kazzak", type="worldboss", info="60" }, @@ -95,8 +97,8 @@ ModernMapMarkers_Points = { ["Burning Steppes"] = { { x=0.328, y=0.362, name="Blackrock Depths", type="dungeon", info="52-60" }, { x=0.95, y=0.53, name="Hateforge Quarry", type="dungeon", info="52-60" }, - { x=0.321, y=0.386, name="Lower Blackrock Spire", type="dungeon", info="55-60" }, - { x=0.312, y=0.365, name="Upper Blackrock Spire", type="dungeon", info="55-60" }, + { x=0.321, y=0.386, name="Blackrock Spire", mask="Lower %s", type="dungeon", info="55-60" }, + { x=0.312, y=0.365, name="Blackrock Spire", mask="Upper %s", type="dungeon", info="55-60" }, { x=0.273, y=0.363, name="Blackwing Lair", type="raid", info="60" }, { x=0.273, y=0.387, name="Molten Core", type="raid", info="60" }, }, @@ -115,23 +117,23 @@ ModernMapMarkers_Points = { }, ["Eastern Plaguelands"] = { { x=0.31, y=0.14, name="Stratholme", type="dungeon", info="58-60" }, - { x=0.47, y=0.24, name="Stratholme - Back Gate", type="dungeon", info="58-60" }, + { x=0.47, y=0.24, name="Stratholme", mask="%s - Back Gate", type="dungeon", info="58-60" }, { x=0.40, y=0.28, name="Naxxramas", type="raid", info="60" }, { x=0.082, y=0.38, name="Nerubian Overseer", type="worldboss", info="60" }, }, ["Elwynn Forest"] = { - { x=0.29, y=0.61, name="Stormwind Vault - Horde Entrance", type="dungeon", info="60" }, + { x=0.29, y=0.61, name="Stormwind Vault", mask="%s - Horde Entrance", type="dungeon", info="60" }, }, ["Gilneas"] = { { x=0.30, y=0.27, name="Gilneas City", type="dungeon", info="43" }, }, ["Ironforge"] = { - { x=0.762, y=0.511, name="Tram to Stormwind", type="tram", info="Alliance" }, + { x=0.762, y=0.511, name="Stormwind City", destContinentId=2, destZone="Stormwind City", type="tram", info="Alliance" }, }, ["Searing Gorge"] = { { x=0.371, y=0.857, name="Blackrock Depths", type="dungeon", info="52-60" }, - { x=0.364, y=0.879, name="Lower Blackrock Spire", type="dungeon", info="55-60" }, - { x=0.355, y=0.855, name="Upper Blackrock Spire", type="dungeon", info="55-60" }, + { x=0.364, y=0.879, name="Blackrock Spire", mask="Lower %s", type="dungeon", info="55-60" }, + { x=0.355, y=0.855, name="Blackrock Spire", mask="Upper %s", type="dungeon", info="55-60" }, { x=0.332, y=0.851, name="Blackwing Lair", type="raid", info="60" }, { x=0.336, y=0.879, name="Molten Core", type="raid", info="60" }, }, @@ -141,27 +143,29 @@ ModernMapMarkers_Points = { ["Stormwind City"] = { { x=0.51, y=0.675, name="The Stockade", type="dungeon", info="24-31" }, { x=0.63, y=0.58, name="Stormwind Vault", type="dungeon", info="60" }, - { x=0.694, y=0.294, name="Tram to Ironforge", type="tram", info="Alliance" }, - { x=0.218, y=0.563, name="Boat to Auberdine", type="boat", info="Alliance" }, + { x=0.694, y=0.294, name="Ironforge", destContinentId=2, destZone="Ironforge", type="tram", info="Alliance" }, + { x=0.218, y=0.563, name="Auberdine", destContinentId=1, destZone="Darkshore", type="boat", info="Alliance" }, }, ["Stranglethorn Vale"] = { { x=0.53, y=0.172, name="Zul'Gurub", type="raid", info="60" }, - { x=0.257, y=0.73, name="Boat to Ratchet", type="boat", info="Neutral" }, - { x=0.312, y=0.298, name="Zeppelins to UC & Orgrimmar", type="zepp", info="Horde" }, + { x=0.259, y=0.731, name="Ratchet", destContinentId=1, destZone="The Barrens", type="boat", info="Neutral" }, + { x=0.310, y=0.280, name="Undercity", destContinentId=2, destZone="Tirisfal Glades", type="zepp", info="Horde" }, + { x=0.308, y=0.304, name="Orgrimmar", destContinentId=1, destZone="Durotar", type="zepp", info="Horde" }, }, ["Swamp of Sorrows"] = { - { x=0.701, y=0.55, name="The Sunken Temple", type="dungeon", info="50-60" }, + { x=0.701, y=0.55, name="Sunken Temple", type="dungeon", info="50-60" }, }, ["The Hinterlands"] = { { x=0.632, y=0.217, name="Ysondre", type="worldboss", info="60" }, - { x=0.812, y=0.794, name="Boat to Sparkwater Port", type="boat", info="Horde" }, + { x=0.812, y=0.794, name="Sparkwater Port", destContinentId=1, destZone="Durotar", type="boat", info="Horde" }, }, ["Tirisfal Glades"] = { - { x=0.869, y=0.323, name="Scarlet Monastery - Armory", type="dungeon", info="32-42" }, - { x=0.862, y=0.295, name="Scarlet Monastery - Cathedral", type="dungeon", info="35-45" }, - { x=0.839, y=0.283, name="Scarlet Monastery - Graveyard", type="dungeon", info="26-36" }, - { x=0.850, y=0.338, name="Scarlet Monastery - Library", type="dungeon", info="29-39" }, - { x=0.616, y=0.571, name="Zeppelins to Orgrimmar & Grom'Gol", type="zepp", info="Horde" }, + { x=0.869, y=0.323, name="Scarlet Monastery", mask="%s - Armory", type="dungeon", info="32-42" }, + { x=0.862, y=0.295, name="Scarlet Monastery", mask="%s - Cathedral", type="dungeon", info="35-45" }, + { x=0.839, y=0.283, name="Scarlet Monastery", mask="%s - Graveyard", type="dungeon", info="26-36" }, + { x=0.850, y=0.338, name="Scarlet Monastery", mask="%s - Library", type="dungeon", info="29-39" }, + { x=0.595, y=0.575, name="Orgrimmar", destContinentId=1, destZone="Durotar", type="zepp", info="Horde" }, + { x=0.615, y=0.575, name="Grom'gol Base Camp", destContinentId=2, destZone="Stranglethorn Vale", type="zepp", info="Horde" }, }, ["Western Plaguelands"] = { { x=0.69, y=0.74, name="Scholomance", type="dungeon", info="58-60" }, @@ -171,7 +175,7 @@ ModernMapMarkers_Points = { }, ["Wetlands"] = { { x=0.67, y=0.634, name="Dragonmaw Retreat", type="dungeon", info="27-33" }, - { x=0.068, y=0.613, name="Boat to Theramore Isle", type="boat", info="Alliance" }, + { x=0.068, y=0.613, name="Theramore Isle", destContinentId=1, destZone="Dustwallow Marsh", type="boat", info="Alliance" }, }, } } diff --git a/ModernMapMarkers.lua b/ModernMapMarkers.lua index a6a0220..ea2355b 100644 --- a/ModernMapMarkers.lua +++ b/ModernMapMarkers.lua @@ -1,655 +1,657 @@ -local MMM = CreateFrame("Frame", "ModernMapMarkersCore", UIParent) -MMM.markers = {} -MMM.Data = {} -MMM.ZoneMarkers = {} -MMM.FlatDropdownData = nil -MMM.ijInstalled = false - --- Localization shorthand -local L = ModernMapMarkers_Locale - --- Filter constants -local ALL_TYPES = { "DUNGEON", "RAID", "WORLDBOSS", "BOAT", "ZEPPELIN", "TRAM" } - --- InstanceJournal Integration --- MMM markers to hide when IJ is installed (covered by IJ POI entrances) -local IJ_HIDDEN_MARKERS = { - ["Blackrock Depths"] = true, - ["Lower Blackrock Spire"] = true, - ["Upper Blackrock Spire"] = true, - ["Blackwing Lair"] = true, - ["Molten Core"] = true, - ["Dire Maul - East"] = true, - ["Dire Maul - North"] = true, - ["Dire Maul - West"] = true, - ["Black Morass"] = true, - ["The Deadmines"] = true, - ["Temple of Ahn'Qiraj"] = true, - ["Ruins of Ahn'Qiraj"] = true, - ["Gnomeregan"] = true, - ["Maraudon"] = true, - ["Scarlet Monastery - Armory"] = true, - ["Scarlet Monastery - Cathedral"] = true, - ["Scarlet Monastery - Graveyard"] = true, - ["Scarlet Monastery - Library"] = true, - ["Uldaman - Main Entrance"] = true, - ["Uldaman - Back Entrance"] = true, - ["Wailing Caverns"] = true, - ["Windhorn Canyon"] = true, - ["Timbermaw Hold"] = true, -} - --- Map MMM marker names to IJ database keys for click behavior --- { db = "DG" or "R", key = IJDB key } -local MMM_TO_IJ = { - -- Dungeons - ["Blackfathom Deeps"] = { db = "DG", key = "BFD" }, - ["Crescent Grove"] = { db = "DG", key = "CG" }, - ["Ragefire Chasm"] = { db = "DG", key = "RFC" }, - ["Razorfen Downs"] = { db = "DG", key = "RFD" }, - ["Razorfen Kraul"] = { db = "DG", key = "RFK" }, - ["Zul'Farrak"] = { db = "DG", key = "ZF" }, - ["Shadowfang Keep"] = { db = "DG", key = "SFK" }, - ["The Stockade"] = { db = "DG", key = "STOCKADES" }, - ["Stormwind Vault"] = { db = "DG", key = "SV" }, - ["Stormwind Vault - Horde Entrance"] = { db = "DG", key = "SV" }, - ["Stratholme"] = { db = "DG", key = "STRAT" }, - ["Stratholme - Back Gate"] = { db = "DG", key = "STRAT" }, - ["Scholomance"] = { db = "DG", key = "SCHOLO" }, - ["The Sunken Temple"] = { db = "DG", key = "ST" }, - ["Hateforge Quarry"] = { db = "DG", key = "HQ" }, - ["Dragonmaw Retreat"] = { db = "DG", key = "DMR" }, - ["Karazhan Crypt"] = { db = "DG", key = "KC" }, - ["Lower Blackrock Spire"] = { db = "DG", key = "LBRS" }, - ["Upper Blackrock Spire"] = { db = "DG", key = "UBRS" }, - ["Gilneas City"] = { db = "DG", key = "GC" }, - ["Stormwrought Ruins"] = { db = "DG", key = "SWR" }, - ["Stormwrought Ruins - Back Entrance"] = { db = "DG", key = "SWR" }, - ["Frostmane Hollow"] = { db = "DG", key = "FH" }, - ["Windhorn Canyon"] = { db = "DG", key = "WHC" }, - -- Raids - ["Onyxia's Lair"] = { db = "R", key = "ONY" }, - ["Emerald Sanctum"] = { db = "R", key = "ES" }, - ["Lower Karazhan Halls"] = { db = "R", key = "KARA10" }, - ["Blackwing Lair"] = { db = "R", key = "BWL" }, - ["Tower of Karazhan"] = { db = "R", key = "KARA40" }, - ["Naxxramas"] = { db = "R", key = "NAXX" }, - ["Zul'Gurub"] = { db = "R", key = "ZG" }, - ["Timbermaw Hold"] = { db = "R", key = "TH" }, -} - --- Keep POI submap zone markers -local IJ_SUBMAP_ZONES = {} - --- Default filters -MMM.filters = { - DUNGEON = true, - RAID = true, - BOAT = true, - ZEPPELIN = true, - TRAM = true, - WORLDBOSS = true, - FACTION = "ALL" -} - --- Dirty-check state for RefreshMarkers -local lastContinent = nil -local lastZone = nil -local forceRefresh = false - --- Textures -local TEX_BASE = "Interface\\AddOns\\ModernMapMarkers\\Textures\\" -local TEXTURE_MAP = { - DUNGEON = TEX_BASE .. "dungeon.tga", - RAID = TEX_BASE .. "raid.tga", - BOAT = TEX_BASE .. "boat.tga", - ZEPPELIN = TEX_BASE .. "zepp.tga", - TRAM = TEX_BASE .. "tram.tga", - WORLDBOSS = TEX_BASE .. "worldboss.tga", -} -local HIGHLIGHT_MAP = { - DUNGEON = TEX_BASE .. "dungeon-highlight.tga", - RAID = TEX_BASE .. "raid-highlight.tga", -} - --- Zone name cache -local ZONE_CACHE = {} -function MMM:CacheZones() - ZONE_CACHE[1] = { GetMapZones(1) } -- Kalimdor - ZONE_CACHE[2] = { GetMapZones(2) } -- Eastern Kingdoms -end - --- Map multi-entrance dungeons to a single zone -local CANONICAL_ZONE = { - ["Blackrock Depths"] = "Burning Steppes", - ["Lower Blackrock Spire"] = "Burning Steppes", - ["Upper Blackrock Spire"] = "Burning Steppes", - ["Blackwing Lair"] = "Burning Steppes", - ["Molten Core"] = "Burning Steppes", - ["Stormwind Vault"] = "Stormwind City", - ["Timbermaw Hold"] = "Azshara", -} - --- Data Parsing -function MMM:BuildData() - if self.dataBuilt then return end - if not ModernMapMarkers_Points then return end - - MMM.Data = {} - MMM.ZoneMarkers = {} - - local index = 1 - - for contID, zones in pairs(ModernMapMarkers_Points) do - MMM.ZoneMarkers[contID] = MMM.ZoneMarkers[contID] or {} - - for zoneName, markers in pairs(zones) do - MMM.ZoneMarkers[contID][zoneName] = {} - - for _, m in ipairs(markers) do - local typeUpper = string.upper(m.type or "UNKNOWN") - if typeUpper == "ZEPP" then typeUpper = "ZEPPELIN" end - - local markerData = { - continent = contID, - zoneName = zoneName, - x = m.x, - y = m.y, - name = m.name, - type = typeUpper, - description = m.info, - id = index - } - - table.insert(MMM.Data, markerData) - table.insert(MMM.ZoneMarkers[contID][zoneName], markerData) - - index = index + 1 - end - end - end - self.dataBuilt = true -end - --- Get deduplicated data for dropdowns -function ModernMapMarkers_GetFlatData() - MMM:BuildData() - - if MMM.FlatDropdownData then return MMM.FlatDropdownData end - - local filteredData = {} - local seenNames = {} - - for _, data in ipairs(MMM.Data) do - if data.type == "DUNGEON" or data.type == "RAID" or data.type == "WORLDBOSS" then - local baseName = data.name or "" - - local dashIndex = string.find(baseName, " %- ") - if dashIndex then - baseName = string.sub(baseName, 1, dashIndex - 1) - end - - local existingIndex = seenNames[baseName] - if not existingIndex then - local dropData = {} - for k, v in pairs(data) do dropData[k] = v end - dropData.name = baseName - table.insert(filteredData, dropData) - seenNames[baseName] = table.getn(filteredData) - else - local canon = CANONICAL_ZONE[baseName] - if canon and data.zoneName == canon then - local dropData = {} - for k, v in pairs(data) do dropData[k] = v end - dropData.name = baseName - filteredData[existingIndex] = dropData - end - end - end - end - - MMM.FlatDropdownData = filteredData - return filteredData -end - --- Drawing Logic -function MMM:RefreshMarkers() - if not WorldMapFrame:IsVisible() then return end - - self:BuildData() - - local currentContinent = GetCurrentMapContinent() - local currentZone = GetCurrentMapZone() - - -- Dirty-check: skip full redraw if zone hasn't changed and no force refresh - if not forceRefresh - and currentContinent == lastContinent - and currentZone == lastZone then - return - end - - lastContinent = currentContinent - lastZone = currentZone - forceRefresh = false - - if currentContinent == 0 or currentZone == 0 then - self:HideAllMarkers() - return - end - - local zoneNames = ZONE_CACHE[currentContinent] - local currentZoneName = zoneNames and zoneNames[currentZone] - if not currentZoneName then - self:HideAllMarkers() - return - end - - -- Translate localized zone name to English key used in MarkerData - local englishZoneName = L:GetEnglishZoneName(currentZoneName) - - local zoneMarkers = MMM.ZoneMarkers[currentContinent] and MMM.ZoneMarkers[currentContinent][englishZoneName] - - local markerIndex = 0 - - if zoneMarkers then - for _, data in ipairs(zoneMarkers) do - - local showMarker = (MMM.filters[data.type] == true) - - -- Hide markers replaced by InstanceJournal - if showMarker and MMM.ijInstalled then - if data.type == "WORLDBOSS" then - showMarker = false - elseif IJ_HIDDEN_MARKERS[data.name] then - showMarker = false - end - end - - -- Check faction filter - if showMarker and (data.type == "BOAT" or data.type == "ZEPPELIN" or data.type == "TRAM") then - if MMM.filters.FACTION ~= "ALL" - and data.description ~= "Neutral" - and data.description ~= MMM.filters.FACTION then - showMarker = false - end - end - - if showMarker then - markerIndex = markerIndex + 1 - local marker = self:GetOrCreateMarker(markerIndex) - - -- Sizing - if data.type == "DUNGEON" or data.type == "RAID" or data.type == "WORLDBOSS" then - marker:SetWidth(32) - marker:SetHeight(32) - else - marker:SetWidth(24) - marker:SetHeight(24) - end - - -- Position - local width = WorldMapDetailFrame:GetWidth() - local height = WorldMapDetailFrame:GetHeight() - marker:SetPoint("CENTER", WorldMapDetailFrame, "TOPLEFT", data.x * width, -data.y * height) - - -- Texture - local tex = TEXTURE_MAP[data.type] or "Interface\\Minimap\\POIIcons" - if marker.lastTexture ~= tex then - marker.texture:SetTexture(tex) - marker.lastTexture = tex - end - - local hlTex = HIGHLIGHT_MAP[data.type] - if marker.lastHighlight ~= hlTex then - if hlTex then - marker:SetHighlightTexture(hlTex) - elseif marker.lastHighlight then - marker:SetHighlightTexture("") - end - marker.lastHighlight = hlTex - end - - -- Metadata - marker.name = L:GetLocalizedMarkerName(data.name) - marker.nameEN = data.name - marker.description = data.description - marker.markerType = data.type - marker.continent = data.continent - marker.zoneName = data.zoneName - - marker:Show() - end - end - end - - -- Hide any excess markers from the previous zone - self:HideMarkersFrom(markerIndex + 1) -end - --- Hide all markers in the pool -function MMM:HideAllMarkers() - self:HideMarkersFrom(1) -end - --- Hide markers from startIndex onwards -function MMM:HideMarkersFrom(startIndex) - for i = startIndex, table.getn(self.markers) do - if self.markers[i] then - self.markers[i]:Hide() - end - end -end - --- Invalidate dirty-check so next RefreshMarkers does a full redraw -function MMM:InvalidateCache() - forceRefresh = true -end - --- Get IJ instance from MMM marker English name -function MMM:GetIJInstance(nameEN) - if not MMM.ijInstalled or not nameEN then return nil end - local mapping = MMM_TO_IJ[nameEN] - if not mapping then return nil end - local dbTable = (mapping.db == "R") and IJDB.R or IJDB.DG - if not dbTable then return nil end - return dbTable[mapping.key] -end - --- InstanceJournal Integration -function MMM:OnMarkerClick(marker, button) - if not MMM.ijInstalled then return end - - local instance = MMM:GetIJInstance(marker.nameEN) - if not instance then return end - - if button == "RightButton" then - -- Right-click: open IJ journal page - if not IJ_InstanceJournalFrame:IsShown() then - IJ_InstanceJournalFrame:Show() - end - if instance.Type == IJLib.InstanceType.Raid then - IJ_ShowRaids = true - PanelTemplates_SetTab(IJ_InstanceJournalFrame, 2) - else - IJ_ShowRaids = false - PanelTemplates_SetTab(IJ_InstanceJournalFrame, 1) - end - IJ_ShowEncounter(instance) - WorldMapFrame:Hide() - else - -- Left-click: navigate to instance submap - SetMapZoom(tonumber(instance.MapId), 1) - end -end - --- Marker Pool -function MMM:GetOrCreateMarker(index) - if not self.markers[index] then - local marker = CreateFrame("Button", "ModernMapMarkerIcon"..index, WorldMapButton) - marker:SetWidth(24) - marker:SetHeight(24) - marker:SetFrameLevel(WorldMapButton:GetFrameLevel() + 5) - - local tex = marker:CreateTexture(nil, "OVERLAY") - tex:SetAllPoints(marker) - marker.texture = tex - - marker:RegisterForClicks("LeftButtonUp", "RightButtonUp") - marker:SetScript("OnClick", function() MMM:OnMarkerClick(this, arg1) end) - - marker:SetScript("OnEnter", function() - WorldMapTooltip:SetOwner(this, "ANCHOR_RIGHT") - WorldMapTooltip:AddLine(this.name, 1, 0.82, 0) - - if this.description then - if this.markerType == "DUNGEON" or this.markerType == "RAID" or this.markerType == "WORLDBOSS" then - local lvlLabel = L:GetLocalizedMarkerName("Level") or "Level" - WorldMapTooltip:AddLine(lvlLabel .. ": " .. this.description, 1, 1, 1, 1) - elseif this.description == "Alliance" then - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Alliance"), 0.0, 0.47, 1.0, 1) - elseif this.description == "Horde" then - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Horde"), 1.0, 0.0, 0.0, 1) - else - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName(this.description), 1, 1, 1, 1) - end - end - - -- IJ tooltips for dungeon/raid markers - if MMM.ijInstalled and MMM:GetIJInstance(this.nameEN) then - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Left-Click: View Map"), 0.5, 0.5, 0.5) - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Right-Click: Instance Journal"), 0.5, 0.5, 0.5) - end - - WorldMapTooltip:Show() - end) - - marker:SetScript("OnLeave", function() WorldMapTooltip:Hide() end) - - self.markers[index] = marker - end - return self.markers[index] -end - --- Hooks & API -function ModernMapMarkers_SetFilter(key, state) - if key == "ALL" then - for _, t in ipairs(ALL_TYPES) do - MMM.filters[t] = state - end - else - MMM.filters[key] = state - end - MMM:InvalidateCache() - MMM:RefreshMarkers() -end - -function ModernMapMarkers_SetFactionFilter(factionStr) - MMM.filters.FACTION = factionStr - MMM:InvalidateCache() - MMM:RefreshMarkers() -end - -function MMM:GetZoneIndex(continentID, zoneName) - local zones = ZONE_CACHE[continentID] or {} - -- zoneName is English (from MarkerData), ZONE_CACHE has localized names - local localizedName = L:GetLocalizedZoneName(zoneName) - for i, name in ipairs(zones) do - if name == localizedName then return i end - end - -- Fallback: try direct match (for enUS or untranslated zones) - for i, name in ipairs(zones) do - if name == zoneName then return i end - end - return 0 -end - -function ModernMapMarkers_FindMarker(dataIndex) - MMM:BuildData() - local data = MMM.Data[dataIndex] - if not data then return end - - local zoneIndex = MMM:GetZoneIndex(data.continent, data.zoneName) - if zoneIndex > 0 then - SetMapZoom(data.continent, zoneIndex) - end - - if not MMM.filters[data.type] then - MMM.filters[data.type] = true - if ModernMapMarkers_SyncFilterUI then - ModernMapMarkers_SyncFilterUI(data.type, true) - end - end - - MMM:InvalidateCache() - MMM:RefreshMarkers() -end - -local original_WorldMapFrame_Update = WorldMapFrame_Update -function WorldMapFrame_Update() - if original_WorldMapFrame_Update then - original_WorldMapFrame_Update() - end - MMM:RefreshMarkers() -end - -MMM:SetScript("OnEvent", function() - if event == "VARIABLES_LOADED" then - if ModernMapMarkersDB and ModernMapMarkersDB.filters then - for k, v in pairs(ModernMapMarkersDB.filters) do - MMM.filters[k] = v - end - else - -- First load: auto-detect player faction for transport filter - local faction = UnitFactionGroup("player") - if faction == "Alliance" or faction == "Horde" then - MMM.filters.FACTION = faction - end - end - - L:Initialize() - MMM:CacheZones() - MMM:BuildData() - - -- Detect InstanceJournal - if IJDB and IJLib and IJ_ShowInstanceEntrancesIcon then - MMM.ijInstalled = true - - -- Build POI submap zone lookup - if IJDB.POI then - for _, poi in pairs(IJDB.POI) do - if poi.MapContinentId and poi.MapZoneId then - local key = tostring(poi.MapContinentId) .. ":" .. tostring(poi.MapZoneId) - IJ_SUBMAP_ZONES[key] = true - end - end - end - - -- Also include instance entrance locations inside other instance maps - -- (e.g., Molten Core entrance inside BRD submap) - local instanceMapIds = {} - local allInstances = {} - for _, inst in pairs(IJDB.DG or {}) do - if inst.MapId then instanceMapIds[tostring(inst.MapId)] = true end - table.insert(allInstances, inst) - end - for _, inst in pairs(IJDB.R or {}) do - if inst.MapId then instanceMapIds[tostring(inst.MapId)] = true end - table.insert(allInstances, inst) - end - for _, inst in ipairs(allInstances) do - if inst.Entrances then - for _, ent in pairs(inst.Entrances) do - if ent.MapContinentId and ent.MapZoneId - and instanceMapIds[tostring(ent.MapContinentId)] then - local key = tostring(ent.MapContinentId) .. ":" .. tostring(ent.MapZoneId) - IJ_SUBMAP_ZONES[key] = true - end - end - end - end - - -- Hook IJ entrance markers: hide on world zones, keep in POI submaps - -- In submaps, reskin entrance pins with MMM dungeon/raid textures - local original_ShowEntrance = IJ_ShowInstanceEntrancesIcon - IJ_ShowInstanceEntrancesIcon = function(instance) - local key = tostring(GetCurrentMapContinent()) .. ":" .. tostring(GetCurrentMapZone()) - if IJ_SUBMAP_ZONES[key] then - original_ShowEntrance(instance) - - -- Determine marker type and apply MMM filter - local isRaid = instance.Type == IJLib.InstanceType.Raid - local filterKey = isRaid and "RAID" or "DUNGEON" - local mmmTex = isRaid and TEXTURE_MAP.RAID or TEXTURE_MAP.DUNGEON - - local cleanName = string.gsub(instance.Name or "", "%s+", "") - local prefix = "IJ_EntrancePin_" .. cleanName - - for _, pin in ipairs(IJ_CreatedMapInstanceEntrance) do - local pinName = pin:GetName() or "" - if string.find(pinName, prefix, 1, true) and pin:IsVisible() then - -- Hide pin if MMM filter is disabled for this type - if not MMM.filters[filterKey] then - pin:Hide() - end - pin.icon:SetTexture(mmmTex) - pin.mmmInstance = instance - - if not pin.mmmReskinned then - pin.mmmReskinned = true - pin.mmmTexture = mmmTex - - local mmmHL = instance.Type == IJLib.InstanceType.Raid and HIGHLIGHT_MAP.RAID or HIGHLIGHT_MAP.DUNGEON - if mmmHL then - pin:SetHighlightTexture(mmmHL) - end - - local origOnEnter = pin:GetScript("OnEnter") - local origOnLeave = pin:GetScript("OnLeave") - - pin:SetScript("OnEnter", function() - if origOnEnter then origOnEnter() end - this.icon:SetTexture(this.mmmTexture) - - -- MMM tooltip for IJ POI submap markers - local inst = this.mmmInstance - if inst then - WorldMapTooltip:SetOwner(this, "ANCHOR_RIGHT") - WorldMapTooltip:AddLine(inst.Name or "", 1, 0.82, 0) - local minLvl = inst.MinLevel or 0 - local maxLvl = inst.MaxLevel or 0 - local lvlLabel = L:GetLocalizedMarkerName("Level") or "Level" - WorldMapTooltip:AddLine(lvlLabel .. ": " .. minLvl .. "-" .. maxLvl, 1, 1, 1, 1) - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Left-Click: View Map"), 0.5, 0.5, 0.5) - WorldMapTooltip:AddLine(L:GetLocalizedMarkerName("Right-Click: Instance Journal"), 0.5, 0.5, 0.5) - WorldMapTooltip:Show() - end - end) - - pin:SetScript("OnLeave", function() - if origOnLeave then origOnLeave() end - this.icon:SetTexture(this.mmmTexture) - WorldMapTooltip:Hide() - end) - - -- Right click for IJ journal - pin:RegisterForClicks("LeftButtonUp", "RightButtonUp") - local origOnClick = pin:GetScript("OnClick") - pin:SetScript("OnClick", function() - if arg1 == "RightButton" and this.mmmInstance then - local inst = this.mmmInstance - if not IJ_InstanceJournalFrame:IsShown() then - IJ_InstanceJournalFrame:Show() - end - if inst.Type == IJLib.InstanceType.Raid then - IJ_ShowRaids = true - PanelTemplates_SetTab(IJ_InstanceJournalFrame, 2) - else - IJ_ShowRaids = false - PanelTemplates_SetTab(IJ_InstanceJournalFrame, 1) - end - IJ_ShowEncounter(inst) - WorldMapFrame:Hide() - else - if origOnClick then origOnClick() end - end - end) - end - end - end - end - end - end - - MMM:InvalidateCache() - MMM:RefreshMarkers() - - elseif event == "PLAYER_LOGOUT" then - if not ModernMapMarkersDB then ModernMapMarkersDB = {} end - ModernMapMarkersDB.filters = {} - for k, v in pairs(MMM.filters) do - ModernMapMarkersDB.filters[k] = v - end - end -end) -MMM:RegisterEvent("VARIABLES_LOADED") -MMM:RegisterEvent("PLAYER_LOGOUT") +local MMM = CreateFrame("Frame", "ModernMapMarkersCore", UIParent) +MMM.markers = {} +MMM.Data = {} +MMM.ZoneMarkers = {} +MMM.FlatDropdownData = nil +MMM.ijInstalled = false + +-- Localization shorthand +local L = ModernMapMarkers_Locale + +-- Filter constants +local ALL_TYPES = { "DUNGEON", "RAID", "WORLDBOSS", "BOAT", "ZEPPELIN", "TRAM" } + +-- InstanceJournal Integration +-- MMM markers to hide when IJ is installed (covered by IJ POI entrances) +local IJ_HIDDEN_MARKERS = { + ["Blackrock Depths"] = true, + ["Blackrock Spire"] = true, + ["Blackwing Lair"] = true, + ["Molten Core"] = true, + ["Dire Maul"] = true, + ["The Black Morass"] = true, + ["The Deadmines"] = true, + ["Ahn'Qiraj"] = true, + ["Ruins of Ahn'Qiraj"] = true, + ["Gnomeregan"] = true, + ["Maraudon"] = true, + ["Scarlet Monastery"] = true, + ["Uldaman"] = true, + ["Wailing Caverns"] = true, + ["Windhorn Canyon"] = true, + ["Timbermaw Hold"] = true, +} + +-- Map MMM marker names to IJ database keys for click behavior +-- { db = "DG" or "R", key = IJDB key } +local MMM_TO_IJ = { + -- Dungeons + ["Blackfathom Deeps"] = { db = "DG", key = "BFD" }, + ["Crescent Grove"] = { db = "DG", key = "CG" }, + ["Ragefire Chasm"] = { db = "DG", key = "RFC" }, + ["Razorfen Downs"] = { db = "DG", key = "RFD" }, + ["Razorfen Kraul"] = { db = "DG", key = "RFK" }, + ["Zul'Farrak"] = { db = "DG", key = "ZF" }, + ["Shadowfang Keep"] = { db = "DG", key = "SFK" }, + ["The Stockade"] = { db = "DG", key = "STOCKADES" }, + ["Stormwind Vault"] = { db = "DG", key = "SV" }, + ["Stormwind Vault - Horde Entrance"] = { db = "DG", key = "SV" }, + ["Stratholme"] = { db = "DG", key = "STRAT" }, + ["Stratholme - Back Gate"] = { db = "DG", key = "STRAT" }, + ["Scholomance"] = { db = "DG", key = "SCHOLO" }, + ["Sunken Temple"] = { db = "DG", key = "ST" }, + ["Hateforge Quarry"] = { db = "DG", key = "HQ" }, + ["Dragonmaw Retreat"] = { db = "DG", key = "DMR" }, + ["Karazhan Crypt"] = { db = "DG", key = "KC" }, + ["Lower Blackrock Spire"] = { db = "DG", key = "LBRS" }, + ["Upper Blackrock Spire"] = { db = "DG", key = "UBRS" }, + ["Gilneas City"] = { db = "DG", key = "GC" }, + ["Stormwrought Ruins"] = { db = "DG", key = "SWR" }, + ["Stormwrought Ruins - Back Entrance"] = { db = "DG", key = "SWR" }, + ["Frostmane Hollow"] = { db = "DG", key = "FH" }, + ["Windhorn Canyon"] = { db = "DG", key = "WHC" }, + -- Raids + ["Onyxia's Lair"] = { db = "R", key = "ONY" }, + ["Emerald Sanctum"] = { db = "R", key = "ES" }, + ["Lower Karazhan Halls"] = { db = "R", key = "KARA10" }, + ["Blackwing Lair"] = { db = "R", key = "BWL" }, + ["Tower of Karazhan"] = { db = "R", key = "KARA40" }, + ["Naxxramas"] = { db = "R", key = "NAXX" }, + ["Zul'Gurub"] = { db = "R", key = "ZG" }, + ["Timbermaw Hold"] = { db = "R", key = "TH" }, +} + +-- Keep POI submap zone markers +local IJ_SUBMAP_ZONES = {} + +-- Default filters +MMM.filters = { + DUNGEON = true, + RAID = true, + BOAT = true, + ZEPPELIN = true, + TRAM = true, + WORLDBOSS = true, + FACTION = "ALL" +} + +-- Dirty-check state for RefreshMarkers +local lastContinent = nil +local lastZone = nil +local forceRefresh = false + +-- Textures +local TEX_BASE = "Interface\\AddOns\\ModernMapMarkers\\Textures\\" +local TEXTURE_MAP = { + DUNGEON = TEX_BASE .. "dungeon.tga", + RAID = TEX_BASE .. "raid.tga", + BOAT = TEX_BASE .. "boat.tga", + ZEPPELIN = TEX_BASE .. "zepp.tga", + TRAM = TEX_BASE .. "tram.tga", + WORLDBOSS = TEX_BASE .. "worldboss.tga", +} +local HIGHLIGHT_MAP = { + DUNGEON = TEX_BASE .. "dungeon-highlight.tga", + RAID = TEX_BASE .. "raid-highlight.tga", +} + +-- Zone name cache. Directly from the client, so they are localized in the client's language. +local LOCALIZED_ZONE_CACHE = {} +function MMM:CacheZones() + LOCALIZED_ZONE_CACHE[1] = { GetMapZones(1) } -- Kalimdor + LOCALIZED_ZONE_CACHE[2] = { GetMapZones(2) } -- Eastern Kingdoms +end + +-- Map multi-entrance dungeons to a single zone +local CANONICAL_ZONE = { + ["Blackrock Depths"] = "Burning Steppes", + ["Blackrock Spire"] = "Burning Steppes", + ["Blackwing Lair"] = "Burning Steppes", + ["Molten Core"] = "Burning Steppes", + ["Stormwind Vault"] = "Stormwind City", + ["Timbermaw Hold"] = "Azshara", +} + +-- Data Parsing +function MMM:BuildData() + if self.dataBuilt then return end + if not ModernMapMarkers_Points then return end + + MMM.Data = {} + MMM.ZoneMarkers = {} + + local index = 1 + + for contID, zones in pairs(ModernMapMarkers_Points) do + MMM.ZoneMarkers[contID] = MMM.ZoneMarkers[contID] or {} + + for zoneName, markers in pairs(zones) do + MMM.ZoneMarkers[contID][zoneName] = {} + + for _, m in ipairs(markers) do + local typeUpper = string.upper(m.type or "UNKNOWN") + if typeUpper == "ZEPP" then typeUpper = "ZEPPELIN" end + + local markerData = { + continent = contID, + zoneName = zoneName, + x = m.x, + y = m.y, + name = m.name, + type = typeUpper, + mask = m.mask, + description = m.info, + id = index, + destContinentId = m.destContinentId, + destZone = m.destZone + } + + table.insert(MMM.Data, markerData) + table.insert(MMM.ZoneMarkers[contID][zoneName], markerData) + + index = index + 1 + end + end + end + self.dataBuilt = true +end + +-- Get deduplicated data for dropdowns +function ModernMapMarkers_GetFlatData() + MMM:BuildData() + + if MMM.FlatDropdownData then return MMM.FlatDropdownData end + + local filteredData = {} + local seenNames = {} + + for _, data in ipairs(MMM.Data) do + if data.type == "DUNGEON" or data.type == "RAID" or data.type == "WORLDBOSS" then + local baseName = data.name or "" + + local existingIndex = seenNames[baseName] + if not existingIndex then + local dropData = {} + for k, v in pairs(data) do dropData[k] = v end + dropData.name = baseName + table.insert(filteredData, dropData) + seenNames[baseName] = table.getn(filteredData) + else + local canon = CANONICAL_ZONE[baseName] + if canon and data.zoneName == canon then + local dropData = {} + for k, v in pairs(data) do dropData[k] = v end + dropData.name = baseName + filteredData[existingIndex] = dropData + end + end + end + end + + MMM.FlatDropdownData = filteredData + return filteredData +end + +-- Drawing Logic +function MMM:RefreshMarkers() + if not WorldMapFrame:IsVisible() then return end + + self:BuildData() + + local currentContinent = GetCurrentMapContinent() + local currentZone = GetCurrentMapZone() + + -- Dirty-check: skip full redraw if zone hasn't changed and no force refresh + if not forceRefresh + and currentContinent == lastContinent + and currentZone == lastZone then + return + end + + lastContinent = currentContinent + lastZone = currentZone + forceRefresh = false + + if currentContinent == 0 or currentZone == 0 then + self:HideAllMarkers() + return + end + + local zoneNames = LOCALIZED_ZONE_CACHE[currentContinent] + local currentZoneName = zoneNames and zoneNames[currentZone] + if not currentZoneName then + self:HideAllMarkers() + return + end + + -- Translate localized zone name to English key used in MarkerData + local englishZoneName = L:GetEnglishZoneName(currentZoneName) + + local zoneMarkers = MMM.ZoneMarkers[currentContinent] and MMM.ZoneMarkers[currentContinent][englishZoneName] + + local markerIndex = 0 + + if zoneMarkers then + for _, data in ipairs(zoneMarkers) do + + local showMarker = (MMM.filters[data.type] == true) + + -- Hide markers replaced by InstanceJournal + if showMarker and MMM.ijInstalled then + if data.type == "WORLDBOSS" then + showMarker = false + elseif IJ_HIDDEN_MARKERS[data.name] then + showMarker = false + end + end + + -- Check faction filter + if showMarker and (data.type == "BOAT" or data.type == "ZEPPELIN" or data.type == "TRAM") then + if MMM.filters.FACTION ~= "ALL" + and data.description ~= "Neutral" + and data.description ~= MMM.filters.FACTION then + showMarker = false + end + end + + if showMarker then + markerIndex = markerIndex + 1 + local marker = self:GetOrCreateMarker(markerIndex) + + -- Sizing + if data.type == "DUNGEON" or data.type == "RAID" or data.type == "WORLDBOSS" then + marker:SetWidth(32) + marker:SetHeight(32) + else + marker:SetWidth(24) + marker:SetHeight(24) + end + + -- Position + local width = WorldMapDetailFrame:GetWidth() + local height = WorldMapDetailFrame:GetHeight() + marker:SetPoint("CENTER", WorldMapDetailFrame, "TOPLEFT", data.x * width, -data.y * height) + + -- Texture + local tex = TEXTURE_MAP[data.type] or "Interface\\Minimap\\POIIcons" + if marker.lastTexture ~= tex then + marker.texture:SetTexture(tex) + marker.lastTexture = tex + end + + local hlTex = HIGHLIGHT_MAP[data.type] + if marker.lastHighlight ~= hlTex then + if hlTex then + marker:SetHighlightTexture(hlTex) + elseif marker.lastHighlight then + marker:SetHighlightTexture("") + end + marker.lastHighlight = hlTex + end + + -- Metadata + marker.name = L:GetLocalizedString(data.name, data.type, data.mask) + marker.nameEN = data.name + marker.description = data.description + marker.markerType = data.type + marker.continent = data.continent + marker.zoneName = data.zoneName + marker.destContinentId = data.destContinentId + marker.destZone = data.destZone + + marker:Show() + end + end + end + + -- Hide any excess markers from the previous zone + self:HideMarkersFrom(markerIndex + 1) +end + +-- Hide all markers in the pool +function MMM:HideAllMarkers() + self:HideMarkersFrom(1) +end + +-- Hide markers from startIndex onwards +function MMM:HideMarkersFrom(startIndex) + for i = startIndex, table.getn(self.markers) do + if self.markers[i] then + self.markers[i]:Hide() + end + end +end + +-- Invalidate dirty-check so next RefreshMarkers does a full redraw +function MMM:InvalidateCache() + forceRefresh = true +end + +-- Get IJ instance from MMM marker English name +function MMM:GetIJInstance(nameEN) + if not MMM.ijInstalled or not nameEN then return nil end + local mapping = MMM_TO_IJ[nameEN] + if not mapping then return nil end + local dbTable = (mapping.db == "R") and IJDB.R or IJDB.DG + if not dbTable then return nil end + return dbTable[mapping.key] +end + +-- InstanceJournal Integration +function MMM:OnMarkerClick(marker, button) + local instance = nil + if MMM.ijInstalled then + instance = MMM:GetIJInstance(marker.nameEN) + end + + if button == "RightButton" then + if instance then + -- Right-click: open IJ journal page + if not IJ_InstanceJournalFrame:IsShown() then + IJ_InstanceJournalFrame:Show() + end + if instance.Type == IJLib.InstanceType.Raid then + IJ_ShowRaids = true + PanelTemplates_SetTab(IJ_InstanceJournalFrame, 2) + else + IJ_ShowRaids = false + PanelTemplates_SetTab(IJ_InstanceJournalFrame, 1) + end + IJ_ShowEncounter(instance) + WorldMapFrame:Hide() + end + else + if marker.destContinentId and marker.destZone then -- we have a transport marker + local zoneIndex = MMM:GetZoneIndex(marker.destContinentId, marker.destZone) + if zoneIndex > 0 then + SetMapZoom(marker.destContinentId, zoneIndex) + return + end + elseif instance then + -- Left-click: navigate to instance submap + SetMapZoom(tonumber(instance.MapId), 1) + end + end +end + +-- Marker Pool +function MMM:GetOrCreateMarker(index) + if not self.markers[index] then + local marker = CreateFrame("Button", "ModernMapMarkerIcon"..index, WorldMapButton) + marker:SetWidth(24) + marker:SetHeight(24) + marker:SetFrameLevel(WorldMapButton:GetFrameLevel() + 5) + + local tex = marker:CreateTexture(nil, "OVERLAY") + tex:SetAllPoints(marker) + marker.texture = tex + + marker:RegisterForClicks("LeftButtonUp", "RightButtonUp") + marker:SetScript("OnClick", function() MMM:OnMarkerClick(this, arg1) end) + + marker:SetScript("OnEnter", function() + WorldMapTooltip:SetOwner(this, "ANCHOR_RIGHT") + WorldMapTooltip:AddLine(this.name, 1, 0.82, 0) + + if this.description then + if this.markerType == "DUNGEON" or this.markerType == "RAID" or this.markerType == "WORLDBOSS" then + local lvlLabel = L:GetLocalizedString("Level") or "Level" + WorldMapTooltip:AddLine(lvlLabel .. ": " .. this.description, 1, 1, 1, 1) + elseif this.description == "Alliance" then + WorldMapTooltip:AddLine(L:GetLocalizedString("Alliance"), 0.0, 0.47, 1.0, 1) + elseif this.description == "Horde" then + WorldMapTooltip:AddLine(L:GetLocalizedString("Horde"), 1.0, 0.0, 0.0, 1) + else + WorldMapTooltip:AddLine(L:GetLocalizedString(this.description), 1, 1, 1, 1) + end + end + + -- IJ tooltips for dungeon/raid markers + if MMM.ijInstalled and MMM:GetIJInstance(this.nameEN) then + WorldMapTooltip:AddLine(L:GetLocalizedString("Left-Click: View Map"), 0.5, 0.5, 0.5) + WorldMapTooltip:AddLine(L:GetLocalizedString("Right-Click: Instance Journal"), 0.5, 0.5, 0.5) + end + + WorldMapTooltip:Show() + end) + + marker:SetScript("OnLeave", function() WorldMapTooltip:Hide() end) + + self.markers[index] = marker + end + return self.markers[index] +end + +-- Hooks & API +function ModernMapMarkers_SetFilter(key, state) + if key == "ALL" then + for _, t in ipairs(ALL_TYPES) do + MMM.filters[t] = state + end + else + MMM.filters[key] = state + end + MMM:InvalidateCache() + MMM:RefreshMarkers() +end + +function ModernMapMarkers_SetFactionFilter(factionStr) + MMM.filters.FACTION = factionStr + MMM:InvalidateCache() + MMM:RefreshMarkers() +end + +function MMM:GetZoneIndex(continentID, zoneName) + local zones = LOCALIZED_ZONE_CACHE[continentID] or {} + -- zoneName is English (from MarkerData), LOCALIZED_ZONE_CACHE has localized names + local localizedName = L:GetLocalizedZoneName(zoneName) + for i, name in ipairs(zones) do + if name == localizedName then return i end + end + -- Fallback: try direct match (for enUS or untranslated zones) + for i, name in ipairs(zones) do + if name == zoneName then return i end + end + return 0 +end + +function ModernMapMarkers_FindMarker(dataIndex) + MMM:BuildData() + local data = MMM.Data[dataIndex] + if not data then return end + + local zoneIndex = MMM:GetZoneIndex(data.continent, data.zoneName) + if zoneIndex > 0 then + SetMapZoom(data.continent, zoneIndex) + end + + if not MMM.filters[data.type] then + MMM.filters[data.type] = true + if ModernMapMarkers_SyncFilterUI then + ModernMapMarkers_SyncFilterUI(data.type, true) + end + end + + MMM:InvalidateCache() + MMM:RefreshMarkers() +end + +local original_WorldMapFrame_Update = WorldMapFrame_Update +function WorldMapFrame_Update() + if original_WorldMapFrame_Update then + original_WorldMapFrame_Update() + end + MMM:RefreshMarkers() +end + +MMM:SetScript("OnEvent", function() + if event == "VARIABLES_LOADED" then + if ModernMapMarkersDB and ModernMapMarkersDB.filters then + for k, v in pairs(ModernMapMarkersDB.filters) do + MMM.filters[k] = v + end + else + -- First load: auto-detect player faction for transport filter + local faction = UnitFactionGroup("player") + if faction == "Alliance" or faction == "Horde" then + MMM.filters.FACTION = faction + end + end + + L:Initialize() + MMM:CacheZones() + MMM:BuildData() + + -- Detect InstanceJournal + if IJDB and IJLib and IJ_ShowInstanceEntrancesIcon then + MMM.ijInstalled = true + + -- Build POI submap zone lookup + if IJDB.POI then + for _, poi in pairs(IJDB.POI) do + if poi.MapContinentId and poi.MapZoneId then + local key = tostring(poi.MapContinentId) .. ":" .. tostring(poi.MapZoneId) + IJ_SUBMAP_ZONES[key] = true + end + end + end + + -- Also include instance entrance locations inside other instance maps + -- (e.g., Molten Core entrance inside BRD submap) + local instanceMapIds = {} + local allInstances = {} + for _, inst in pairs(IJDB.DG or {}) do + if inst.MapId then instanceMapIds[tostring(inst.MapId)] = true end + table.insert(allInstances, inst) + end + for _, inst in pairs(IJDB.R or {}) do + if inst.MapId then instanceMapIds[tostring(inst.MapId)] = true end + table.insert(allInstances, inst) + end + for _, inst in ipairs(allInstances) do + if inst.Entrances then + for _, ent in pairs(inst.Entrances) do + if ent.MapContinentId and ent.MapZoneId + and instanceMapIds[tostring(ent.MapContinentId)] then + local key = tostring(ent.MapContinentId) .. ":" .. tostring(ent.MapZoneId) + IJ_SUBMAP_ZONES[key] = true + end + end + end + end + + -- Hook IJ entrance markers: hide on world zones, keep in POI submaps + -- In submaps, reskin entrance pins with MMM dungeon/raid textures + local original_ShowEntrance = IJ_ShowInstanceEntrancesIcon + IJ_ShowInstanceEntrancesIcon = function(instance) + local key = tostring(GetCurrentMapContinent()) .. ":" .. tostring(GetCurrentMapZone()) + if IJ_SUBMAP_ZONES[key] then + original_ShowEntrance(instance) + + -- Determine marker type and apply MMM filter + local isRaid = instance.Type == IJLib.InstanceType.Raid + local filterKey = isRaid and "RAID" or "DUNGEON" + local mmmTex = isRaid and TEXTURE_MAP.RAID or TEXTURE_MAP.DUNGEON + + local cleanName = string.gsub(instance.Name or "", "%s+", "") + local prefix = "IJ_EntrancePin_" .. cleanName + + for _, pin in ipairs(IJ_CreatedMapInstanceEntrance) do + local pinName = pin:GetName() or "" + if string.find(pinName, prefix, 1, true) and pin:IsVisible() then + -- Hide pin if MMM filter is disabled for this type + if not MMM.filters[filterKey] then + pin:Hide() + end + pin.icon:SetTexture(mmmTex) + pin.mmmInstance = instance + + if not pin.mmmReskinned then + pin.mmmReskinned = true + pin.mmmTexture = mmmTex + + local mmmHL = instance.Type == IJLib.InstanceType.Raid and HIGHLIGHT_MAP.RAID or HIGHLIGHT_MAP.DUNGEON + if mmmHL then + pin:SetHighlightTexture(mmmHL) + end + + local origOnEnter = pin:GetScript("OnEnter") + local origOnLeave = pin:GetScript("OnLeave") + + pin:SetScript("OnEnter", function() + if origOnEnter then origOnEnter() end + this.icon:SetTexture(this.mmmTexture) + + -- MMM tooltip for IJ POI submap markers + local inst = this.mmmInstance + if inst then + WorldMapTooltip:SetOwner(this, "ANCHOR_RIGHT") + WorldMapTooltip:AddLine(inst.Name or "", 1, 0.82, 0) + local minLvl = inst.MinLevel or 0 + local maxLvl = inst.MaxLevel or 0 + local lvlLabel = L:GetLocalizedString("Level") or "Level" + WorldMapTooltip:AddLine(lvlLabel .. ": " .. minLvl .. "-" .. maxLvl, 1, 1, 1, 1) + WorldMapTooltip:AddLine(L:GetLocalizedString("Left-Click: View Map"), 0.5, 0.5, 0.5) + WorldMapTooltip:AddLine(L:GetLocalizedString("Right-Click: Instance Journal"), 0.5, 0.5, 0.5) + WorldMapTooltip:Show() + end + end) + + pin:SetScript("OnLeave", function() + if origOnLeave then origOnLeave() end + this.icon:SetTexture(this.mmmTexture) + WorldMapTooltip:Hide() + end) + + -- Right click for IJ journal + pin:RegisterForClicks("LeftButtonUp", "RightButtonUp") + local origOnClick = pin:GetScript("OnClick") + pin:SetScript("OnClick", function() + if arg1 == "RightButton" and this.mmmInstance then + local inst = this.mmmInstance + if not IJ_InstanceJournalFrame:IsShown() then + IJ_InstanceJournalFrame:Show() + end + if inst.Type == IJLib.InstanceType.Raid then + IJ_ShowRaids = true + PanelTemplates_SetTab(IJ_InstanceJournalFrame, 2) + else + IJ_ShowRaids = false + PanelTemplates_SetTab(IJ_InstanceJournalFrame, 1) + end + IJ_ShowEncounter(inst) + WorldMapFrame:Hide() + else + if origOnClick then origOnClick() end + end + end) + end + end + end + end + end + end + + MMM:InvalidateCache() + MMM:RefreshMarkers() + + elseif event == "PLAYER_LOGOUT" then + if not ModernMapMarkersDB then ModernMapMarkersDB = {} end + ModernMapMarkersDB.filters = {} + for k, v in pairs(MMM.filters) do + ModernMapMarkersDB.filters[k] = v + end + end +end) +MMM:RegisterEvent("VARIABLES_LOADED") +MMM:RegisterEvent("PLAYER_LOGOUT") diff --git a/ModernMapMarkers.toc b/ModernMapMarkers.toc index b6dfa04..1c5d6be 100644 --- a/ModernMapMarkers.toc +++ b/ModernMapMarkers.toc @@ -3,9 +3,10 @@ ## Author: tilr & Heallios ## Notes: Shows dungeon, raid, world boss, boat, zeppelin, and tram locations on the world map ## Version: 2.4 -## OptionalDeps: pfUI, pfQuest, InstanceJournal +## OptionalDeps: pfUI, pfQuest, pfQuest-turtle, InstanceJournal ## SavedVariables: ModernMapMarkersDB +pfDB\pfDB.xml Localization.lua Locales\Locale_deDE.lua Locales\Locale_esES.lua diff --git a/ModernMapMarkers_UI.lua b/ModernMapMarkers_UI.lua index 7686ff3..1bbe3bd 100644 --- a/ModernMapMarkers_UI.lua +++ b/ModernMapMarkers_UI.lua @@ -1,547 +1,580 @@ -local MMM_GUI = {} -local isPfUI = IsAddOnLoaded("pfUI") -local L = ModernMapMarkers_Locale - -function MMM_GUI.InitializeWorldMapControls() - - -- Filter Definitions - local filterOptions = { - { label = L:GetLocalizedMarkerName("All Markers"), value = "ALL", isCheck = true, checked = true }, - { label = L:GetLocalizedMarkerName("Dungeons"), value = "DUNGEON", isCheck = true, checked = true }, - { label = L:GetLocalizedMarkerName("Raids"), value = "RAID", isCheck = true, checked = true }, - { label = L:GetLocalizedMarkerName("World Bosses"), value = "WORLDBOSS", isCheck = true, checked = true }, - { label = L:GetLocalizedMarkerName("Transports"), isHeader = true }, - { label = " " .. L:GetLocalizedMarkerName("Boats"), value = "BOAT", isCheck = true, checked = true }, - { label = " " .. L:GetLocalizedMarkerName("Zeppelins"), value = "ZEPPELIN", isCheck = true, checked = true }, - { label = " " .. L:GetLocalizedMarkerName("Trams"), value = "TRAM", isCheck = true, checked = true }, - { label = L:GetLocalizedMarkerName("Transport Faction"), isHeader = true }, - { label = " " .. L:GetLocalizedMarkerName("Show All"), value = "ALL", isCheck = true, checked = true, isRadio = true, group = "fac" }, - { label = " " .. L:GetLocalizedMarkerName("Alliance"), value = "Alliance", isCheck = true, checked = false, isRadio = true, group = "fac" }, - { label = " " .. L:GetLocalizedMarkerName("Horde"), value = "Horde", isCheck = true, checked = false, isRadio = true, group = "fac" }, - } - - if ModernMapMarkersDB and ModernMapMarkersDB.filters then - local saved = ModernMapMarkersDB.filters - for _, item in ipairs(filterOptions) do - if item.isCheck and item.value and item.value ~= "ALL" then - if item.isRadio then - if saved.FACTION ~= nil then - item.checked = (saved.FACTION == item.value) or (item.value == "ALL" and saved.FACTION == "ALL") - end - elseif saved[item.value] ~= nil then - item.checked = saved[item.value] - end - end - end - -- Auto-check "All Markers" if all individual filters are on - local allOn = true - for _, item in ipairs(filterOptions) do - if item.isCheck and not item.isRadio and item.value ~= "ALL" then - if not item.checked then allOn = false; break end - end - end - filterOptions[1].checked = allOn - end - - function ModernMapMarkers_SyncFilterUI(typeKey, state) - for _, item in ipairs(filterOptions) do - if item.isCheck and not item.isRadio and item.value == typeKey then - item.checked = state - end - end - local allOn = true - for _, item in ipairs(filterOptions) do - if item.isCheck and not item.isRadio and item.value ~= "ALL" then - if not item.checked then allOn = false; break end - end - end - filterOptions[1].checked = allOn - end - - -- Determine Parent Frame (Standard or pfQuest) - local dropdownParent = WorldMapFrame - - -- Dynamic dropdown width based on longest label - local MIN_DROPDOWN_WIDTH = 120 - local PADDING = 35 - local longestLabel = 0 - - -- Measure filter labels - for _, item in ipairs(filterOptions) do - local text = string.gsub(item.label, "^%s+", "") - local len = string.len(text) - if len > longestLabel then longestLabel = len end - end - - -- Also measure button texts and find dropdown labels - local buttonTexts = { - L:GetLocalizedMarkerName("Filter Markers"), - L:GetLocalizedMarkerName("Find Marker"), - L:GetLocalizedZoneName("Kalimdor"), - L:GetLocalizedZoneName("Eastern Kingdoms"), - L:GetLocalizedMarkerName("Dungeons"), - L:GetLocalizedMarkerName("Raids"), - } - for _, text in ipairs(buttonTexts) do - local len = string.len(text) - if len > longestLabel then longestLabel = len end - end - - -- Approximate width: ~7px per character + padding, with minimum - local dropdownWidth = math.max(MIN_DROPDOWN_WIDTH, longestLabel * 7 + PADDING) - local dropdownButtonWidth = dropdownWidth + 5 - - if _G.pfQuestMapDropdown then - dropdownParent = _G.pfQuestMapDropdown:GetParent() or dropdownParent - end - - -- Filter Dropdown - local filterFrame = CreateFrame("Frame", "ModernMapMarkersFilter_Blizz", dropdownParent, "UIDropDownMenuTemplate") - - filterFrame:SetFrameStrata(dropdownParent:GetFrameStrata()) - filterFrame:SetFrameLevel(dropdownParent:GetFrameLevel() + 10) - - local filterBtn = getglobal(filterFrame:GetName().."Button") - if filterBtn then filterBtn:SetFrameLevel(filterFrame:GetFrameLevel() + 2) end - - -- Positioning - if _G.pfQuestMapDropdown then - filterFrame:SetPoint("TOPRIGHT", _G.pfQuestMapDropdown, "BOTTOMRIGHT", 0, 0) - else - filterFrame:SetPoint("TOPRIGHT", WorldMapFrame, "TOPRIGHT", -10, -40) - end - - UIDropDownMenu_Initialize(filterFrame, function(level) - for _, itemRaw in ipairs(filterOptions) do - local item = itemRaw - - if item.isHeader then - local info = {} - info.text = item.label - info.isTitle = 1 - info.notCheckable = 1 - UIDropDownMenu_AddButton(info, level) - else - local info = {} - info.text = string.gsub(item.label, "^%s+", "") - info.value = item.value - info.checked = item.checked - info.keepShownOnClick = 1 - info.func = function() - if item.isRadio then - if item.checked then return end - for _, v in ipairs(filterOptions) do - if v.isRadio and v.group == item.group then v.checked = false end - end - item.checked = true - ModernMapMarkers_SetFactionFilter(item.value) - else - item.checked = not item.checked - if item.value == "ALL" then - for _, v in ipairs(filterOptions) do - if v.isCheck and not v.isRadio and v.value ~= "ALL" then - v.checked = item.checked - end - end - ModernMapMarkers_SetFilter("ALL", item.checked) - else - ModernMapMarkers_SetFilter(item.value, item.checked) - local allOn = true - for _, v in ipairs(filterOptions) do - if v.isCheck and not v.isRadio and v.value ~= "ALL" then - if not v.checked then allOn = false; break end - end - end - filterOptions[1].checked = allOn - end - end - ToggleDropDownMenu(1, nil, filterFrame) - end - UIDropDownMenu_AddButton(info, level) - end - end - end) - - UIDropDownMenu_SetWidth(dropdownWidth, filterFrame) - UIDropDownMenu_SetButtonWidth(dropdownButtonWidth, filterFrame) - UIDropDownMenu_SetText(L:GetLocalizedMarkerName("Filter Markers"), filterFrame) - UIDropDownMenu_JustifyText("RIGHT", filterFrame) - - - -- Find Marker Toggle (UIDropDownMenuTemplate to match filter style) - local findFrame = CreateFrame("Frame", "ModernMapMarkersFind_Blizz", dropdownParent, "UIDropDownMenuTemplate") - findFrame:SetFrameStrata(filterFrame:GetFrameStrata()) - findFrame:SetFrameLevel(filterFrame:GetFrameLevel()) - - local findBtn = getglobal(findFrame:GetName().."Button") - if findBtn then findBtn:SetFrameLevel(findFrame:GetFrameLevel() + 2) end - - findFrame:SetPoint("TOPRIGHT", filterFrame, "BOTTOMRIGHT", 0, 0) - - UIDropDownMenu_SetWidth(dropdownWidth, findFrame) - UIDropDownMenu_SetButtonWidth(dropdownButtonWidth, findFrame) - UIDropDownMenu_SetText(L:GetLocalizedMarkerName("Find Marker"), findFrame) - UIDropDownMenu_JustifyText("RIGHT", findFrame) - - if findBtn then - findBtn:SetScript("OnClick", function() - local panel = getglobal("ModernMapMarkersFind_Panel") - if panel then - if panel:IsVisible() then - panel:Hide() - else - UpdateFindPanel() - panel:Show() - end - end - end) - end - - UIDropDownMenu_Initialize(findFrame, function() end) - - -- Find Marker Panel - local PANEL_WIDTH = 220 - local ROW_HEIGHT = 16 - local MAX_VISIBLE_ROWS = 12 - local BUTTON_HEIGHT = 20 - local BUTTON_SPACING = 2 - local PANEL_PADDING = 8 - - local findPanel = CreateFrame("Frame", "ModernMapMarkersFind_Panel", WorldMapFrame) - findPanel:SetFrameStrata(filterFrame:GetFrameStrata()) - findPanel:SetFrameLevel(filterFrame:GetFrameLevel() + 20) - findPanel:SetWidth(PANEL_WIDTH) - findPanel:SetPoint("TOPRIGHT", findFrame, "BOTTOMRIGHT", -16, 0) - findPanel:SetBackdrop({ - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", - edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", - tile = true, tileSize = 16, edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 }, - }) - findPanel:SetBackdropColor(0.1, 0.1, 0.1, 0.95) - findPanel:SetBackdropBorderColor(0.6, 0.6, 0.6, 1) - findPanel:Hide() - - local activeContinent = 1 - local activeType = "DUNGEON" - - local function CreateSelectorButton(name, parent, width, text) - local btn = CreateFrame("Button", name, parent) - btn:SetWidth(width) - btn:SetHeight(BUTTON_HEIGHT) - - btn:SetBackdrop({ - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", - edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", - tile = true, tileSize = 16, edgeSize = 12, - insets = { left = 2, right = 2, top = 2, bottom = 2 }, - }) - - local label = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") - label:SetPoint("CENTER", 0, 0) - label:SetText(text) - btn.label = label - - btn:SetScript("OnEnter", function() - if not btn.isActive then - btn:SetBackdropColor(0.3, 0.3, 0.3, 1) - end - end) - btn:SetScript("OnLeave", function() - if not btn.isActive then - btn:SetBackdropColor(0.15, 0.15, 0.15, 1) - end - end) - - btn.isActive = false - btn:SetBackdropColor(0.15, 0.15, 0.15, 1) - btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) - - return btn - end - - local function SetButtonActive(btn, active) - btn.isActive = active - if active then - btn:SetBackdropColor(0.2, 0.4, 0.7, 1) - btn:SetBackdropBorderColor(0.4, 0.6, 1.0, 1) - btn.label:SetTextColor(1, 1, 1) - else - btn:SetBackdropColor(0.15, 0.15, 0.15, 1) - btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) - btn.label:SetTextColor(0.8, 0.8, 0.8) - end - end - - -- Continent buttons - local halfWidth = (PANEL_WIDTH - PANEL_PADDING * 2 - BUTTON_SPACING) / 2 - - local btnKalimdor = CreateSelectorButton("MMMFind_Kalimdor", findPanel, halfWidth, L:GetLocalizedZoneName("Kalimdor")) - btnKalimdor:SetPoint("TOPLEFT", findPanel, "TOPLEFT", PANEL_PADDING, -PANEL_PADDING) - - local btnEK = CreateSelectorButton("MMMFind_EK", findPanel, halfWidth, L:GetLocalizedZoneName("Eastern Kingdoms")) - btnEK:SetPoint("TOPLEFT", btnKalimdor, "TOPRIGHT", BUTTON_SPACING, 0) - - -- Type buttons - local thirdWidth = (PANEL_WIDTH - PANEL_PADDING * 2 - BUTTON_SPACING * 2) / 3 - - local btnDungeon = CreateSelectorButton("MMMFind_Dungeon", findPanel, thirdWidth, L:GetLocalizedMarkerName("Dungeons")) - btnDungeon:SetPoint("TOPLEFT", btnKalimdor, "BOTTOMLEFT", 0, -BUTTON_SPACING) - - local btnRaid = CreateSelectorButton("MMMFind_Raid", findPanel, thirdWidth, L:GetLocalizedMarkerName("Raids")) - btnRaid:SetPoint("TOPLEFT", btnDungeon, "TOPRIGHT", BUTTON_SPACING, 0) - - local btnWorldBoss = CreateSelectorButton("MMMFind_WorldBoss", findPanel, thirdWidth, L:GetLocalizedMarkerName("World Bosses")) - btnWorldBoss:SetPoint("TOPLEFT", btnRaid, "TOPRIGHT", BUTTON_SPACING, 0) - - -- Scroll frame for the instance list - local listAreaTop = PANEL_PADDING + BUTTON_HEIGHT * 2 + BUTTON_SPACING * 2 + 4 - - local scrollFrame = CreateFrame("ScrollFrame", "MMMFind_Scroll", findPanel, "FauxScrollFrameTemplate") - scrollFrame:SetPoint("TOPLEFT", findPanel, "TOPLEFT", PANEL_PADDING, -listAreaTop) - scrollFrame:SetPoint("BOTTOMRIGHT", findPanel, "BOTTOMRIGHT", -PANEL_PADDING - 22, PANEL_PADDING) - - -- Row buttons - local rowButtons = {} - for i = 1, MAX_VISIBLE_ROWS do - local row = CreateFrame("Button", "MMMFind_Row" .. i, findPanel) - row:SetHeight(ROW_HEIGHT) - row:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, -((i - 1) * ROW_HEIGHT)) - row:SetPoint("RIGHT", scrollFrame, "RIGHT", 0, 0) - - local highlight = row:CreateTexture(nil, "HIGHLIGHT") - highlight:SetAllPoints(row) - highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") - highlight:SetBlendMode("ADD") - highlight:SetAlpha(0.4) - - local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") - nameText:SetPoint("LEFT", row, "LEFT", 4, 0) - nameText:SetJustifyH("LEFT") - row.nameText = nameText - - local lvlText = row:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall") - lvlText:SetPoint("RIGHT", row, "RIGHT", -4, 0) - lvlText:SetJustifyH("RIGHT") - row.lvlText = lvlText - - row:SetScript("OnEnter", function() - if row.dataID then - WorldMapTooltip:SetOwner(row, "ANCHOR_LEFT") - WorldMapTooltip:AddLine(row.nameText:GetText(), 1, 0.82, 0) - if row.lvlText:GetText() and row.lvlText:GetText() ~= "" then - WorldMapTooltip:AddLine(row.lvlText:GetText(), 1, 1, 1) - end - WorldMapTooltip:Show() - end - end) - row:SetScript("OnLeave", function() - WorldMapTooltip:Hide() - end) - - row:Hide() - rowButtons[i] = row - end - - -- Current filtered + sorted list cache - local currentList = {} - - -- Sort function: level then name - local function sortLvl(a, b) - local _, _, alvlStr = string.find(a.description or "", "^(%d+)") - local _, _, blvlStr = string.find(b.description or "", "^(%d+)") - local alvl = tonumber(alvlStr) or 0 - local blvl = tonumber(blvlStr) or 0 - if alvl == blvl then return (a.name or "") < (b.name or "") end - return alvl < blvl - end - - local function RefreshFindList() - local flatData = ModernMapMarkers_GetFlatData() - currentList = {} - - for _, data in ipairs(flatData) do - if data.continent == activeContinent and data.type == activeType then - table.insert(currentList, data) - end - end - table.sort(currentList, sortLvl) - - local totalRows = table.getn(currentList) - local displayRows = math.min(totalRows, MAX_VISIBLE_ROWS) - - local panelHeight = listAreaTop + (displayRows * ROW_HEIGHT) + PANEL_PADDING + 4 - if totalRows > MAX_VISIBLE_ROWS then - panelHeight = listAreaTop + (MAX_VISIBLE_ROWS * ROW_HEIGHT) + PANEL_PADDING + 4 - end - findPanel:SetHeight(panelHeight) - - FauxScrollFrame_Update(scrollFrame, totalRows, MAX_VISIBLE_ROWS, ROW_HEIGHT) - - local offset = FauxScrollFrame_GetOffset(scrollFrame) - local lvlLabel = L:GetLocalizedMarkerName("Level") or "Level" - - for i = 1, MAX_VISIBLE_ROWS do - local row = rowButtons[i] - local dataIndex = offset + i - - if dataIndex <= totalRows then - local data = currentList[dataIndex] - local localizedName = L:GetLocalizedMarkerName(data.name) - row.nameText:SetText(localizedName) - - if data.description then - row.lvlText:SetText(lvlLabel .. " " .. data.description) - else - row.lvlText:SetText("") - end - - row.nameText:SetWidth(row:GetWidth() - row.lvlText:GetStringWidth() - 16) - - row.dataID = data.id - row:SetScript("OnClick", function() - ModernMapMarkers_FindMarker(data.id) - end) - row:Show() - else - row.nameText:SetText("") - row.lvlText:SetText("") - row.dataID = nil - row:Hide() - end - end - end - - scrollFrame:SetScript("OnVerticalScroll", function() - FauxScrollFrame_OnVerticalScroll(ROW_HEIGHT, RefreshFindList) - end) - - -- Button click handlers - local function UpdateButtonStates() - SetButtonActive(btnKalimdor, activeContinent == 1) - SetButtonActive(btnEK, activeContinent == 2) - SetButtonActive(btnDungeon, activeType == "DUNGEON") - SetButtonActive(btnRaid, activeType == "RAID") - SetButtonActive(btnWorldBoss, activeType == "WORLDBOSS") - end - - btnKalimdor:SetScript("OnClick", function() - activeContinent = 1 - UpdateButtonStates() - RefreshFindList() - end) - - btnEK:SetScript("OnClick", function() - activeContinent = 2 - UpdateButtonStates() - RefreshFindList() - end) - - btnDungeon:SetScript("OnClick", function() - activeType = "DUNGEON" - UpdateButtonStates() - RefreshFindList() - end) - - btnRaid:SetScript("OnClick", function() - activeType = "RAID" - UpdateButtonStates() - RefreshFindList() - end) - - btnWorldBoss:SetScript("OnClick", function() - activeType = "WORLDBOSS" - UpdateButtonStates() - RefreshFindList() - end) - - function UpdateFindPanel() - UpdateButtonStates() - RefreshFindList() - end - - -- Close panel when the world map closes - local origOnHide = WorldMapFrame:GetScript("OnHide") - WorldMapFrame:SetScript("OnHide", function() - if origOnHide then origOnHide() end - findPanel:Hide() - end) - - UpdateButtonStates() - - -- pfUI Skinning - if isPfUI and _G.pfUI and _G.pfUI.api then - if _G.pfUI.api.SkinDropDown then - _G.pfUI.api.SkinDropDown(filterFrame) - _G.pfUI.api.SkinDropDown(findFrame) - end - if _G.pfUI.api.SkinButton then - _G.pfUI.api.SkinButton(btnKalimdor) - _G.pfUI.api.SkinButton(btnEK) - _G.pfUI.api.SkinButton(btnDungeon) - _G.pfUI.api.SkinButton(btnRaid) - _G.pfUI.api.SkinButton(btnWorldBoss) - end - end - - -- Apply saved visibility state - if ModernMapMarkersDB and ModernMapMarkersDB.hideDropdowns then - filterFrame:Hide() - findFrame:Hide() - end - -end - --- Debug Utilities -SLASH_MMMDEBUG1 = "/mmmzones" -SlashCmdList["MMMDEBUG"] = function() - if not DEFAULT_CHAT_FRAME then return end - for contID = 1, 2 do - local contName = (contID == 1) and "Kalimdor" or "Eastern Kingdoms" - DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModernMapMarkers:|r Zone Indexes for " .. contName .. ":") - local zones = { GetMapZones(contID) } - for i, zoneName in ipairs(zones) do - DEFAULT_CHAT_FRAME:AddMessage(" " .. i .. ": " .. zoneName) - end - end -end - --- Slash command to toggle dropdown visibility -SLASH_MMM1 = "/mmm" -SlashCmdList["MMM"] = function() - if type(ModernMapMarkersDB) ~= "table" then - ModernMapMarkersDB = { filters = {} } - end - ModernMapMarkersDB.hideDropdowns = not ModernMapMarkersDB.hideDropdowns - - local filterFrame = getglobal("ModernMapMarkersFilter_Blizz") - local findFrame = getglobal("ModernMapMarkersFind_Blizz") - local findPanel = getglobal("ModernMapMarkersFind_Panel") - - if filterFrame and findFrame then - if ModernMapMarkersDB.hideDropdowns then - filterFrame:Hide() - findFrame:Hide() - if findPanel then findPanel:Hide() end - if DEFAULT_CHAT_FRAME then - DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModern|rMapMarkers: " .. L:GetLocalizedMarkerName("Dropdown menus hidden.")) - end - else - filterFrame:Show() - findFrame:Show() - if DEFAULT_CHAT_FRAME then - DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModern|rMapMarkers: " .. L:GetLocalizedMarkerName("Dropdown menus shown.")) - end - end - end -end - -local initFrame = CreateFrame("Frame") -initFrame:RegisterEvent("VARIABLES_LOADED") -initFrame:SetScript("OnEvent", function() - L:Initialize() - MMM_GUI.InitializeWorldMapControls() - this:UnregisterEvent("VARIABLES_LOADED") -end) - +local MMM_GUI = {} +local isPfUI = IsAddOnLoaded("pfUI") +local L = ModernMapMarkers_Locale + +function MMM_GUI.InitializeWorldMapControls() + + -- Filter Definitions + local filterOptions = { + { label = L:GetLocalizedString("All Markers"), value = "ALL", isCheck = true, checked = true }, + { label = L:GetLocalizedString("Dungeons"), value = "DUNGEON", isCheck = true, checked = true }, + { label = L:GetLocalizedString("Raids"), value = "RAID", isCheck = true, checked = true }, + { label = L:GetLocalizedString("World Bosses"), value = "WORLDBOSS", isCheck = true, checked = true }, + { label = L:GetLocalizedString("Transports"), isHeader = true }, + { label = " " .. L:GetLocalizedString("Boats"), value = "BOAT", isCheck = true, checked = true }, + { label = " " .. L:GetLocalizedString("Zeppelins"), value = "ZEPPELIN", isCheck = true, checked = true }, + { label = " " .. L:GetLocalizedString("Trams"), value = "TRAM", isCheck = true, checked = true }, + { label = L:GetLocalizedString("Transport Faction"), isHeader = true }, + { label = " " .. L:GetLocalizedString("Show All"), value = "ALL", isCheck = true, checked = true, isRadio = true, group = "fac" }, + { label = " " .. L:GetLocalizedString("Alliance"), value = "Alliance", isCheck = true, checked = false, isRadio = true, group = "fac" }, + { label = " " .. L:GetLocalizedString("Horde"), value = "Horde", isCheck = true, checked = false, isRadio = true, group = "fac" }, + } + + if ModernMapMarkersDB and ModernMapMarkersDB.filters then + local saved = ModernMapMarkersDB.filters + for _, item in ipairs(filterOptions) do + if item.isCheck and item.value and item.value ~= "ALL" then + if item.isRadio then + if saved.FACTION ~= nil then + item.checked = (saved.FACTION == item.value) or (item.value == "ALL" and saved.FACTION == "ALL") + end + elseif saved[item.value] ~= nil then + item.checked = saved[item.value] + end + end + end + -- Auto-check "All Markers" if all individual filters are on + local allOn = true + for _, item in ipairs(filterOptions) do + if item.isCheck and not item.isRadio and item.value ~= "ALL" then + if not item.checked then allOn = false; break end + end + end + filterOptions[1].checked = allOn + end + + function ModernMapMarkers_SyncFilterUI(typeKey, state) + for _, item in ipairs(filterOptions) do + if item.isCheck and not item.isRadio and item.value == typeKey then + item.checked = state + end + end + local allOn = true + for _, item in ipairs(filterOptions) do + if item.isCheck and not item.isRadio and item.value ~= "ALL" then + if not item.checked then allOn = false; break end + end + end + filterOptions[1].checked = allOn + end + + -- Determine Parent Frame (Standard or pfQuest) + local dropdownParent = WorldMapFrame + + -- Dynamic dropdown width based on longest label + local MIN_DROPDOWN_WIDTH = 120 + local PADDING = 35 + local longestLabel = 0 + + -- Measure filter labels + for _, item in ipairs(filterOptions) do + local text = string.gsub(item.label, "^%s+", "") + local len = string.len(text) + if len > longestLabel then longestLabel = len end + end + + -- Also measure button texts and find dropdown labels + local buttonTexts = { + L:GetLocalizedString("Filter Markers"), + L:GetLocalizedString("Find Marker"), + L:GetLocalizedZoneName("Kalimdor"), + L:GetLocalizedZoneName("Eastern Kingdoms"), + L:GetLocalizedString("Dungeons"), + L:GetLocalizedString("Raids"), + } + for _, text in ipairs(buttonTexts) do + local len = string.len(text) + if len > longestLabel then longestLabel = len end + end + + -- Approximate width: ~7px per character + padding, with minimum + local dropdownWidth = math.max(MIN_DROPDOWN_WIDTH, longestLabel * 7 + PADDING) + local dropdownButtonWidth = dropdownWidth + 5 + + if _G.pfQuestMapDropdown then + dropdownParent = _G.pfQuestMapDropdown:GetParent() or dropdownParent + end + + -- Filter Dropdown + local filterFrame = CreateFrame("Frame", "ModernMapMarkersFilter_Blizz", dropdownParent, "UIDropDownMenuTemplate") + + filterFrame:SetFrameStrata(dropdownParent:GetFrameStrata()) + filterFrame:SetFrameLevel(dropdownParent:GetFrameLevel() + 10) + + local filterBtn = getglobal(filterFrame:GetName().."Button") + if filterBtn then filterBtn:SetFrameLevel(filterFrame:GetFrameLevel() + 2) end + + -- Positioning + if _G.pfQuestMapDropdown then + filterFrame:SetPoint("TOPRIGHT", _G.pfQuestMapDropdown, "BOTTOMRIGHT", 0, 0) + else + filterFrame:SetPoint("TOPRIGHT", WorldMapFrame, "TOPRIGHT", -10, -40) + end + + UIDropDownMenu_Initialize(filterFrame, function(level) + for _, itemRaw in ipairs(filterOptions) do + local item = itemRaw + + if item.isHeader then + local info = {} + info.text = item.label + info.isTitle = 1 + info.notCheckable = 1 + UIDropDownMenu_AddButton(info, level) + else + local info = {} + info.text = string.gsub(item.label, "^%s+", "") + info.value = item.value + info.checked = item.checked + info.keepShownOnClick = 1 + info.func = function() + if item.isRadio then + if item.checked then return end + for _, v in ipairs(filterOptions) do + if v.isRadio and v.group == item.group then v.checked = false end + end + item.checked = true + ModernMapMarkers_SetFactionFilter(item.value) + else + item.checked = not item.checked + if item.value == "ALL" then + for _, v in ipairs(filterOptions) do + if v.isCheck and not v.isRadio and v.value ~= "ALL" then + v.checked = item.checked + end + end + ModernMapMarkers_SetFilter("ALL", item.checked) + else + ModernMapMarkers_SetFilter(item.value, item.checked) + local allOn = true + for _, v in ipairs(filterOptions) do + if v.isCheck and not v.isRadio and v.value ~= "ALL" then + if not v.checked then allOn = false; break end + end + end + filterOptions[1].checked = allOn + end + end + ToggleDropDownMenu(1, nil, filterFrame) + end + UIDropDownMenu_AddButton(info, level) + end + end + end) + + UIDropDownMenu_SetWidth(dropdownWidth, filterFrame) + UIDropDownMenu_SetButtonWidth(dropdownButtonWidth, filterFrame) + UIDropDownMenu_SetText(L:GetLocalizedString("Filter Markers"), filterFrame) + UIDropDownMenu_JustifyText("RIGHT", filterFrame) + + + -- Find Marker Toggle (UIDropDownMenuTemplate to match filter style) + local findFrame = CreateFrame("Frame", "ModernMapMarkersFind_Blizz", dropdownParent, "UIDropDownMenuTemplate") + findFrame:SetFrameStrata(filterFrame:GetFrameStrata()) + findFrame:SetFrameLevel(filterFrame:GetFrameLevel()) + + local findBtn = getglobal(findFrame:GetName().."Button") + if findBtn then findBtn:SetFrameLevel(findFrame:GetFrameLevel() + 2) end + + findFrame:SetPoint("TOPRIGHT", filterFrame, "BOTTOMRIGHT", 0, 0) + + UIDropDownMenu_SetWidth(dropdownWidth, findFrame) + UIDropDownMenu_SetButtonWidth(dropdownButtonWidth, findFrame) + UIDropDownMenu_SetText(L:GetLocalizedString("Find Marker"), findFrame) + UIDropDownMenu_JustifyText("RIGHT", findFrame) + + if findBtn then + findBtn:SetScript("OnClick", function() + local panel = getglobal("ModernMapMarkersFind_Panel") + if panel then + if panel:IsVisible() then + panel:Hide() + else + UpdateFindPanel() + panel:Show() + end + end + end) + end + + UIDropDownMenu_Initialize(findFrame, function() end) + + -- Find Marker Panel + local PANEL_WIDTH = 240 + local ROW_HEIGHT = 16 + local MAX_VISIBLE_ROWS = 12 + local BUTTON_HEIGHT = 20 + local BUTTON_SPACING = 2 + local PANEL_PADDING = 8 + + local findPanel = CreateFrame("Frame", "ModernMapMarkersFind_Panel", WorldMapFrame) + findPanel:SetFrameStrata(filterFrame:GetFrameStrata()) + findPanel:SetFrameLevel(filterFrame:GetFrameLevel() + 20) + findPanel:SetWidth(PANEL_WIDTH) + findPanel:SetPoint("TOPRIGHT", findFrame, "BOTTOMRIGHT", -16, 0) + findPanel:SetBackdrop({ + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", + edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 }, + }) + findPanel:SetBackdropColor(0.1, 0.1, 0.1, 0.95) + findPanel:SetBackdropBorderColor(0.6, 0.6, 0.6, 1) + findPanel:Hide() + + local activeContinent = 1 + local activeType = "DUNGEON" + + local function CreateSelectorButton(name, parent, width, text) + local btn = CreateFrame("Button", name, parent) + btn:SetWidth(width) + btn:SetHeight(BUTTON_HEIGHT) + + btn:SetBackdrop({ + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", + edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", + tile = true, tileSize = 16, edgeSize = 12, + insets = { left = 2, right = 2, top = 2, bottom = 2 }, + }) + + local label = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + label:SetPoint("CENTER", 0, 0) + label:SetText(text) + btn.label = label + + btn:SetScript("OnEnter", function() + if not btn.isActive then + btn:SetBackdropColor(0.3, 0.3, 0.3, 1) + end + end) + btn:SetScript("OnLeave", function() + if not btn.isActive then + btn:SetBackdropColor(0.15, 0.15, 0.15, 1) + end + end) + + btn.isActive = false + btn:SetBackdropColor(0.15, 0.15, 0.15, 1) + btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) + + return btn + end + + local function SetButtonActive(btn, active) + btn.isActive = active + if active then + btn:SetBackdropColor(0.2, 0.4, 0.7, 1) + btn:SetBackdropBorderColor(0.4, 0.6, 1.0, 1) + btn.label:SetTextColor(1, 1, 1) + else + btn:SetBackdropColor(0.15, 0.15, 0.15, 1) + btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) + btn.label:SetTextColor(0.8, 0.8, 0.8) + end + end + + -- Continent buttons + local halfWidth = (PANEL_WIDTH - PANEL_PADDING * 2 - BUTTON_SPACING) / 2 + + local btnKalimdor = CreateSelectorButton("MMMFind_Kalimdor", findPanel, halfWidth, L:GetLocalizedString("Kalimdor")) + btnKalimdor:SetPoint("TOPLEFT", findPanel, "TOPLEFT", PANEL_PADDING, -PANEL_PADDING) + + local btnEK = CreateSelectorButton("MMMFind_EK", findPanel, halfWidth, L:GetLocalizedString("Eastern Kingdoms")) + btnEK:SetPoint("TOPLEFT", btnKalimdor, "TOPRIGHT", BUTTON_SPACING, 0) + + -- Type buttons + local thirdWidth = (PANEL_WIDTH - PANEL_PADDING * 2 - BUTTON_SPACING * 2) / 3 + + local btnDungeon = CreateSelectorButton("MMMFind_Dungeon", findPanel, thirdWidth, L:GetLocalizedString("Dungeons")) + btnDungeon:SetPoint("TOPLEFT", btnKalimdor, "BOTTOMLEFT", 0, -BUTTON_SPACING) + + local btnRaid = CreateSelectorButton("MMMFind_Raid", findPanel, thirdWidth, L:GetLocalizedString("Raids")) + btnRaid:SetPoint("TOPLEFT", btnDungeon, "TOPRIGHT", BUTTON_SPACING, 0) + + local btnWorldBoss = CreateSelectorButton("MMMFind_WorldBoss", findPanel, thirdWidth, L:GetLocalizedString("World Bosses")) + btnWorldBoss:SetPoint("TOPLEFT", btnRaid, "TOPRIGHT", BUTTON_SPACING, 0) + + -- Scroll frame for the instance list + local listAreaTop = PANEL_PADDING + BUTTON_HEIGHT * 2 + BUTTON_SPACING * 2 + 4 + + local scrollFrame = CreateFrame("ScrollFrame", "MMMFind_Scroll", findPanel, "FauxScrollFrameTemplate") + scrollFrame:SetPoint("TOPLEFT", findPanel, "TOPLEFT", PANEL_PADDING, -listAreaTop) + scrollFrame:SetPoint("BOTTOMRIGHT", findPanel, "BOTTOMRIGHT", -PANEL_PADDING - 22, PANEL_PADDING) + + -- Row buttons + local rowButtons = {} + for i = 1, MAX_VISIBLE_ROWS do + local row = CreateFrame("Button", "MMMFind_Row" .. i, findPanel) + row:SetHeight(ROW_HEIGHT) + row:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, -((i - 1) * ROW_HEIGHT)) + row:SetPoint("RIGHT", scrollFrame, "RIGHT", 0, 0) + + local highlight = row:CreateTexture(nil, "HIGHLIGHT") + highlight:SetAllPoints(row) + highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") + highlight:SetBlendMode("ADD") + highlight:SetAlpha(0.4) + + local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + nameText:SetPoint("LEFT", row, "LEFT", 4, 0) + nameText:SetJustifyH("LEFT") + row.nameText = nameText + + local lvlText = row:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall") + lvlText:SetPoint("RIGHT", row, "RIGHT", -4, 0) + lvlText:SetJustifyH("RIGHT") + row.lvlText = lvlText + + row:SetScript("OnEnter", function() + if row.dataID then + WorldMapTooltip:SetOwner(row, "ANCHOR_LEFT") + WorldMapTooltip:AddLine(row.tooltipNameText, 1, 0.82, 0) + if row.tooltipLvlText then + WorldMapTooltip:AddLine(row.tooltipLvlText, 1, 1, 1) + end + WorldMapTooltip:Show() + end + end) + row:SetScript("OnLeave", function() + WorldMapTooltip:Hide() + end) + + row:Hide() + rowButtons[i] = row + end + + -- Current filtered + sorted list cache + local currentList = {} + + -- Sort function: level then name + local function sortLvl(a, b) + local _, _, alvlStr = string.find(a.description or "", "^(%d+)") + local _, _, blvlStr = string.find(b.description or "", "^(%d+)") + local alvl = tonumber(alvlStr) or 0 + local blvl = tonumber(blvlStr) or 0 + if alvl == blvl then return (a.name or "") < (b.name or "") end + return alvl < blvl + end + + -- Set text on a FontString and truncate with ellipsis if rendered width > maxWidth. + -- fontString : a valid FontString object + -- text : string to set + -- maxWidth : maximum allowed width in pixels (number) + local function SetFontStringTruncated(fontString, text, maxWidth) + if not fontString or type(text) ~= "string" or type(maxWidth) ~= "number" then return end + fontString:SetText(text) + if fontString:GetStringWidth() <= maxWidth then return end -- return if whole string isn't longer anyways + + local ELLIPSIS = "…" + local lo = 0; local hi = string.len(text); local best = 0 + while lo <= hi do -- binary search to determine the maximum string length including ellipsis + local mid = math.floor((lo + hi) / 2) + local substr = string.sub(text, 1, mid) .. ELLIPSIS + fontString:SetText(substr) + if fontString:GetStringWidth() <= maxWidth then + best = mid + lo = mid + 1 + else + hi = mid - 1 + end + end + + if best > 0 then + fontString:SetText(string.sub(text, 1, best) .. ELLIPSIS) + else + fontString:SetText(ELLIPSIS) -- only possible when maxWidth is way too small + end + end + + local function RefreshFindList() + local flatData = ModernMapMarkers_GetFlatData() + currentList = {} + + for _, data in ipairs(flatData) do + if data.continent == activeContinent and data.type == activeType then + table.insert(currentList, data) + end + end + table.sort(currentList, sortLvl) + + local totalRows = table.getn(currentList) + local displayRows = math.min(totalRows, MAX_VISIBLE_ROWS) + + local panelHeight = listAreaTop + (displayRows * ROW_HEIGHT) + PANEL_PADDING + 4 + if totalRows > MAX_VISIBLE_ROWS then + panelHeight = listAreaTop + (MAX_VISIBLE_ROWS * ROW_HEIGHT) + PANEL_PADDING + 4 + end + findPanel:SetHeight(panelHeight) + + FauxScrollFrame_Update(scrollFrame, totalRows, MAX_VISIBLE_ROWS, ROW_HEIGHT) + + local offset = FauxScrollFrame_GetOffset(scrollFrame) + local lvlLabel = L:GetLocalizedString("Level") or "Level" + + for i = 1, MAX_VISIBLE_ROWS do + local row = rowButtons[i] + local dataIndex = offset + i + + if dataIndex <= totalRows then + local data = currentList[dataIndex] + local localizedName = L:GetLocalizedString(data.name, data.type) + row.nameText:SetText(localizedName) + row.tooltipNameText = localizedName -- store the full name text so it never gets truncated in the tooltip + row.tooltipLvlText = lvlLabel .. " " .. data.description + + if data.description then + row.lvlText:SetText(data.description) + else + row.lvlText:SetText("") + end + + SetFontStringTruncated(row.nameText, localizedName, row:GetWidth() - row.lvlText:GetStringWidth()) + row.nameText:SetWidth(row:GetWidth() - row.lvlText:GetStringWidth()) + + row.dataID = data.id + row:SetScript("OnClick", function() + ModernMapMarkers_FindMarker(data.id) + end) + row:Show() + else + row.nameText:SetText("") + row.lvlText:SetText("") + row.dataID = nil + row:Hide() + end + end + end + + scrollFrame:SetScript("OnVerticalScroll", function() + FauxScrollFrame_OnVerticalScroll(ROW_HEIGHT, RefreshFindList) + end) + + -- Button click handlers + local function UpdateButtonStates() + SetButtonActive(btnKalimdor, activeContinent == 1) + SetButtonActive(btnEK, activeContinent == 2) + SetButtonActive(btnDungeon, activeType == "DUNGEON") + SetButtonActive(btnRaid, activeType == "RAID") + SetButtonActive(btnWorldBoss, activeType == "WORLDBOSS") + end + + btnKalimdor:SetScript("OnClick", function() + activeContinent = 1 + UpdateButtonStates() + RefreshFindList() + end) + + btnEK:SetScript("OnClick", function() + activeContinent = 2 + UpdateButtonStates() + RefreshFindList() + end) + + btnDungeon:SetScript("OnClick", function() + activeType = "DUNGEON" + UpdateButtonStates() + RefreshFindList() + end) + + btnRaid:SetScript("OnClick", function() + activeType = "RAID" + UpdateButtonStates() + RefreshFindList() + end) + + btnWorldBoss:SetScript("OnClick", function() + activeType = "WORLDBOSS" + UpdateButtonStates() + RefreshFindList() + end) + + function UpdateFindPanel() + UpdateButtonStates() + RefreshFindList() + end + + -- Close panel when the world map closes + local origOnHide = WorldMapFrame:GetScript("OnHide") + WorldMapFrame:SetScript("OnHide", function() + if origOnHide then origOnHide() end + findPanel:Hide() + end) + + UpdateButtonStates() + + -- pfUI Skinning + if isPfUI and _G.pfUI and _G.pfUI.api then + if _G.pfUI.api.SkinDropDown then + _G.pfUI.api.SkinDropDown(filterFrame) + _G.pfUI.api.SkinDropDown(findFrame) + end + if _G.pfUI.api.SkinButton then + _G.pfUI.api.SkinButton(btnKalimdor) + _G.pfUI.api.SkinButton(btnEK) + _G.pfUI.api.SkinButton(btnDungeon) + _G.pfUI.api.SkinButton(btnRaid) + _G.pfUI.api.SkinButton(btnWorldBoss) + end + end + + -- Apply saved visibility state + if ModernMapMarkersDB and ModernMapMarkersDB.hideDropdowns then + filterFrame:Hide() + findFrame:Hide() + end + +end + +-- Debug Utilities +SLASH_MMMDEBUG1 = "/mmmzones" +SlashCmdList["MMMDEBUG"] = function() + if not DEFAULT_CHAT_FRAME then return end + for contID = 1, 2 do + local contName = (contID == 1) and "Kalimdor" or "Eastern Kingdoms" + DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModernMapMarkers:|r Zone Indexes for " .. contName .. ":") + local zones = { GetMapZones(contID) } + for i, zoneName in ipairs(zones) do + DEFAULT_CHAT_FRAME:AddMessage(" " .. i .. ": " .. zoneName) + end + end +end + +-- Slash command to toggle dropdown visibility +SLASH_MMM1 = "/mmm" +SlashCmdList["MMM"] = function() + if type(ModernMapMarkersDB) ~= "table" then + ModernMapMarkersDB = { filters = {} } + end + ModernMapMarkersDB.hideDropdowns = not ModernMapMarkersDB.hideDropdowns + + local filterFrame = getglobal("ModernMapMarkersFilter_Blizz") + local findFrame = getglobal("ModernMapMarkersFind_Blizz") + local findPanel = getglobal("ModernMapMarkersFind_Panel") + + if filterFrame and findFrame then + if ModernMapMarkersDB.hideDropdowns then + filterFrame:Hide() + findFrame:Hide() + if findPanel then findPanel:Hide() end + if DEFAULT_CHAT_FRAME then + DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModern|rMapMarkers: " .. L:GetLocalizedString("Dropdown menus hidden.")) + end + else + filterFrame:Show() + findFrame:Show() + if DEFAULT_CHAT_FRAME then + DEFAULT_CHAT_FRAME:AddMessage("|cff7fff7fModern|rMapMarkers: " .. L:GetLocalizedString("Dropdown menus shown.")) + end + end + end +end + +local initFrame = CreateFrame("Frame") +initFrame:RegisterEvent("VARIABLES_LOADED") +initFrame:SetScript("OnEvent", function() + L:Initialize() + MMM_GUI.InitializeWorldMapControls() + this:UnregisterEvent("VARIABLES_LOADED") +end) + _G.ModernMapMarkers_GUI = MMM_GUI \ No newline at end of file diff --git a/pfDB/MMM_pfDB.xml b/pfDB/MMM_pfDB.xml new file mode 100644 index 0000000..6ffbd02 --- /dev/null +++ b/pfDB/MMM_pfDB.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pfDB/MMM_pfDB_fixes.xml b/pfDB/MMM_pfDB_fixes.xml new file mode 100644 index 0000000..27138fc --- /dev/null +++ b/pfDB/MMM_pfDB_fixes.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pfDB/deDE/units_filtered.lua b/pfDB/deDE/units_filtered.lua new file mode 100644 index 0000000..d74eb81 --- /dev/null +++ b/pfDB/deDE/units_filtered.lua @@ -0,0 +1,20 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +if GetLocale() ~= "deDE" then return end + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["units"] = MMM_pfDB["units"] or {} +MMM_pfDB["units"]["deDE"] = { + [6109] = "Azuregos", + [12397] = "Lord Kazzak", + [14887] = "Ysondre", + [14888] = "Lethon", + [14889] = "Smariss", + [14890] = "Taerar", + [16184] = "Nerubischer Aufseher", + [59963] = "Cla'ckora", + [62059] = "Vater Lycan", + [80935] = "Ostarius", + [80936] = "Dunkler Plünderer von Karazhan", + [92213] = "Concavius", +} diff --git a/pfDB/deDE/zones_filtered.lua b/pfDB/deDE/zones_filtered.lua new file mode 100644 index 0000000..c2ec036 --- /dev/null +++ b/pfDB/deDE/zones_filtered.lua @@ -0,0 +1,96 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +if GetLocale() ~= "deDE" then return end + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["zones"] = MMM_pfDB["zones"] or {} +MMM_pfDB["zones"]["deDE"] = { + [1] = "Dun Morogh", + [3] = "Ödland", + [4] = "Verwüstete Lande", + [8] = "Sümpfe des Elends", + [10] = "Dämmerwald", + [11] = "Sumpfland", + [12] = "Wald von Elwynn", + [14] = "Durotar", + [15] = "Düstermarschen", + [16] = "Azshara", + [17] = "Brachland", + [19] = "Zul'Gurub", + [28] = "Westliche Pestländer", + [33] = "Schlingendorntal", + [35] = "Beutebucht", + [40] = "Westfall", + [41] = "Gebirgspass der Totenwinde", + [46] = "Brennende Steppe", + [47] = "Hinterland", + [51] = "Sengende Schlucht", + [85] = "Tirisfal", + [117] = "Basislager Grom'gol", + [130] = "Silberwald", + [133] = "Gnomeregan", + [139] = "Östliche Pestländer", + [141] = "Teldrassil", + [148] = "Dunkelküste", + [150] = "Hafen von Menethil", + [209] = "Burg Schattenfang", + [331] = "Ashenvale", + [340] = "Kargath", + [357] = "Feralas", + [392] = "Ratschet", + [400] = "Tausend Nadeln", + [405] = "Desolace", + [440] = "Tanaris", + [442] = "Auberdine", + [491] = "Kral der Klingenhauer", + [513] = "Die Insel Theramore", + [616] = "Hyjal", + [702] = "Rut'theran", + [717] = "Das Verlies", + [718] = "Höhlen des Wehklagens", + [719] = "Tiefschwarze Grotte", + [722] = "Hügel der Klingenhauer", + [796] = "Das Scharlachrote Kloster", + [978] = "Zul'Farrak", + [1108] = "Die Vergessene Küste", + [1120] = "Insel Sardor", + [1216] = "Holzschlundfeste", + [1337] = "Uldaman", + [1377] = "Silithus", + [1417] = "Versunkener Tempel", + [1497] = "Undercity", + [1519] = "Stormwind", + [1537] = "Ironforge", + [1637] = "Orgrimmar", + [1638] = "Thunder Bluff", + [2040] = "Alah'Thalas", + [2100] = "Maraudon", + [2159] = "Onyxias Hort", + [2279] = "Stratholme", + [2366] = "Der Schwarze Morast", + [2408] = "Schattenflucht", + [2437] = "Der Flammenschlund", + [2577] = "Düsterbruch", + [2677] = "Pechschwingenhort", + [2717] = "Geschmolzener Kern", + [3317] = "Dorf der Bruchhauer", + [3428] = "Ahn'Qiraj", + [3429] = "Ruinen von Ahn'Qiraj", + [3456] = "Naxxramas", + [3457] = "Turm von Karazhan", + [4021] = "Funkelwasserhafen ", + [5077] = "Mondsichelhain", + [5086] = "Karazhan Krypta", + [5087] = "Gewölbe von Sturmwind", + [5097] = "Smaragdsanktum", + [5098] = "Hassschmieden Steinbruch", + [5138] = "Die Todesminen", + [5139] = "Schwarzfelsspitze", + [5140] = "Schwarzfelstiefen", + [5142] = "Scholomance", + [5179] = "Gilneas", + [5180] = "Stadt von Gilneas", + [5561] = "Balor", + [5600] = "Drachenmal Zuflucht", + [5628] = "Ruine von Sturmschmied", +} diff --git a/pfDB/deDE/zones_filtered_fixes.lua b/pfDB/deDE/zones_filtered_fixes.lua new file mode 100644 index 0000000..ff36b91 --- /dev/null +++ b/pfDB/deDE/zones_filtered_fixes.lua @@ -0,0 +1,7 @@ +if GetLocale() ~= "deDE" then return end + +-- modifications +MMM_pfDB["zones"]["deDE"][15] = "Marschen von Dustwallow" + +-- additions +MMM_pfDB["zones"]["deDE"][-5] = "Untere Hallen von Karazhan" diff --git a/pfDB/enUS/units_filtered.lua b/pfDB/enUS/units_filtered.lua new file mode 100644 index 0000000..87f626f --- /dev/null +++ b/pfDB/enUS/units_filtered.lua @@ -0,0 +1,18 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["units"] = MMM_pfDB["units"] or {} +MMM_pfDB["units"]["enUS"] = { + [6109] = "Azuregos", + [12397] = "Lord Kazzak", + [14887] = "Ysondre", + [14888] = "Lethon", + [14889] = "Emeriss", + [14890] = "Taerar", + [16184] = "Nerubian Overseer", + [59963] = "Cla'ckora", + [62059] = "Father Lycan", + [80935] = "Ostarius", + [80936] = "Dark Reaver of Karazhan", + [92213] = "Concavius", +} diff --git a/pfDB/enUS/zones_filtered.lua b/pfDB/enUS/zones_filtered.lua new file mode 100644 index 0000000..345dd64 --- /dev/null +++ b/pfDB/enUS/zones_filtered.lua @@ -0,0 +1,94 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["zones"] = MMM_pfDB["zones"] or {} +MMM_pfDB["zones"]["enUS"] = { + [1] = "Dun Morogh", + [3] = "Badlands", + [4] = "Blasted Lands", + [8] = "Swamp of Sorrows", + [10] = "Duskwood", + [11] = "Wetlands", + [12] = "Elwynn Forest", + [14] = "Durotar", + [15] = "Dustwallow Marsh", + [16] = "Azshara", + [17] = "The Barrens", + [19] = "Zul'Gurub", + [28] = "Western Plaguelands", + [33] = "Stranglethorn Vale", + [35] = "Booty Bay", + [40] = "Westfall", + [41] = "Deadwind Pass", + [46] = "Burning Steppes", + [47] = "The Hinterlands", + [51] = "Searing Gorge", + [85] = "Tirisfal Glades", + [117] = "Grom'gol Base Camp", + [130] = "Silverpine Forest", + [133] = "Gnomeregan", + [139] = "Eastern Plaguelands", + [141] = "Teldrassil", + [148] = "Darkshore", + [150] = "Menethil Harbor", + [209] = "Shadowfang Keep", + [331] = "Ashenvale", + [340] = "Kargath", + [357] = "Feralas", + [392] = "Ratchet", + [400] = "Thousand Needles", + [405] = "Desolace", + [440] = "Tanaris", + [442] = "Auberdine", + [491] = "Razorfen Kraul", + [513] = "Theramore Isle", + [616] = "Hyjal", + [702] = "Rut'theran Village", + [717] = "The Stockade", + [718] = "Wailing Caverns", + [719] = "Blackfathom Deeps", + [722] = "Razorfen Downs", + [796] = "Scarlet Monastery", + [978] = "Zul'Farrak", + [1108] = "The Forgotten Coast", + [1120] = "Sardor Isle", + [1216] = "Timbermaw Hold", + [1337] = "Uldaman", + [1377] = "Silithus", + [1417] = "Sunken Temple", + [1497] = "Undercity", + [1519] = "Stormwind City", + [1537] = "Ironforge", + [1637] = "Orgrimmar", + [1638] = "Thunder Bluff", + [2040] = "Alah'Thalas", + [2100] = "Maraudon", + [2159] = "Onyxia's Lair", + [2279] = "Stratholme", + [2366] = "The Black Morass", + [2408] = "Shadowprey Village", + [2437] = "Ragefire Chasm", + [2577] = "Dire Maul", + [2677] = "Blackwing Lair", + [2717] = "Molten Core", + [3317] = "Revantusk Village", + [3428] = "Ahn'Qiraj", + [3429] = "Ruins of Ahn'Qiraj", + [3456] = "Naxxramas", + [3457] = "Tower of Karazhan", + [4021] = "Sparkwater Port", + [5077] = "Crescent Grove", + [5086] = "Karazhan Crypt", + [5087] = "Stormwind Vault", + [5097] = "Emerald Sanctum", + [5098] = "Hateforge Quarry", + [5138] = "The Deadmines", + [5139] = "Blackrock Spire", + [5140] = "Blackrock Depths", + [5142] = "Scholomance", + [5179] = "Gilneas", + [5180] = "Gilneas City", + [5561] = "Balor", + [5600] = "Dragonmaw Retreat", + [5628] = "Stormwrought Ruins", +} diff --git a/pfDB/enUS/zones_filtered_fixes.lua b/pfDB/enUS/zones_filtered_fixes.lua new file mode 100644 index 0000000..bf2f028 --- /dev/null +++ b/pfDB/enUS/zones_filtered_fixes.lua @@ -0,0 +1,8 @@ +-- modifications + +-- additions +MMM_pfDB["zones"]["enUS"][-1] = "Moonwhisper Coast" +MMM_pfDB["zones"]["enUS"][-2] = "Moonhoof Village" +MMM_pfDB["zones"]["enUS"][-3] = "Windhorn Canyon" +MMM_pfDB["zones"]["enUS"][-4] = "Frostmane Hollow" +MMM_pfDB["zones"]["enUS"][-5] = "Lower Karazhan Halls" diff --git a/pfDB/esES/units_filtered.lua b/pfDB/esES/units_filtered.lua new file mode 100644 index 0000000..41b711a --- /dev/null +++ b/pfDB/esES/units_filtered.lua @@ -0,0 +1,20 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +if GetLocale() ~= "esES" then return end + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["units"] = MMM_pfDB["units"] or {} +MMM_pfDB["units"]["esES"] = { + [6109] = "Azuregos", + [12397] = "Lord Kazzak", + [14887] = "Ysondre", + [14888] = "Lethon", + [14889] = "Emeriss", + [14890] = "Taerar", + [16184] = "Sobrestante Nerubiano", + [59963] = "Cla'ckora", + [62059] = "Padre Lycan", + [80935] = "Ostarius", + [80936] = "Segador Oscuro de Karazhan", + [92213] = "Concavius", +} diff --git a/pfDB/esES/zones_filtered.lua b/pfDB/esES/zones_filtered.lua new file mode 100644 index 0000000..d34330f --- /dev/null +++ b/pfDB/esES/zones_filtered.lua @@ -0,0 +1,96 @@ +-- created with https://codeberg.org/hyperhumble/pfDB-Localization-Helper + +if GetLocale() ~= "esES" then return end + +MMM_pfDB = MMM_pfDB or {} +MMM_pfDB["zones"] = MMM_pfDB["zones"] or {} +MMM_pfDB["zones"]["esES"] = { + [1] = "Dun Morogh", + [3] = "Tierras Inhóspitas", + [4] = "Tierras Devastadas", + [8] = "Pantano de las Penas", + [10] = "Bosque del Ocaso", + [11] = "Los Humedales", + [12] = "Bosque de Elwynn", + [14] = "Durotar", + [15] = "Marjal Revolcafango", + [16] = "Azshara", + [17] = "Los Baldíos", + [19] = "Zul'Gurub", + [28] = "Tierras de la Peste del Oeste", + [33] = "Vega de Tuercespina", + [35] = "Bahía del Botín", + [40] = "Páramos del Poniente", + [41] = "Paso de la Muerte", + [46] = "Las Estepas Ardientes", + [47] = "Tierras del Interior", + [51] = "La Garganta de Fuego", + [85] = "Claros de Tirisfal", + [117] = "Campamento Base Grom'gol", + [130] = "Bosque de Argénteos", + [133] = "Gnomeregan", + [139] = "Tierras de la Peste del Este", + [141] = "Teldrassil", + [148] = "Costa Oscura", + [150] = "Puerto Menethil", + [209] = "Fortaleza Colmillo Oscuro", + [331] = "Vallefresno", + [340] = "Kargath", + [357] = "Feralas", + [392] = "Ratchett", + [400] = "Las Mil Agujas", + [405] = "Desolace", + [440] = "Tanaris", + [442] = "Auberdine", + [491] = "Madriguera de Rajacieno", + [513] = "Isla Theramore", + [616] = "Hyjal", + [702] = "Aldea Rut'theran", + [717] = "La Mazmorras", + [718] = "Cuevas de los Lamentos", + [719] = "Cavernas de Brazanegra", + [722] = "Zahúrda Rajacieno", + [796] = "Monasterio Escarlata", + [978] = "Zul'Farrak", + [1108] = "La Costa Olvidada", + [1120] = "Isla Sardor", + [1216] = "Bastión de los Timbermaw", + [1337] = "Uldaman", + [1377] = "Silithus", + [1417] = "Templo Sumergido", + [1497] = "Entrañas", + [1519] = "Ciudad de Ventormenta", + [1537] = "Forjaz", + [1637] = "Orgrimmar", + [1638] = "Cima del Trueno", + [2040] = "Alah'Thalas", + [2100] = "Maraudon", + [2159] = "Guarida de Onyxia", + [2279] = "Stratholme", + [2366] = "La Ciénaga Negra", + [2408] = "Poblado Presacaz", + [2437] = "Sima Ígnea", + [2577] = "La Masacre", + [2677] = "Guarida Alanegra", + [2717] = "Núcleo de Magma", + [3317] = "Aldea Revantusk", + [3428] = "Ahn'Qiraj", + [3429] = "Ruinas de Ahn'Qiraj", + [3456] = "Naxxramas", + [3457] = "Torre de Karazhan", + [4021] = "Puerto Aguachispa", + [5077] = "Claro de la Media Luna", + [5086] = "Cripta de Karazhan", + [5087] = "Bóveda de Ventormenta", + [5097] = "Sanctum Esmeralda", + [5098] = "Cantera Hateforge", + [5138] = "Las Minas de la Muerte", + [5139] = "Cima Roca Negra", + [5140] = "Profundidades Roca Negra", + [5142] = "Scholomance", + [5179] = "Gilneas", + [5180] = "Ciudad Gilneas", + [5561] = "Balor", + [5600] = "Refugio Faucedrago", + [5628] = "Ruinas Forjatormenta", +} diff --git a/pfDB/esES/zones_filtered_fixes.lua b/pfDB/esES/zones_filtered_fixes.lua new file mode 100644 index 0000000..6a2e4aa --- /dev/null +++ b/pfDB/esES/zones_filtered_fixes.lua @@ -0,0 +1,11 @@ +if GetLocale() ~= "esES" then return end + +-- modifications +MMM_pfDB["zones"]["esES"][1216] = "Bastión Fauces de Madera" + +-- additions +MMM_pfDB["zones"]["esES"][-1] = "Costa Susurrolunar" +MMM_pfDB["zones"]["esES"][-2] = "Aldea Pezuña Lunar" +MMM_pfDB["zones"]["esES"][-3] = "Cañón Cornaviento" +MMM_pfDB["zones"]["esES"][-4] = "Hondonada Peloescarcha" +MMM_pfDB["zones"]["esES"][-5] = "Salas Inferiores de Karazhan" diff --git a/pfDB/pfDB.xml b/pfDB/pfDB.xml new file mode 100644 index 0000000..2f56ed2 --- /dev/null +++ b/pfDB/pfDB.xml @@ -0,0 +1,6 @@ + + + +