@@ -14,6 +14,10 @@ local m_floor = math.floor
1414local band = bit .band
1515local b_rshift = bit .rshift
1616
17+ local JEWEL_RADIUS_TINT_NEUTRAL = { 1 , 1 , 1 , 0.7 }
18+ local JEWEL_RADIUS_TINT_PRIMARY_ONLY = { 1 , 0 , 0 , 0.7 }
19+ local JEWEL_RADIUS_TINT_COMPARE_ONLY = { 0 , 1 , 0 , 0.7 }
20+
1721local gemTooltip = LoadModule (" Classes/GemTooltip" )
1822local PassiveTreeViewClass = newClass (" PassiveTreeView" , function (self )
1923 self .ring = NewImageHandle ()
@@ -144,6 +148,13 @@ function PassiveTreeViewClass:GetJewelSocketOverlay(jewel, isExpansion)
144148 end
145149end
146150
151+ local function compareJewelsEqual (a , b )
152+ if not a or not b then
153+ return a == b
154+ end
155+ return a :BuildRaw () == b :BuildRaw ()
156+ end
157+
147158-- Returns the draw color for a node when compare overlay is active.
148159-- Handles diff coloring for allocated/unallocated, mastery changes, and jewel socket differences.
149160function PassiveTreeViewClass :GetCompareNodeColor (node , compareNode , spec , build , nodeDefaultColor )
@@ -160,9 +171,7 @@ function PassiveTreeViewClass:GetCompareNodeColor(node, compareNode, spec, build
160171 local pJewelId = spec .jewels [node .id ]
161172 local pJewel = pJewelId and build .itemsTab .items [pJewelId ]
162173 local cJewel = self :GetCompareJewel (node .id )
163- local pName = pJewel and pJewel .name or " "
164- local cName = cJewel and cJewel .name or " "
165- if pName ~= cName then
174+ if not compareJewelsEqual (pJewel , cJewel ) then
166175 return 0 , 0 , 1
167176 end
168177 end
@@ -1115,80 +1124,89 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
11151124 end
11161125
11171126 -- Draw ring overlays for jewel sockets
1127+ local function drawJewelRadius (jewel , scrX , scrY , tint )
1128+ local radData = build .data .jewelRadius [jewel .jewelRadiusIndex ]
1129+ local outerSize = radData .outer * scale
1130+ local innerSize = radData .inner * scale * 1.06
1131+ SetDrawColor (tint [1 ], tint [2 ], tint [3 ], tint [4 ])
1132+ if jewel .title :match (" Impossible Escape" ) then
1133+ -- Impossible Escape ring shows on the allocated Keystone
1134+ for keystoneName , _ in pairs (jewel .jewelData .impossibleEscapeKeystones ) do
1135+ local keystone = spec .tree .keystoneMap [keystoneName ]
1136+ if keystone and keystone .x and keystone .y then
1137+ innerSize = 150 * scale
1138+ local keyX , keyY = treeToScreen (keystone .x , keystone .y )
1139+ self :DrawImageRotated (self .jewelShadedOuterRing , keyX , keyY , outerSize * 2 , outerSize * 2 , - 0.8 )
1140+ self :DrawImageRotated (self .jewelShadedOuterRingFlipped , keyX , keyY , outerSize * 2 , outerSize * 2 , 1 )
1141+ self :DrawImageRotated (self .jewelShadedInnerRing , keyX , keyY , innerSize * 2 , innerSize * 2 , - 1.2 )
1142+ self :DrawImageRotated (self .jewelShadedInnerRingFlipped , keyX , keyY , innerSize * 2 , innerSize * 2 , 1.0 )
1143+ end
1144+ end
1145+ elseif jewel .title :match (" ^Brutal Restraint" ) then
1146+ self :DrawImageRotated (self .maraketh1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1147+ self :DrawImageRotated (self .maraketh2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1148+ elseif jewel .title :match (" ^Elegant Hubris" ) then
1149+ self :DrawImageRotated (self .eternal1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1150+ self :DrawImageRotated (self .eternal2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1151+ elseif jewel .title :match (" ^Glorious Vanity" ) then
1152+ self :DrawImageRotated (self .vaal1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1153+ self :DrawImageRotated (self .vaal2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1154+ elseif jewel .title :match (" ^Lethal Pride" ) then
1155+ self :DrawImageRotated (self .karui1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1156+ self :DrawImageRotated (self .karui2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1157+ elseif jewel .title :match (" ^Militant Faith" ) then
1158+ self :DrawImageRotated (self .templar1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1159+ self :DrawImageRotated (self .templar2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1160+ elseif jewel .title :match (" ^Heroic Tragedy" ) then
1161+ self :DrawImageRotated (self .kalguur1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1162+ self :DrawImageRotated (self .kalguur2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1163+ else
1164+ self :DrawImageRotated (self .jewelShadedOuterRing , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1165+ self :DrawImageRotated (self .jewelShadedOuterRingFlipped , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1166+ self :DrawImageRotated (self .jewelShadedInnerRing , scrX , scrY , innerSize * 2 , innerSize * 2 , - 0.7 )
1167+ self :DrawImageRotated (self .jewelShadedInnerRingFlipped , scrX , scrY , innerSize * 2 , innerSize * 2 , 0.7 )
1168+ end
1169+ end
11181170 SetDrawLayer (nil , 25 )
11191171 for nodeId in pairs (tree .sockets ) do
11201172 local node = spec .nodes [nodeId ]
11211173 if node and node .name ~= " Charm Socket" and (not node .expansionJewel or node .expansionJewel .size == 2 ) then
11221174 local scrX , scrY = treeToScreen (node .x , node .y )
11231175 local socket , jewel = build .itemsTab :GetSocketAndJewelForNodeID (nodeId )
1176+ local compareNode = self .compareSpec and self .compareSpec .nodes [nodeId ] or nil
1177+ local cJewel = self .compareSpec and self :GetCompareJewel (nodeId ) or nil
11241178 if node == hoverNode then
1125- local isThreadOfHope = jewel and jewel .jewelRadiusLabel == " Variable"
1126- if isThreadOfHope then
1127- for _ , radData in ipairs (build .data .jewelRadius ) do
1128- local outerSize = radData .outer * scale
1129- local innerSize = radData .inner * scale
1130- -- Jewel in socket is Thread of Hope or similar, draw it's annulus
1179+ local effectiveJewel = jewel or cJewel
1180+ local isThreadOfHope = effectiveJewel and effectiveJewel .jewelRadiusLabel == " Variable"
1181+ for _ , radData in ipairs (build .data .jewelRadius ) do
1182+ local outerSize = radData .outer * scale
1183+ local innerSize = radData .inner * scale
1184+ if isThreadOfHope then
1185+ -- Thread of Hope-like: draw the annulus (only radii with a non-zero inner)
11311186 if innerSize ~= 0 then
11321187 SetDrawColor (radData .col )
11331188 DrawImage (self .ring , scrX - outerSize , scrY - outerSize , outerSize * 2 , outerSize * 2 )
11341189 DrawImage (self .ring , scrX - innerSize , scrY - innerSize , innerSize * 2 , innerSize * 2 )
11351190 end
1136- end
1137- else
1138- for _ , radData in ipairs (build .data .jewelRadius ) do
1139- local outerSize = radData .outer * scale
1140- local innerSize = radData .inner * scale
1141- -- Jewel in socket is not Thread of Hope or similar, draw normal jewel radius
1191+ else
1192+ -- Standard jewel: draw the full-disc radii (inner == 0)
11421193 if innerSize == 0 then
11431194 SetDrawColor (radData .col )
11441195 DrawImage (self .ring , scrX - outerSize , scrY - outerSize , outerSize * 2 , outerSize * 2 )
11451196 end
11461197 end
11471198 end
1148- elseif node .alloc then
1149- if jewel and jewel .jewelRadiusIndex then
1150- -- Draw only the selected jewel radius
1151- local radData = build .data .jewelRadius [jewel .jewelRadiusIndex ]
1152- local outerSize = radData .outer * scale
1153- local innerSize = radData .inner * scale * 1.06
1154- SetDrawColor (1 ,1 ,1 ,0.7 )
1155- if jewel .title :match (" Impossible Escape" ) then
1156- -- Impossible Escape ring shows on the allocated Keystone
1157- for keystoneName , _ in pairs (jewel .jewelData .impossibleEscapeKeystones ) do
1158- local keystone = spec .tree .keystoneMap [keystoneName ]
1159- if keystone and keystone .x and keystone .y then
1160- innerSize = 150 * scale
1161- local keyX , keyY = treeToScreen (keystone .x , keystone .y )
1162- self :DrawImageRotated (self .jewelShadedOuterRing , keyX , keyY , outerSize * 2 , outerSize * 2 , - 0.8 )
1163- self :DrawImageRotated (self .jewelShadedOuterRingFlipped , keyX , keyY , outerSize * 2 , outerSize * 2 , 1 )
1164- self :DrawImageRotated (self .jewelShadedInnerRing , keyX , keyY , innerSize * 2 , innerSize * 2 , - 1.2 )
1165- self :DrawImageRotated (self .jewelShadedInnerRingFlipped , keyX , keyY , innerSize * 2 , innerSize * 2 , 1.0 )
1166- end
1167- end
1168- elseif jewel .title :match (" ^Brutal Restraint" ) then
1169- self :DrawImageRotated (self .maraketh1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1170- self :DrawImageRotated (self .maraketh2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1171- elseif jewel .title :match (" ^Elegant Hubris" ) then
1172- self :DrawImageRotated (self .eternal1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1173- self :DrawImageRotated (self .eternal2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1174- elseif jewel .title :match (" ^Glorious Vanity" ) then
1175- self :DrawImageRotated (self .vaal1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1176- self :DrawImageRotated (self .vaal2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1177- elseif jewel .title :match (" ^Lethal Pride" ) then
1178- self :DrawImageRotated (self .karui1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1179- self :DrawImageRotated (self .karui2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1180- elseif jewel .title :match (" ^Militant Faith" ) then
1181- self :DrawImageRotated (self .templar1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1182- self :DrawImageRotated (self .templar2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1183- elseif jewel .title :match (" ^Heroic Tragedy" ) then
1184- self :DrawImageRotated (self .kalguur1 , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1185- self :DrawImageRotated (self .kalguur2 , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1186- else
1187- self :DrawImageRotated (self .jewelShadedOuterRing , scrX , scrY , outerSize * 2 , outerSize * 2 , - 0.7 )
1188- self :DrawImageRotated (self .jewelShadedOuterRingFlipped , scrX , scrY , outerSize * 2 , outerSize * 2 , 0.7 )
1189- self :DrawImageRotated (self .jewelShadedInnerRing , scrX , scrY , innerSize * 2 , innerSize * 2 , - 0.7 )
1190- self :DrawImageRotated (self .jewelShadedInnerRingFlipped , scrX , scrY , innerSize * 2 , innerSize * 2 , 0.7 )
1191- end
1199+ end
1200+ if node .alloc or (compareNode and compareNode .alloc ) then
1201+ local pHasRadius = jewel and jewel .jewelRadiusIndex
1202+ local cHasRadius = cJewel and cJewel .jewelRadiusIndex
1203+ local sameJewel = compareJewelsEqual (jewel , cJewel )
1204+ if pHasRadius then
1205+ local tint = (not self .compareSpec or sameJewel ) and JEWEL_RADIUS_TINT_NEUTRAL or JEWEL_RADIUS_TINT_PRIMARY_ONLY
1206+ drawJewelRadius (jewel , scrX , scrY , tint )
1207+ end
1208+ if cHasRadius and not sameJewel then
1209+ drawJewelRadius (cJewel , scrX , scrY , JEWEL_RADIUS_TINT_COMPARE_ONLY )
11921210 end
11931211 end
11941212 end
@@ -1407,30 +1425,40 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build)
14071425 self .skillTooltip :Clear ()
14081426 tooltip .center = true
14091427 tooltip .maxWidth = 800
1428+ -- Appends the compare spec's jewel tooltip if it has a jewel in this allocated socket.
1429+ local function addCompareJewelSection (socket , withLabel )
1430+ local cJewel = self .compareSpec and self :GetCompareJewel (node .id )
1431+ local cAllocated = self .compareSpec and self .compareSpec .allocNodes and self .compareSpec .allocNodes [node .id ]
1432+ if not cJewel or not cAllocated then
1433+ return false
1434+ end
1435+ if withLabel then
1436+ tooltip :AddSeparator (14 )
1437+ tooltip :AddLine (14 , colorCodes .DEXTERITY .. " Compared build:" )
1438+ end
1439+ self .compareSpec .build .itemsTab :AddItemTooltip (tooltip , cJewel , socket )
1440+ return true
1441+ end
1442+
14101443 -- Special case for sockets
14111444 if node .type == " Socket" and node .alloc then
14121445 local socket , jewel = build .itemsTab :GetSocketAndJewelForNodeID (node .id )
1446+ local cJewel = self .compareSpec and self :GetCompareJewel (node .id ) or nil
14131447 if jewel then
14141448 build .itemsTab :AddItemTooltip (tooltip , jewel , socket )
1415- if node .distanceToClassStart and node .distanceToClassStart > 0 then
1416- tooltip :AddSeparator (14 )
1417- tooltip :AddLine (16 , string.format (" ^7Distance to start: %d" , node .distanceToClassStart ))
1449+ if not compareJewelsEqual (jewel , cJewel ) then
1450+ addCompareJewelSection (socket , true )
14181451 end
1419- else
1452+ elseif not addCompareJewelSection ( socket , false ) then
14201453 self :AddNodeName (tooltip , node , build )
14211454 end
1422- -- Show compare build's jewel info when in overlay compare mode
1423- if self .compareSpec then
1424- local cJewel = self :GetCompareJewel (node .id )
1425- local cAllocated = self .compareSpec .allocNodes and self .compareSpec .allocNodes [node .id ]
1426- if cJewel then
1427- tooltip :AddSeparator (14 )
1428- tooltip :AddLine (16 , colorCodes .WARNING .. " Compared build jewel:" )
1429- tooltip :AddLine (16 , (cJewel .rarity == " UNIQUE" and colorCodes .UNIQUE or cJewel .rarity == " RARE" and colorCodes .RARE or cJewel .rarity == " MAGIC" and colorCodes .MAGIC or " ^7" ) .. cJewel .name )
1430- elseif cAllocated then
1431- tooltip :AddSeparator (14 )
1432- tooltip :AddLine (16 , colorCodes .WARNING .. " Compared build: ^7(empty socket)" )
1433- end
1455+ if self .compareSpec and self .compareSpec .allocNodes and self .compareSpec .allocNodes [node .id ] and not cJewel then
1456+ tooltip :AddSeparator (14 )
1457+ tooltip :AddLine (16 , colorCodes .WARNING .. " Compared build: ^7(empty socket)" )
1458+ end
1459+ if node .distanceToClassStart and node .distanceToClassStart > 0 then
1460+ tooltip :AddSeparator (14 )
1461+ tooltip :AddLine (16 , string.format (" ^7Distance to start: %d" , node .distanceToClassStart ))
14341462 end
14351463 tooltip :AddSeparator (14 )
14361464 if socket :IsEnabled () then
@@ -1441,16 +1469,9 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build)
14411469 end
14421470
14431471 -- For unallocated sockets, show compare build's jewel if it has one
1444- if node .type == " Socket" and not node .alloc and self .compareSpec then
1445- local cJewel = self :GetCompareJewel (node .id )
1446- local cItemsTab = self .compareSpec .build and self .compareSpec .build .itemsTab
1447- local cAllocated = self .compareSpec .allocNodes and self .compareSpec .allocNodes [node .id ]
1448- if cJewel and cAllocated then
1449- -- Show the compare build's jewel tooltip instead of generic socket info
1450- local socket = build .itemsTab :GetSocketAndJewelForNodeID (node .id )
1451- cItemsTab :AddItemTooltip (tooltip , cJewel , socket )
1452- tooltip :AddSeparator (14 )
1453- tooltip :AddLine (14 , colorCodes .DEXTERITY .. " Jewel from compared build" )
1472+ if node .type == " Socket" and not node .alloc then
1473+ local socket = build .itemsTab :GetSocketAndJewelForNodeID (node .id )
1474+ if addCompareJewelSection (socket , false ) then
14541475 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Hold Shift or Ctrl to hide this tooltip." )
14551476 return
14561477 end
0 commit comments