diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dba5df0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/References \ No newline at end of file diff --git a/Data/pfDB/meta-turtle.lua b/Data/pfDB/meta-turtle.lua index 0613eb1..ab091b9 100644 --- a/Data/pfDB/meta-turtle.lua +++ b/Data/pfDB/meta-turtle.lua @@ -2809,4 +2809,568 @@ pfDB["meta-turtle"] = { [92221] = "H", [93115] = "AH", }, -} + ["trainers"] = { + ["warrior"] = { + [3593] = "A", + [914] = "A", + [4594] = "H", + [4087] = "A", + [2131] = "H", + [4595] = "H", + [92198] = "H", + [5114] = "A", + [8141] = "A", + [4593] = "H", + [2119] = "H", + [7315] = "A", + [3153] = "H", + [1229] = "A", + [3353] = "H", + [80104] = "H", + [3059] = "H", + [5480] = "A", + [1901] = "A", + [5113] = "A", + [3043] = "H", + [3063] = "H", + [3598] = "A", + [80247] = "AH", + [911] = "A", + [913] = "A", + [985] = "H", + [62428] = "AH", + [3042] = "H", + [4089] = "A", + [3354] = "H", + [3169] = "H", + [912] = "A", + [3041] = "H", + [80217] = "AH", + [5479] = "A", + [3408] = "H", + }, + ["mage"] = { + [4568] = "H", + [3047] = "H", + [5144] = "A", + [2128] = "H", + [5885] = "H", + [7312] = "A", + [62863] = "AH", + [5498] = "A", + [5883] = "H", + [80964] = "H", + [80246] = "AH", + [60628] = "A", + [2124] = "H", + [5497] = "A", + [5145] = "A", + [4566] = "H", + [198] = "A", + [80402] = "A", + [1228] = "A", + [80218] = "AH", + [5884] = "H", + [60516] = "A", + [944] = "A", + [5146] = "A", + [5882] = "H", + [4567] = "H", + [3049] = "H", + [5880] = "H", + [80857] = "H", + [3048] = "H", + [7311] = "H", + [80108] = "H", + [328] = "A", + }, + ["rogue"] = { + [4215] = "A", + [4582] = "H", + [2122] = "H", + [4214] = "A", + [5167] = "A", + [3594] = "A", + [3327] = "H", + [4584] = "H", + [1234] = "A", + [5165] = "A", + [1411] = "AH", + [3599] = "A", + [915] = "A", + [3170] = "H", + [917] = "A", + [80223] = "AH", + [80106] = "H", + [13283] = "A", + [80248] = "AH", + [2130] = "H", + [4583] = "H", + [3328] = "H", + [5166] = "A", + [918] = "A", + [3155] = "H", + [3401] = "H", + [916] = "A", + [4163] = "A", + }, + ["druid"] = { + [4218] = "A", + [4219] = "A", + [3060] = "H", + [3064] = "H", + [9465] = "A", + [8142] = "H", + [3602] = "A", + [3036] = "H", + [12042] = "AH", + [5506] = "A", + [3597] = "A", + [4217] = "A", + [63084] = "A", + [3034] = "H", + [5504] = "A", + [63075] = "H", + [5505] = "A", + [3033] = "H", + }, + ["hunter"] = { + [61624] = "A", + [8308] = "A", + [3596] = "A", + [80855] = "A", + [5115] = "A", + [61625] = "A", + [80245] = "AH", + [3963] = "A", + [10930] = "A", + [81050] = "H", + [3601] = "A", + [61626] = "AH", + [4205] = "A", + [5515] = "A", + [1231] = "A", + [3039] = "H", + [4138] = "A", + [3154] = "H", + [4146] = "A", + [5501] = "A", + [3038] = "H", + [1404] = "H", + [3061] = "H", + [60484] = "H", + [61640] = "A", + [80105] = "H", + [60483] = "H", + [60485] = "H", + [987] = "H", + [61627] = "A", + [5116] = "A", + [3352] = "H", + [80458] = "A", + [80219] = "AH", + [5117] = "A", + [3407] = "H", + [5517] = "A", + [895] = "A", + [3171] = "H", + [80856] = "AH", + [5516] = "A", + [3040] = "H", + [60487] = "H", + [60486] = "H", + [80903] = "AH", + [61628] = "A", + [3406] = "H", + [3065] = "H", + }, + ["shaman"] = { + [3032] = "H", + [62801] = "H", + [986] = "H", + [3344] = "H", + [3062] = "H", + [3066] = "H", + [62803] = "H", + [13417] = "H", + [3157] = "H", + [3403] = "H", + [3030] = "H", + [3173] = "H", + [3031] = "H", + [62805] = "H", + }, + ["priest"] = { + [4606] = "H", + [63098] = "H", + [4090] = "A", + [5142] = "A", + [837] = "A", + [5484] = "A", + [5489] = "A", + [2129] = "H", + [2123] = "H", + [3046] = "H", + [4607] = "H", + [4608] = "H", + [80243] = "AH", + [11406] = "A", + [376] = "A", + [4091] = "A", + [3707] = "A", + [4092] = "A", + [3600] = "A", + [3045] = "H", + [80401] = "A", + [1226] = "A", + [62976] = "H", + [3044] = "H", + [11397] = "A", + [63096] = "H", + [63097] = "H", + [63099] = "H", + [11401] = "A", + [375] = "A", + [377] = "A", + [80221] = "AH", + [3595] = "A", + [3706] = "A", + [5141] = "A", + [5143] = "A", + [6018] = "A", + [6014] = "A", + }, + ["warlock"] = { + [460] = "A", + [5173] = "A", + [80107] = "H", + [5172] = "A", + [61632] = "H", + [461] = "A", + [3172] = "H", + [459] = "A", + [63197] = "A", + [63161] = "A", + [5612] = "A", + [3324] = "H", + [61633] = "H", + [4563] = "H", + [988] = "H", + [4564] = "H", + [906] = "A", + [2126] = "H", + [61636] = "H", + [3325] = "H", + [3156] = "H", + [4565] = "H", + [2127] = "H", + [5496] = "A", + [5171] = "A", + [63196] = "A", + [5495] = "A", + [3326] = "H", + [61635] = "H", + [61634] = "H", + }, + ["paladin"] = { + [80244] = "A", + [5491] = "A", + [1232] = "A", + [5148] = "A", + [5149] = "A", + [926] = "A", + [8140] = "A", + [925] = "A", + [927] = "A", + [5492] = "A", + [80220] = "A", + [928] = "A", + [5147] = "A", + }, + }, + ["professions"] = { + ["riding"] = { + [80452] = "AH", + [62183] = "A", + [7954] = "A", + [4753] = "A", + [3690] = "H", + [4752] = "H", + [4732] = "A", + [4772] = "A", + [4773] = "H", + [7953] = "H", + }, + ["weapon"] = { + [11869] = "H", + [11870] = "H", + [13084] = "A", + [11865] = "A", + [80130] = "H", + [2704] = "H", + [11866] = "A", + [11868] = "H", + [80228] = "AH", + [11867] = "A", + }, + ["cooking"] = { + [4210] = "A", + [3026] = "H", + [91950] = "AH", + [1355] = "A", + [3087] = "A", + [5159] = "A", + [4552] = "H", + [1699] = "A", + [91754] = "H", + [80101] = "AH", + [5482] = "A", + [61883] = "AH", + [3399] = "H", + }, + ["skinning"] = { + [6291] = "A", + [6292] = "A", + [7087] = "H", + [8144] = "H", + [12030] = "H", + [1292] = "A", + [7089] = "H", + [7088] = "H", + [6295] = "A", + }, + ["firstaid"] = { + [3373] = "H", + [6094] = "A", + [4211] = "A", + [3181] = "A", + [91743] = "H", + [4591] = "H", + [5150] = "A", + [5759] = "H", + [2798] = "H", + [5943] = "H", + [2327] = "A", + [5939] = "H", + }, + ["alchemy"] = { + [4160] = "A", + [1215] = "A", + [4900] = "A", + [3009] = "H", + [2132] = "H", + [3603] = "A", + [4611] = "H", + [4609] = "H", + [11044] = "H", + [1470] = "A", + [2837] = "AH", + [11047] = "H", + [3964] = "A", + [7948] = "H", + [5499] = "A", + [3184] = "H", + [11041] = "A", + [1386] = "H", + [2391] = "H", + [11042] = "A", + [5177] = "A", + [61505] = "AH", + [91202] = "H", + [5500] = "A", + [61835] = "A", + [1246] = "A", + [11046] = "H", + [3347] = "H", + }, + ["blacksmithing"] = { + [4605] = "H", + [957] = "H", + [6299] = "A", + [3174] = "H", + [10277] = "A", + [3557] = "H", + [514] = "A", + [10278] = "H", + [1241] = "A", + [10266] = "H", + [3136] = "A", + [4596] = "H", + [2998] = "H", + [10276] = "A", + [62143] = "A", + [1383] = "H", + [5511] = "H", + [3478] = "H", + [4258] = "A", + [7802] = "AH", + [3355] = "H", + [63056] = "H", + + }, + ["engineering"] = { + [1702] = "A", + [3290] = "A", + [4586] = "H", + [11028] = "A", + [11037] = "A", + [11025] = "H", + [11026] = "A", + [2857] = "H", + [61738] = "AH", + [3494] = "AH", + [10993] = "AH", + [1676] = "A", + [11031] = "H", + [5518] = "A", + [3412] = "H", + [11029] = "A", + [11017] = "H", + [5174] = "A", + }, + ["enchanting"] = { + [3606] = "A", + [11068] = "A", + [11066] = "H", + [11070] = "A", + [11067] = "H", + [11071] = "H", + [11065] = "A", + [5695] = "H", + [62290] = "A", + [5157] = "A", + [3345] = "H", + [4616] = "H", + [1317] = "A", + [4213] = "A", + [3011] = "H", + [7949] = "A", + [11074] = "H", + [11072] = "A", + }, + ["fishing"] = { + [3607] = "A", + [7946] = "A", + [5690] = "H", + [2367] = "A", + [62859] = "AH", + [91206] = "A", + [60447] = "AH", + [8137] = "AH", + [4307] = "A", + [60928] = "A", + [12961] = "H", + [5748] = "A", + [3497] = "AH", + [4305] = "A", + [5941] = "A", + [1651] = "A", + [12032] = "H", + [2834] = "AH", + [2626] = "AH", + [1700] = "A", + [3178] = "Wetlands", + [61838] = "AH", + [61274] = "A", + [5938] = "H", + [1683] = "H", + [2842] = "AH", + [3572] = "AH", + }, + ["herbalism"] = { + [2856] = "H", + [2390] = "H", + [4898] = "A", + [3965] = "A", + [61842] = "A", + [2114] = "H", + [908] = "AH", + [62974] = "H", + [1218] = "A", + [15477] = "H", + [1473] = "A", + [3604] = "A", + [12025] = "AH", + [3185] = "H", + [62286] = "A", + [61739] = "AH", + }, + ["leatherworking"] = { + [3967] = "A", + [1632] = "A", + [4588] = "H", + [1385] = "H", + [3069] = "H", + [223] = "H", + [11083] = "A", + [11081] = "A", + [5127] = "A", + [1466] = "A", + [11098] = "H", + [5811] = "H", + [3365] = "H", + [3703] = "AH", + [3008] = "H", + [3605] = "A", + [11096] = "A", + [61840] = "AH", + [3549] = "H", + [5564] = "A", + [11084] = "H", + [4212] = "A", + [3007] = "H", + [5784] = "AH", + }, + ["mining"] = { + [3001] = "H", + [61882] = "AH", + [1681] = "A", + [4598] = "H", + [1701] = "A", + [5513] = "A", + [4254] = "A", + [6297] = "A", + [3357] = "H", + [3137] = "A", + [5392] = "A", + }, + ["tailoring"] = { + [3523] = "H", + [1103] = "A", + [4193] = "A", + [3484] = "H", + [1300] = "A", + [2855] = "H", + [11050] = "A", + [1703] = "A", + [11051] = "H", + [11048] = "H", + [2627] = "AH", + [5153] = "A", + [3363] = "H", + [3704] = "H", + [4159] = "A", + [11049] = "H", + [5567] = "A", + [3004] = "H", + [1346] = "A", + [4576] = "H", + }, + ["jewelcrafting"] = { + [61918] = "H", + [61906] = "A", + [61921] = "H", + [61910] = "A", + [61925] = "H", + [61916] = "AH", + [61917] = "AH", + [61919] = "H", + [61907] = "A", + [61923] = "H", + [61927] = "H", + [61911] = "A", + [61924] = "H", + [61912] = "A", + }, + }, +} \ No newline at end of file diff --git a/Map/Map.lua b/Map/Map.lua index 127376c..8fb6e35 100644 --- a/Map/Map.lua +++ b/Map/Map.lua @@ -10,6 +10,7 @@ local function IsPermanentRole(role) or role=="mailbox" or role=="battlemaster" or role=="innkeeper" or role=="meetingStone" or role=="repair" or role=="spiritHealer" or role=="stableMaster" or role=="vendor" or role=="rareMob" + or role=="classTrainer" or role=="professionTrainer" end local function IsSpecialQuestNode(node) @@ -44,6 +45,8 @@ local function IsRoleEnabled(role) if role=="spiritHealer" then return settings:Get("showMapSpiritHealer") and true or false end if role=="stableMaster" then return settings:Get("showMapStableMaster") and true or false end if role=="vendor" then return settings:Get("showMapVendor") and true or false end + if role=="classTrainer" then return settings:Get("showMapClassTrainer") and true or false end + if role=="professionTrainer" then return settings:Get("showMapProfessionTrainer") and true or false end if role=="rareMob" then return settings:Get("showMapRareMonsters") and true or false end if not settings:Get("enableMapIcons") then return false end @@ -106,6 +109,43 @@ local TEX_SPIRITHEALER=ICON_ROOT.."spirithealer" local TEX_STABLEMASTER=ICON_ROOT.."stablemaster" local TEX_VENDOR=ICON_ROOT.."vendor" local TEX_RARE=ICON_ROOT.."rares" +-- Class/profession trainers share two ringed icon atlases (from the Trainer +-- addon, see References/Trainer). Each name maps to a {left,right,top,bottom} +-- sub-rectangle inside its atlas, so trainer pins set both the atlas texture and +-- these texture coordinates instead of a dedicated single-icon file. +local TEX_CLASSTRAINER=ICON_ROOT.."Ringed-Classes" +local TEX_PROFESSIONTRAINER=ICON_ROOT.."Ringed-Professions" + +-- {left,right,top,bottom} atlas coordinates, copied from References/Trainer +-- (TrainerLegacy.lua) and keyed by the lower-case class/profession names used by +-- the meta-turtle ["trainers"]/["professions"] tables. +local CLASS_TRAINER_COORDS={ + ["warrior"]={0,0.25,0,0.25}, ["mage"]={0.25,0.5,0,0.25}, ["rogue"]={0.495,0.745,0,0.25}, + ["druid"]={0.75,1,0,0.25}, ["hunter"]={0,0.25,0.25,0.5}, ["shaman"]={0.25,0.5,0.25,0.5}, + ["priest"]={0.5,0.75,0.25,0.5}, ["warlock"]={0.75,1,0.25,0.5}, ["paladin"]={0,0.25,0.5,0.75}, +} +local PROFESSION_TRAINER_COORDS={ + ["riding"]={0,0.25,0,0.25}, ["cooking"]={0.25,0.5,0,0.25}, ["skinning"]={0.5,0.75,0,0.25}, + ["firstaid"]={0.75,1,0,0.25}, ["alchemy"]={0,0.25,0.25,0.5}, ["blacksmithing"]={0.25,0.5,0.25,0.5}, + ["engineering"]={0.5,0.75,0.25,0.5}, ["enchanting"]={0.75,1,0.25,0.5}, ["fishing"]={0,0.25,0.5,0.75}, + ["herbalism"]={0.25,0.5,0.5,0.75}, ["leatherworking"]={0.5,0.75,0.5,0.75}, ["mining"]={0.75,1,0.5,0.75}, + ["tailoring"]={0,0.25,0.75,1}, ["weapon"]={0.25,0.5,0.75,1}, ["jewelcrafting"]={0.5,0.75,0.75,1}, +} + +-- Returns left,right,top,bottom texture coordinates for a node. Trainer pins +-- carve their icon out of an atlas; every other node uses the full texture. +-- Recycled pins therefore always get their coordinates reset to the full 0..1 +-- rectangle when they are reused for a non-trainer role. +local function TexCoordForNode(node) + if node and node.role=="classTrainer" then + local c=CLASS_TRAINER_COORDS[node.trainerKey or ""] + if c then return c[1],c[2],c[3],c[4] end + elseif node and node.role=="professionTrainer" then + local c=PROFESSION_TRAINER_COORDS[node.trainerKey or ""] + if c then return c[1],c[2],c[3],c[4] end + end + return 0,1,0,1 +end -- Turtle deliberately keeps full quest XP through 25 levels above the quest -- (Tortoise src/game/QuestDef.cpp). The server file is XP logic rather than a @@ -141,6 +181,8 @@ local function TextureForNode(node) if node.role=="spiritHealer" then return TEX_SPIRITHEALER end if node.role=="stableMaster" then return TEX_STABLEMASTER end if node.role=="vendor" then return TEX_VENDOR end + if node.role=="classTrainer" then return TEX_CLASSTRAINER end + if node.role=="professionTrainer" then return TEX_PROFESSIONTRAINER end if node.role=="rareMob" then return TEX_RARE end if node.role=="itemStart" then -- Presentation priority: PvP > Repeatable > Event > Turtle low-level gray > Normal. @@ -223,9 +265,13 @@ local function ApplyVisualRole(pin,node) pin.repeatable=node.repeatable and true or false pin.sourceKind=node.sourceKind pin.sourceID=node.sourceID + pin.trainerKey=node.trainerKey pin.displayName=node.sourceName or pin.displayName or "Quest source" pin.iconScaleKey=node.iconScaleKey or ScaleKeyForRole(node.role) pin.texture:SetTexture(TextureForNode(node)) + -- Trainer pins crop their icon from a shared atlas; reset to the full + -- rectangle for every other (recycled) role. + if pin.texture.SetTexCoord then pin.texture:SetTexCoord(TexCoordForNode(node)) end pin.texture:SetDrawLayer("OVERLAY",DrawSublevelForRole(node.role)) -- Miscellaneous/rare markers stay below quest pins so an overlapping -- quest objective, starter or turn-in remains visible and clickable. @@ -245,6 +291,10 @@ function M:GetTextureForNode(node) return TextureForNode(node) end +function M:GetTexCoordForNode(node) + return TexCoordForNode(node) +end + function M:IsGrayAvailableQuest(node) return IsGrayAvailableQuest(node) end @@ -276,7 +326,8 @@ function M:GetPinScale(pin) if pin and (pin.role=="auctioneer" or pin.role=="banker" or pin.role=="flightMaster" or pin.role=="mailbox" or pin.role=="battlemaster" or pin.role=="innkeeper" or pin.role=="meetingStone" or pin.role=="repair" or pin.role=="spiritHealer" or - pin.role=="stableMaster" or pin.role=="vendor") then + pin.role=="stableMaster" or pin.role=="vendor" or + pin.role=="classTrainer" or pin.role=="professionTrainer") then return 0.9 end return 1 @@ -398,8 +449,25 @@ local function AttachWorldMapPinInput(pin) if not pin then return end pin:EnableMouse(true) pin:RegisterForClicks("LeftButtonUp") - pin:SetScript("OnEnter",function() QuestieOcto.Tooltips:Show(this) end) - pin:SetScript("OnLeave",function() QuestieOcto.Tooltips:Hide(this) end) + pin:SetScript("OnEnter",function() + QuestieOcto.Tooltips:Show(this) + -- Hovering an objective pin drives the same dim/glow highlight as hovering + -- the quest header in the tracker: this quest's objectives stay bright and + -- glow while everything else fades. Only objective roles trigger it so + -- pickup/turn-in markers keep the normal hover behavior. + if QuestieOcto.MapHighlight and this.questID + and QuestieOcto.Visuals and QuestieOcto.Visuals:IsObjectiveRole(this.role) then + this.highlightArmed=true + QuestieOcto.MapHighlight:Set(this.questID) + end + end) + pin:SetScript("OnLeave",function() + QuestieOcto.Tooltips:Hide(this) + if this.highlightArmed and QuestieOcto.MapHighlight then + this.highlightArmed=nil + QuestieOcto.MapHighlight:Clear() + end + end) -- Full Node objective dots re-roll their quest color on click; otherwise a -- continent-map marker still behaves as a zone-entry target. pin:SetScript("OnClick",function() @@ -674,6 +742,9 @@ function M:RenderItemStartArea(area,generation,continentZoneMapID) pin.displayName=area.displayName pin.clusterCount=area.n pin.texture:SetTexture(TextureForNode({role="itemStart",questID=area.questID,event=pin.event,pvp=pin.pvp,repeatable=pin.repeatable})) + -- Item-start-area pins use the full texture (defensive reset in case this + -- frame was ever recycled from an atlas-cropped trainer pin). + if pin.texture.SetTexCoord then pin.texture:SetTexCoord(0,1,0,1) end pin.texture:SetDrawLayer("OVERLAY",5) if QuestieOcto.Visuals then QuestieOcto.Visuals:ApplyPin(pin,{role="itemStart",questID=area.questID,pvp=pin.pvp,repeatable=pin.repeatable},false,1) @@ -1217,6 +1288,7 @@ function M:OnSettingChanged(key,value) key=="showMapFlightMaster" or key=="showMapMailbox" or key=="showMapBattlemaster" or key=="showMapInnkeeper" or key=="showMapMeetingStone" or key=="showMapRepair" or key=="showMapSpiritHealer" or key=="showMapStableMaster" or key=="showMapVendor" or + key=="showMapClassTrainer" or key=="showMapProfessionTrainer" or key=="showMapRareMonsters" then self:RequestSync(true) end diff --git a/Map/Minimap.lua b/Map/Minimap.lua index 2dce4fe..dcadecc 100644 --- a/Map/Minimap.lua +++ b/Map/Minimap.lua @@ -33,6 +33,7 @@ local function IsPermanentRole(role) or role=="mailbox" or role=="battlemaster" or role=="innkeeper" or role=="meetingStone" or role=="repair" or role=="spiritHealer" or role=="stableMaster" or role=="vendor" or role=="rareMob" + or role=="classTrainer" or role=="professionTrainer" end local function IsRoleEnabled(role) @@ -48,6 +49,8 @@ local function IsRoleEnabled(role) if role=="spiritHealer" then return settings:Get("showMinimapSpiritHealer") and true or false end if role=="stableMaster" then return settings:Get("showMinimapStableMaster") and true or false end if role=="vendor" then return settings:Get("showMinimapVendor") and true or false end + if role=="classTrainer" then return settings:Get("showMinimapClassTrainer") and true or false end + if role=="professionTrainer" then return settings:Get("showMinimapProfessionTrainer") and true or false end if role=="rareMob" then return settings:Get("showMinimapRareMonsters") and true or false end if not settings:Get("enableMiniMapIcons") then return false end @@ -122,6 +125,7 @@ function MM:OnSettingChanged(key,value) key=="showMinimapFlightMaster" or key=="showMinimapMailbox" or key=="showMinimapBattlemaster" or key=="showMinimapInnkeeper" or key=="showMinimapMeetingStone" or key=="showMinimapRepair" or key=="showMinimapSpiritHealer" or key=="showMinimapStableMaster" or key=="showMinimapVendor" or + key=="showMinimapClassTrainer" or key=="showMinimapProfessionTrainer" or key=="showMinimapRareMonsters" then self:UpdatePositions(true) return @@ -383,9 +387,13 @@ local function ApplyVisual(pin,node) pin.repeatable=node.repeatable and true or false pin.sourceKind=node.sourceKind pin.sourceID=node.sourceID + pin.trainerKey=node.trainerKey pin.displayName=node.sourceName or pin.displayName or "Quest source" pin.iconScaleKey=node.iconScaleKey or QuestieOcto.Map:GetScaleKeyForRole(node.role) pin.texture:SetTexture(QuestieOcto.Map:GetTextureForNode(node)) + -- Trainer pins crop their icon from a shared atlas; every other role resets + -- to the full 0..1 rectangle so recycled frames never keep a sub-rectangle. + if pin.texture.SetTexCoord then pin.texture:SetTexCoord(QuestieOcto.Map:GetTexCoordForNode(node)) end pin.texture:SetDrawLayer("OVERLAY",QuestieOcto.Map:GetDrawSublevelForRole(node.role)) -- Keep townsfolk/rare markers below quest pins at identical coordinates. if pin.SetFrameLevel and Minimap then diff --git a/Map/MinimapSettings.lua b/Map/MinimapSettings.lua index 01b24f2..37b6e13 100644 --- a/Map/MinimapSettings.lua +++ b/Map/MinimapSettings.lua @@ -17,6 +17,9 @@ S.defaults={ enableObjectives=true, enableTurnins=true, enableAvailable=true, + -- Keep completed quests on the map/minimap even when their Blizzard quest-log + -- zone header is collapsed. Opt-in, so default map behavior is unchanged. + showCompletedQuests=false, globalScale=1, -- Questie 5.2.3/6.0.0 mature old-Questie icon-type defaults. @@ -55,6 +58,9 @@ S.defaults={ showMapSpiritHealer=false, showMapStableMaster=false, showMapVendor=false, + -- Class/profession trainers (map only). Opt-in, using the ringed atlas icons. + showMapClassTrainer=false, + showMapProfessionTrainer=false, showMinimapRareMonsters=true, showMinimapAuctioneer=true, showMinimapBanker=true, @@ -67,6 +73,8 @@ S.defaults={ showMinimapSpiritHealer=false, showMinimapStableMaster=false, showMinimapVendor=false, + showMinimapClassTrainer=false, + showMinimapProfessionTrainer=false, showLowLevelQuests=true, -- Maximum number of displayed quest levels below the player to expose when @@ -223,7 +231,7 @@ function S:Set(key,value) if not self.db or SavedVariableBindingsChanged(self) then self:Initialize() end if key=="enableMapIcons" or key=="showAllQuestsWorldMap" or key=="showSpecialQuestsWorldMap" or key=="enableObjectives" or key=="enableTurnins" or - key=="enableAvailable" or key=="enableMiniMapIcons" or + key=="enableAvailable" or key=="enableMiniMapIcons" or key=="showCompletedQuests" or key=="alwaysGlowMap" or key=="alwaysGlowMinimap" or key=="questObjectiveColors" or key=="questMinimapObjectiveColors" or key=="showLowLevelQuests" or key=="showEventQuests" or key=="showRepeatableQuests" or key=="showPvPRelatedQuests" or @@ -232,10 +240,12 @@ function S:Set(key,value) key=="showMapFlightMaster" or key=="showMapMailbox" or key=="showMapBattlemaster" or key=="showMapInnkeeper" or key=="showMapMeetingStone" or key=="showMapRepair" or key=="showMapSpiritHealer" or key=="showMapStableMaster" or key=="showMapVendor" or + key=="showMapClassTrainer" or key=="showMapProfessionTrainer" or key=="showMinimapRareMonsters" or key=="showMinimapAuctioneer" or key=="showMinimapBanker" or key=="showMinimapFlightMaster" or key=="showMinimapMailbox" or key=="showMinimapBattlemaster" or key=="showMinimapInnkeeper" or key=="showMinimapMeetingStone" or key=="showMinimapRepair" or key=="showMinimapSpiritHealer" or key=="showMinimapStableMaster" or key=="showMinimapVendor" or + key=="showMinimapClassTrainer" or key=="showMinimapProfessionTrainer" or key=="enableTooltips" or key=="enableTooltipsQuestLevel" or key=="enableTooltipsQuestID" or key=="enableTooltipsNPCID" or key=="enableTooltipsItemID" or @@ -320,6 +330,15 @@ function S:Set(key,value) return true end + -- Rescan the quest log so completed quests in collapsed zones are added to + -- (or removed from) the active set, which cascades to the map and minimap. + if key=="showCompletedQuests" then + if QuestieOcto.QuestLog and QuestieOcto.QuestLog.Schedule then + QuestieOcto.QuestLog:Schedule(0.01,true) + end + return true + end + if key=="showLowLevelQuests" or key=="lowLevelQuestRange" or key=="showEventQuests" or key=="showRepeatableQuests" or key=="showPvPRelatedQuests" then if QuestieOcto.AvailableQuests and QuestieOcto.AvailableQuests.FastRefresh then QuestieOcto.AvailableQuests:FastRefresh() @@ -377,13 +396,14 @@ function S:Set(key,value) if key=="showMapRareMonsters" or key=="showMapAuctioneer" or key=="showMapBanker" or key=="showMapFlightMaster" or key=="showMapMailbox" or key=="showMapBattlemaster" or key=="showMapInnkeeper" or key=="showMapMeetingStone" or - key=="showMapRepair" or key=="showMapSpiritHealer" or key=="showMapStableMaster" or key=="showMapVendor" then + key=="showMapRepair" or key=="showMapSpiritHealer" or key=="showMapStableMaster" or key=="showMapVendor" or + key=="showMapClassTrainer" or key=="showMapProfessionTrainer" then -- The additional pfQuest service categories are not materialized while -- disabled on both map surfaces. Rebuild transactionally when one changes -- so opt-in categories have no default startup/node cost. if string.find(key,"Battlemaster") or string.find(key,"Innkeeper") or string.find(key,"MeetingStone") or string.find(key,"Repair") or string.find(key,"SpiritHealer") or string.find(key,"StableMaster") or - string.find(key,"Vendor") then + string.find(key,"Vendor") or string.find(key,"ClassTrainer") or string.find(key,"ProfessionTrainer") then if QuestieOcto.Nodes and QuestieOcto.Nodes.Rebuild then QuestieOcto.Nodes:Rebuild() end end if QuestieOcto.Map and QuestieOcto.Map.OnSettingChanged then @@ -395,10 +415,11 @@ function S:Set(key,value) if key=="showMinimapRareMonsters" or key=="showMinimapAuctioneer" or key=="showMinimapBanker" or key=="showMinimapFlightMaster" or key=="showMinimapMailbox" or key=="showMinimapBattlemaster" or key=="showMinimapInnkeeper" or key=="showMinimapMeetingStone" or - key=="showMinimapRepair" or key=="showMinimapSpiritHealer" or key=="showMinimapStableMaster" or key=="showMinimapVendor" then + key=="showMinimapRepair" or key=="showMinimapSpiritHealer" or key=="showMinimapStableMaster" or key=="showMinimapVendor" or + key=="showMinimapClassTrainer" or key=="showMinimapProfessionTrainer" then if string.find(key,"Battlemaster") or string.find(key,"Innkeeper") or string.find(key,"MeetingStone") or string.find(key,"Repair") or string.find(key,"SpiritHealer") or string.find(key,"StableMaster") or - string.find(key,"Vendor") then + string.find(key,"Vendor") or string.find(key,"ClassTrainer") or string.find(key,"ProfessionTrainer") then if QuestieOcto.Nodes and QuestieOcto.Nodes.Rebuild then QuestieOcto.Nodes:Rebuild() end end if QuestieOcto.Minimap and QuestieOcto.Minimap.OnSettingChanged then @@ -451,4 +472,4 @@ function S:Reset() end end -S:Initialize() +S:Initialize() \ No newline at end of file diff --git a/Map/Nodes.lua b/Map/Nodes.lua index 981e0bf..19d4728 100644 --- a/Map/Nodes.lua +++ b/Map/Nodes.lua @@ -30,6 +30,8 @@ N.stats={ spiritHealer=0, stableMaster=0, vendor=0, + classTrainer=0, + professionTrainer=0, rareMob=0, } @@ -55,6 +57,8 @@ local function NewStats() spiritHealer=0, stableMaster=0, vendor=0, + classTrainer=0, + professionTrainer=0, rareMob=0, } end @@ -298,6 +302,8 @@ local optionalServiceSettings={ spiritHealer={"showMapSpiritHealer","showMinimapSpiritHealer"}, stableMaster={"showMapStableMaster","showMinimapStableMaster"}, vendor={"showMapVendor","showMinimapVendor"}, + classTrainer={"showMapClassTrainer","showMinimapClassTrainer"}, + professionTrainer={"showMapProfessionTrainer","showMinimapProfessionTrainer"}, } local function OptionalServiceEnabled(role) @@ -380,6 +386,66 @@ local function ProcessServiceObjectSlice(metaKey,role,statKey,cursor,limit) return cursor,false end +-- Trainers are stored two levels deep: meta["trainers"][class] and +-- meta["professions"][profession] each hold a flat {[creatureID]=faction} table. +-- We flatten that lazily so the incremental builder can pause between frames: +-- the cursor is {groupKey=, innerCursor=}. Each +-- emitted node is tagged with trainerKey= so the renderer can pick the +-- right icon out of the ringed class/profession atlas. +local function ProcessTrainerSlice(metaKey,role,statKey,cursor,limit) + local root=TrackingMeta(metaKey) + if type(root)~="table" then return nil,true end + local factionCode=PlayerFactionCode() + if not factionCode then return nil,true end + + cursor=cursor or {} + local groupKey=cursor.groupKey + local innerCursor=cursor.innerCursor + + local count=0 + while count<(limit or 128) do + if groupKey==nil then + groupKey=next(root,nil) + innerCursor=nil + if groupKey==nil then return nil,true end + end + + local group=root[groupKey] + local rawID,allowed + if type(group)=="table" then rawID,allowed=next(group,innerCursor) end + + if rawID==nil then + -- Group exhausted (or not a table): advance to the next group. Empty + -- profession tables fall straight through here without costing a slot. + groupKey=next(root,groupKey) + innerCursor=nil + if groupKey==nil then return nil,true end + else + innerCursor=rawID + local creatureID=tonumber(rawID) + if creatureID and creatureID>0 and FactionAllows(allowed,factionCode) then + local coords=QuestieOcto.DatabaseAPI:GetCreatureCoords(creatureID) + if coords and next(coords) then + AddNode({ + questID=0, + role=role, + sourceKind="creature", + sourceID=creatureID, + sourceName=QuestieOcto.DatabaseAPI:GetCreatureName(creatureID), + coords=coords, + serviceFaction=allowed, + trainerKey=tostring(groupKey) + }) + CurrentStats()[statKey]=(CurrentStats()[statKey] or 0)+1 + end + end + count=count+1 + end + end + + return {groupKey=groupKey,innerCursor=innerCursor},false +end + local function ProcessRareMobSlice(cursor,limit) local list=TrackingMeta("rares") if not list then return nil,true end @@ -537,6 +603,8 @@ local function StatKeyForNode(node) if node.role=="spiritHealer" then return "spiritHealer" end if node.role=="stableMaster" then return "stableMaster" end if node.role=="vendor" then return "vendor" end + if node.role=="classTrainer" then return "classTrainer" end + if node.role=="professionTrainer" then return "professionTrainer" end if node.role=="rareMob" then return "rareMob" end return nil end @@ -756,6 +824,8 @@ function N:Rebuild() {kind="creature",metaKey="spirithealer",role="spiritHealer",statKey="spiritHealer",optional=true}, {kind="creature",metaKey="stablemaster",role="stableMaster",statKey="stableMaster",optional=true}, {kind="creature",metaKey="vendor",role="vendor",statKey="vendor",optional=true}, + {kind="trainer",metaKey="trainers",role="classTrainer",statKey="classTrainer",optional=true}, + {kind="trainer",metaKey="professions",role="professionTrainer",statKey="professionTrainer",optional=true}, {kind="rare"}, } @@ -775,6 +845,8 @@ function N:Rebuild() nextCursor,done=ProcessServiceCreatureSlice(job.metaKey,job.role,job.statKey,cursor,128) elseif job.kind=="object" then nextCursor,done=ProcessServiceObjectSlice(job.metaKey,job.role,job.statKey,cursor,128) + elseif job.kind=="trainer" then + nextCursor,done=ProcessTrainerSlice(job.metaKey,job.role,job.statKey,cursor,128) elseif job.kind=="rare" then nextCursor,done=ProcessRareMobSlice(cursor,128) end diff --git a/Map/Prepared.lua b/Map/Prepared.lua index df26240..c01f22a 100644 --- a/Map/Prepared.lua +++ b/Map/Prepared.lua @@ -35,6 +35,7 @@ local function ExactRole(role) or role=="auctioneer" or role=="banker" or role=="mailbox" or role=="battlemaster" or role=="innkeeper" or role=="meetingStone" or role=="repair" or role=="spiritHealer" or role=="stableMaster" or role=="vendor" + or role=="classTrainer" or role=="professionTrainer" or role=="rareMob" end diff --git a/Map/Tooltips.lua b/Map/Tooltips.lua index 1791f0d..5b1fb04 100644 --- a/Map/Tooltips.lua +++ b/Map/Tooltips.lua @@ -1088,9 +1088,17 @@ function T:Show(pin) spiritHealer="Spirit Healer", stableMaster="Stable Master", vendor="Vendor", + classTrainer="Class Trainer", + professionTrainer="Profession Trainer", rareMob="[Rare]" } local permanentLabel=permanentLabels[pin.role] + -- Trainers refine the generic label with the specific class/profession, e.g. + -- "Warrior Trainer" / "Cooking Trainer". + if permanentLabel and (pin.role=="classTrainer" or pin.role=="professionTrainer") and type(pin.trainerKey)=="string" and pin.trainerKey~="" then + local key=pin.trainerKey + permanentLabel=string.upper(string.sub(key,1,1))..string.sub(key,2).." Trainer" + end if permanentLabel then tooltip:SetOwner(pin,"ANCHOR_CURSOR") tooltip:ClearLines() diff --git a/Map/Visuals.lua b/Map/Visuals.lua index 460c28d..8aab482 100644 --- a/Map/Visuals.lua +++ b/Map/Visuals.lua @@ -14,13 +14,39 @@ local function NextRandom(seed) return seed,value end +-- HSV->RGB (h in [0,360), s/v in [0,1]). Lua 5.0: math.mod is fmod and works on +-- floats, math.abs/math.floor are available. +local function HSVToRGB(h,s,v) + local c=v*s + local hp=h/60 + local x=c*(1-math.abs(math.mod(hp,2)-1)) + local r,g,b=0,0,0 + if hp<1 then r,g,b=c,x,0 + elseif hp<2 then r,g,b=x,c,0 + elseif hp<3 then r,g,b=0,c,x + elseif hp<4 then r,g,b=0,x,c + elseif hp<5 then r,g,b=x,0,c + else r,g,b=c,0,x end + local m=v-c + return r+m,g+m,b+m +end + +-- Full-wheel vivid colors. The previous scheme mapped each RGB channel into +-- [0.45,0.95], which clustered every roll near a light desaturated gray: little +-- variety and near-identical neighbours. Drawing a hue across the entire color +-- wheel with high saturation and brightness gives a far larger, more separable +-- gamut so overlapping quests/objectives are easy to tell apart, and re-rolling +-- (Full Node click) jumps to a clearly different color. local function SeedColor(seed) seed=tonumber(seed) or 0 - local r,g,b - seed,r=NextRandom(seed) - seed,g=NextRandom(seed) - seed,b=NextRandom(seed) - return 0.45+r/2,0.45+g/2,0.45+b/2 + local h,s,v + seed,h=NextRandom(seed) + seed,s=NextRandom(seed) + seed,v=NextRandom(seed) + local hue=h*360 + local sat=0.82+s*0.18 -- 0.82 .. 1.00: strongly saturated + local val=0.85+v*0.15 -- 0.85 .. 1.00: bright/readable + return HSVToRGB(hue,sat,val) end V.colorRolls=V.colorRolls or {} @@ -133,6 +159,12 @@ function V:ApplyPin(pin,node,isMinimap,alpha) end end +-- Fixed light blue-white used for the hover-highlight glow. The highlight only +-- appears while every other objective is faded, so it never needs to be color +-- coded per quest; a neutral tint reads clearly against the vivid node colors +-- rather than blending into them. +local HIGHLIGHT_GLOW_R,HIGHLIGHT_GLOW_G,HIGHLIGHT_GLOW_B=0.50,0.70,1.0 + -- Tracker-hover highlight: brighten a pin and force its glow on so the hovered -- quest's objectives stand out, then restore the normal glow state on release. function V:SetHighlight(pin,on) @@ -140,8 +172,7 @@ function V:SetHighlight(pin,on) if on then pin.texture:SetVertexColor(pin.iconR or 1,pin.iconG or 1,pin.iconB or 1,1) if pin.glowTexture then - local gr,gg,gb=self:GetQuestColor(pin.questID) - pin.glowTexture:SetVertexColor(gr,gg,gb,1) + pin.glowTexture:SetVertexColor(HIGHLIGHT_GLOW_R,HIGHLIGHT_GLOW_G,HIGHLIGHT_GLOW_B,1) self:ResizeGlow(pin) pin.glowTexture:Show() pin.glowForced=true diff --git a/Quest/QuestLog.lua b/Quest/QuestLog.lua index 80a7988..ac80201 100644 --- a/Quest/QuestLog.lua +++ b/Quest/QuestLog.lua @@ -10,6 +10,10 @@ QL.acceptedHints={} QL.acceptPollGeneration=0 QL.acceptPollUntil=0 QL.active={} +-- Completed quests remembered while their zone header was expanded, so they can +-- be kept on the map/minimap after the zone is collapsed (option-gated). Small: +-- one entry per currently-complete quest, purged once the quest leaves the log. +QL.completedZoneQuests={} QL.snapshot=nil QL.mapSnapshot=nil QL.mapState=nil @@ -227,6 +231,25 @@ local function LiveObjectiveKind(q,row) return nil end +-- Map a native objective type ("monster"/"object"/"item") to the QuestModel +-- objectiveData kind ("creature"/"gameObject"/"item"). Kept local to QuestLog +-- so the leaderboard-name reconstruction below does not depend on Objectives.lua. +local function ObjectiveTypeMatchesKind(logType,dbKind) + local typ=string.lower(tostring(logType or "")) + if dbKind=="creature" then return typ=="monster" or typ=="creature" or typ=="kill" end + if dbKind=="gameObject" then return typ=="object" or typ=="gameobject" end + if dbKind=="item" then return typ=="item" end + return false +end + +local function NameForObjectiveDataEntry(entry) + if not entry then return nil end + if entry.kind=="creature" then return QuestieOcto.DatabaseAPI:GetCreatureName(entry.id) end + if entry.kind=="gameObject" then return QuestieOcto.DatabaseAPI:GetObjectName(entry.id) end + if entry.kind=="item" then return QuestieOcto.DatabaseAPI:GetItemName(entry.id) end + return nil +end + local function LocalizeObjectiveRows(questID,objectives) if not questID or type(objectives)~="table" then return objectives end if not QuestieOcto.DatabaseAPI or not QuestieOcto.DatabaseAPI:IsReady() then return objectives end @@ -234,6 +257,8 @@ local function LocalizeObjectiveRows(questID,objectives) local q=QuestieOcto.QuestModel and QuestieOcto.QuestModel:Get(questID) or nil if not q then return objectives end + local objectiveData=q.objectiveData or {} + for i=1,table.getn(objectives) do local row=objectives[i] local id=tonumber(row and row.objectiveID) @@ -244,9 +269,18 @@ local function LocalizeObjectiveRows(questID,objectives) elseif id and kind=="gameObject" then name=QuestieOcto.DatabaseAPI:GetObjectName(id) elseif id and kind=="item" then name=QuestieOcto.DatabaseAPI:GetItemName(id) end - -- Never localize by objective array position. Questie 5/6 only assumes - -- positional identity when both sides contain one objective; pfQuest uses - -- ClassicAPI's live leaderboard ID. If no trustworthy ID is available, + -- Turtle/ClassicAPI publishes no live leaderboard entity ID so fix this + if (not name or name=="") then + local entry=objectiveData[i] + if entry and row and ObjectiveTypeMatchesKind(row.type,entry.kind) then + name=NameForObjectiveDataEntry(entry) + end + end + + -- Never localize by objective array position beyond the type-matched engine + -- ordering above. Questie 5/6 only assume positional identity when both + -- sides contain one objective; pfQuest uses ClassicAPI's live leaderboard + -- ID. When neither a trustworthy ID nor a type-matched slot is available, -- keep Turtle's native objective text intact for the fallback matcher. if row and name and name~="" then if row.current~=nil and row.required~=nil then @@ -383,6 +417,51 @@ function QL:Schedule(delay,fastRefresh) end,"questlog-refresh") end +-- Collapsing a Blizzard quest-log zone hides its quests from enumeration, so +-- they drop out of the active set and off the map. Rather than toggling headers +-- (which flickers the log), the main scan remembers completed quests in +-- QL.completedZoneQuests while their zone is visible; here we re-add any that +-- have since been collapsed away but are still on the player, as map-only active +-- entries. Also purges quests that have left the log to keep the cache bounded. +local function SyncCompletedZoneCache(nextActive,nextMapState,snapshotParts) + local cache=QL.completedZoneQuests + local optionOn=QuestieOcto.MinimapSettings and QuestieOcto.MinimapSettings:Get("showCompletedQuests") and true or false + + local injected + for questID,meta in pairs(cache) do + if nextActive[questID] then + -- Still enumerated (zone expanded); the scan keeps it fresh, no re-add. + elseif QuestieOcto.API and QuestieOcto.API:IsOnQuest(questID) then + if optionOn then + -- mapOnly keeps these out of the tracker: the zone was collapsed there + -- on purpose, so only the map/minimap turn-in should reappear. + nextActive[questID]={ + id=questID,logIndex=meta.logIndex,title=meta.title,level=meta.level,tag=meta.tag, + zoneGroup=meta.zoneGroup,status=1,complete=true,failed=false, + objectives={},objectiveSource=nil,mapOnly=true + } + nextMapState[questID]="1\031" + injected=injected or {} + table.insert(injected,questID) + end + else + -- Turned in or abandoned: release the cache entry. + cache[questID]=nil + end + end + + -- Append map-only quests to the change-detection snapshot in a stable (sorted) + -- order so their presence flips "changed" only when the set actually changes, + -- not on every refresh from pairs() iteration order. + if injected then + table.sort(injected) + for i=1,table.getn(injected) do + table.insert(snapshotParts,"mapOnly") + table.insert(snapshotParts,tostring(injected[i])) + end + end +end + function QL:Refresh(fastRefresh) if self.running then self.pending=true @@ -533,6 +612,15 @@ function QL:Refresh(fastRefresh) -- thousands of Full Nodes whose visibility did not change. nextMapState[questID]=tostring(status).."\031"..tostring(objectiveMapSnapshot or "") QL.stats.resolved=QL.stats.resolved+1 + + -- Remember completed quests (with the metadata needed to redraw their + -- turn-in) while their zone is visible, so SyncCompletedZoneCache can + -- keep them mapped once the zone is collapsed. Clear it otherwise. + if complete then + QL.completedZoneQuests[questID]={logIndex=index,title=title,level=level,tag=tag,zoneGroup=currentHeader} + else + QL.completedZoneQuests[questID]=nil + end end count=count+1 @@ -544,6 +632,10 @@ function QL:Refresh(fastRefresh) return end + -- Re-add completed quests from collapsed zones before any diffs are taken, + -- so they participate in active-set, map-state, and change detection. + SyncCompletedZoneCache(nextActive,nextMapState,snapshotParts) + local nextSnapshot=table.concat(snapshotParts,"\031") local changed=(nextSnapshot~=QL.snapshot) @@ -797,4 +889,4 @@ function QL:Start() end) self:Schedule(0.01,true) -end +end \ No newline at end of file diff --git a/Questie-Octo.toc b/Questie-Octo.toc index 32eaa31..b83108a 100644 --- a/Questie-Octo.toc +++ b/Questie-Octo.toc @@ -2,7 +2,7 @@ ## Title: Questie-Octo ## Notes: Quest helper. ## Author: Questie-Octo -## Version: 1.0.81 +## Version: 1.0.85 ## SavedVariables: QuestieOctoGlobalDB ## SavedVariablesPerCharacter: QuestieOctoDB diff --git a/QuestieOcto.lua b/QuestieOcto.lua index 9d9c4e1..0cb11eb 100644 --- a/QuestieOcto.lua +++ b/QuestieOcto.lua @@ -2,7 +2,7 @@ QuestieOcto = QuestieOcto or {} local QO = QuestieOcto -QO.version = "1.0.81" +QO.version = "1.0.85" QO.enabled = false QO.ready = false QO.messages = {} @@ -67,4 +67,4 @@ function QO:SendMessage(name, ...) fn(entry.owner, unpack(arg)) end end -end +end \ No newline at end of file diff --git a/README.md b/README.md index 3f82801..e1ecb4d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ -ClassicAPI.dll needed. +Simple lightweight featureful quest tracker for OctoWoW +Make sure you rename folder to **Questie-Octo** after extraction -[Latest release here.](https://github.com/brues-code/ClassicAPI/releases/latest) +If you notice any missing quests, objective locations, or notice wrong map icon locations feel free to use [UnitLogger](https://github.com/Blaststar/UnitLogger) addon to help speed up fixes/development if said item/npc doesnt exist in octowowdb + +**ClassicAPI.dll** needed. + +[Latest release here.](https://github.com/brues-code/ClassicAPI/releases/latest) \ No newline at end of file diff --git a/Tracker/TrackerDriver.lua b/Tracker/TrackerDriver.lua index ef23ccd..108320c 100644 --- a/Tracker/TrackerDriver.lua +++ b/Tracker/TrackerDriver.lua @@ -123,7 +123,9 @@ function D:Rebuild() if auto then tracked=not db.AutoUntrackedQuests[questID] else tracked=db.TrackedQuests[questID] and true or false end - if tracked and (showCompleted or not state.complete) then + -- mapOnly quests come from collapsed quest-log zones and belong only on the + -- map/minimap; never surface them in the tracker. + if tracked and not state.mapOnly and (showCompleted or not state.complete) then local objectives={} for i=1,table.getn(state.objectives or {}) do local objective=state.objectives[i] @@ -266,4 +268,4 @@ function D:Start() self:Rebuild() end -QuestieOcto:RegisterMessage("FOUNDATION_READY",D,"Start") +QuestieOcto:RegisterMessage("FOUNDATION_READY",D,"Start") \ No newline at end of file diff --git a/UI/Icons/Ringed-Classes.tga b/UI/Icons/Ringed-Classes.tga new file mode 100644 index 0000000..e263d62 Binary files /dev/null and b/UI/Icons/Ringed-Classes.tga differ diff --git a/UI/Icons/Ringed-Professions.tga b/UI/Icons/Ringed-Professions.tga new file mode 100644 index 0000000..0219eb4 Binary files /dev/null and b/UI/Icons/Ringed-Professions.tga differ diff --git a/UI/Options.lua b/UI/Options.lua index 667b66e..01970bd 100644 --- a/UI/Options.lua +++ b/UI/Options.lua @@ -332,6 +332,7 @@ local function CreateGeneralTab() args={ icon_header={type="header",order=1,name="Icon Settings"}, enableMapIcons={type="toggle",order=2,name="Show Quests",desc="Show quest icons on the main map.",width="full",get=GetValue,set=SetValue}, + showCompletedQuests={type="toggle",order=2.1,name="Always Show Completed Quests",desc="Always show completed quests on minimap and map regardless if zone is collapsed.",width="full",get=GetValue,set=SetValue}, world_map_visibility_header={type="header",order=3,name="World Map Visibility"}, showAllQuestsWorldMap={type="toggle",order=3.1,name="Show Quests on the World Map",desc="Show normal quest pickup and turn-in icons on continent maps.",width="full",get=GetValue,set=SetValue}, showSpecialQuestsWorldMap={type="toggle",order=3.2,name="Show Special Quests on the World Map",desc="Show repeatable, PvP, and active event quest icons on continent maps.",width="full",get=GetValue,set=SetValue}, @@ -399,18 +400,20 @@ local function CreateMapTab() globalScale={type="range",order=2.2,name="Global Scale for Map Icons",desc="Adjust map icon size.",width="double",min=0.01,max=4,step=0.01,disabled=function() return not Settings():Get("enableMapIcons") end,get=GetValue,set=SetValue}, miscellaneous_icons={type="header",order=20,name="Miscellaneous icons"}, - showMapRareMonsters={type="toggle",order=20.1,name="Rare Monsters",desc="Show Rare Monster icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapAuctioneer={type="toggle",order=20.2,name="Auctioneer",desc="Show Auctioneer icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapBanker={type="toggle",order=20.3,name="Banker",desc="Show Banker icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapFlightMaster={type="toggle",order=20.4,name="Flight Master",desc="Show Flight Master icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapMailbox={type="toggle",order=20.5,name="Mailbox",desc="Show Mailbox icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapBattlemaster={type="toggle",order=20.6,name="Battlemaster",desc="Show Battlemaster icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapInnkeeper={type="toggle",order=20.7,name="Innkeeper",desc="Show Innkeeper icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapMeetingStone={type="toggle",order=20.8,name="Meeting Stones",desc="Show Meeting Stone icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapRepair={type="toggle",order=20.9,name="Repair",desc="Show Repair icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapSpiritHealer={type="toggle",order=21.0,name="Spirit Healer",desc="Show Spirit Healer icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapStableMaster={type="toggle",order=21.1,name="Stable Master",desc="Show Stable Master icons on the map.",width="full",get=GetValue,set=SetValue}, - showMapVendor={type="toggle",order=21.2,name="Vendor",desc="Show Vendor icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapClassTrainer={type="toggle",order=20.2,name="Class Trainers",desc="Show Class Trainers on the map.",width="full",get=GetValue,set=SetValue}, + showMapProfessionTrainer={type="toggle",order=20.3,name="Profession Trainers",desc="Show Profession Trainers on the map.",width="full",get=GetValue,set=SetValue}, + showMapRareMonsters={type="toggle",order=20.4,name="Rare Monsters",desc="Show Rare Monster icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapAuctioneer={type="toggle",order=20.5,name="Auctioneer",desc="Show Auctioneer icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapBanker={type="toggle",order=20.6,name="Banker",desc="Show Banker icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapFlightMaster={type="toggle",order=20.7,name="Flight Master",desc="Show Flight Master icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapMailbox={type="toggle",order=20.8,name="Mailbox",desc="Show Mailbox icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapBattlemaster={type="toggle",order=20.9,name="Battlemaster",desc="Show Battlemaster icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapInnkeeper={type="toggle",order=21,name="Innkeeper",desc="Show Innkeeper icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapMeetingStone={type="toggle",order=21.1,name="Meeting Stones",desc="Show Meeting Stone icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapRepair={type="toggle",order=21.2,name="Repair",desc="Show Repair icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapSpiritHealer={type="toggle",order=21.3,name="Spirit Healer",desc="Show Spirit Healer icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapStableMaster={type="toggle",order=21.4,name="Stable Master",desc="Show Stable Master icons on the map.",width="full",get=GetValue,set=SetValue}, + showMapVendor={type="toggle",order=21.5,name="Vendor",desc="Show Vendor icons on the map.",width="full",get=GetValue,set=SetValue}, }, } end @@ -426,18 +429,20 @@ local function CreateMinimapTab() globalMiniMapScale={type="range",order=2.2,name="Global Scale for Minimap Icons",desc="Adjust minimap icon size.",width="double",min=0.01,max=4,step=0.01,disabled=function() return not EnabledMinimap() end,get=GetValue,set=SetValue}, miscellaneous_icons={type="header",order=20,name="Miscellaneous icons"}, - showMinimapRareMonsters={type="toggle",order=20.1,name="Rare Monsters",desc="Show Rare Monster icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapAuctioneer={type="toggle",order=20.2,name="Auctioneer",desc="Show Auctioneer icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapBanker={type="toggle",order=20.3,name="Banker",desc="Show Banker icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapFlightMaster={type="toggle",order=20.4,name="Flight Master",desc="Show Flight Master icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapMailbox={type="toggle",order=20.5,name="Mailbox",desc="Show Mailbox icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapBattlemaster={type="toggle",order=20.6,name="Battlemaster",desc="Show Battlemaster icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapInnkeeper={type="toggle",order=20.7,name="Innkeeper",desc="Show Innkeeper icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapMeetingStone={type="toggle",order=20.8,name="Meeting Stones",desc="Show Meeting Stone icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapRepair={type="toggle",order=20.9,name="Repair",desc="Show Repair icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapSpiritHealer={type="toggle",order=21.0,name="Spirit Healer",desc="Show Spirit Healer icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapStableMaster={type="toggle",order=21.1,name="Stable Master",desc="Show Stable Master icons on the minimap.",width="full",get=GetValue,set=SetValue}, - showMinimapVendor={type="toggle",order=21.2,name="Vendor",desc="Show Vendor icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapClassTrainer={type="toggle",order=20.1,name="Class Trainers",desc="Show Class Trainers on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapProfessionTrainer={type="toggle",order=20.2,name="Profession Trainers",desc="Show Profession Trainers on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapRareMonsters={type="toggle",order=20.3,name="Rare Monsters",desc="Show Rare Monster icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapAuctioneer={type="toggle",order=20.4,name="Auctioneer",desc="Show Auctioneer icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapBanker={type="toggle",order=20.5,name="Banker",desc="Show Banker icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapFlightMaster={type="toggle",order=20.6,name="Flight Master",desc="Show Flight Master icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapMailbox={type="toggle",order=20.7,name="Mailbox",desc="Show Mailbox icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapBattlemaster={type="toggle",order=20.8,name="Battlemaster",desc="Show Battlemaster icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapInnkeeper={type="toggle",order=20.9,name="Innkeeper",desc="Show Innkeeper icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapMeetingStone={type="toggle",order=21,name="Meeting Stones",desc="Show Meeting Stone icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapRepair={type="toggle",order=21.1,name="Repair",desc="Show Repair icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapSpiritHealer={type="toggle",order=21.2,name="Spirit Healer",desc="Show Spirit Healer icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapStableMaster={type="toggle",order=21.3,name="Stable Master",desc="Show Stable Master icons on the minimap.",width="full",get=GetValue,set=SetValue}, + showMinimapVendor={type="toggle",order=21.4,name="Vendor",desc="Show Vendor icons on the minimap.",width="full",get=GetValue,set=SetValue}, }, } end @@ -646,4 +651,4 @@ end -- Build the hidden frame after login rather than during file load. QuestieOcto.Scheduler:After(0.10,function() O:Initialize() -end,"questie-options-init") +end,"questie-options-init") \ No newline at end of file diff --git a/UI/QuestResearch.lua b/UI/QuestResearch.lua index b628f12..1264f9d 100644 --- a/UI/QuestResearch.lua +++ b/UI/QuestResearch.lua @@ -291,7 +291,7 @@ function R:GetQuestDetails() local zones=QuestZoneNames(q,id) if table.getn(zones)>0 then local zoneText={} - for i=1,table.getn(zones) do table.insert(zoneText,"|cff40a0ff["..zones[i].."]|r") end + for i=1,table.getn(zones) do table.insert(zoneText,"|cffd7bea5["..zones[i].."]|r") end table.insert(lines,"\n|cffffd100Zone|r\n"..table.concat(zoneText," ")) end @@ -557,7 +557,7 @@ function R:OpenWindowNow() end local title=f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - title:SetPoint("TOP",f,"TOP",0,-18); title:SetText("Quests") + title:SetPoint("TOP",f,"TOP",0,-18); title:SetText("Quest Database") local close=CreateFrame("Button",nil,f,"UIPanelCloseButton"); close:SetPoint("TOPRIGHT",f,"TOPRIGHT",-5,-5); close:SetScript("OnClick",function() R:CloseWindow() end) local search=CreateFrame("EditBox",nil,f,"InputBoxTemplate") @@ -704,4 +704,4 @@ end QuestieOcto:RegisterMessage("COMPLETION_READY",R,"OnStateChanged") QuestieOcto:RegisterMessage("DATABASE_API_READY",R,"OnStateChanged") QuestieOcto:RegisterMessage("AVAILABLE_QUESTS_READY",R,"OnStateChanged") -QuestieOcto:RegisterMessage("QUEST_LOG_CHANGED",R,"OnStateChanged") +QuestieOcto:RegisterMessage("QUEST_LOG_CHANGED",R,"OnStateChanged") \ No newline at end of file