@@ -479,6 +479,7 @@ function CalcsTabClass:PowerBuilder()
479479 local cache = { }
480480 local distanceMap = { }
481481 local distanceList = { }
482+ local masteryNodeList = { }
482483 local newPowerMax = {
483484 singleStat = 0 ,
484485 offence = 0 ,
@@ -492,18 +493,73 @@ function CalcsTabClass:PowerBuilder()
492493 if coroutine.running () then
493494 coroutine.yield ()
494495 end
496+
497+ local function buildMasteryEffectNode (node , effect )
498+ local effectNode = {
499+ id = node .id ,
500+ type = node .type ,
501+ name = node .name ,
502+ sd = { },
503+ }
504+ for i , sd in ipairs (effect .sd or { }) do
505+ effectNode .sd [i ] = sd
506+ end
507+ self .build .spec .tree :ProcessStats (effectNode )
508+ return effectNode
509+ end
510+
511+ local function masteryEffectCanBeAssignedToNode (node , masteryEffect )
512+ local assignedNodeId = isValueInTable (self .build .spec .masterySelections , masteryEffect .effect )
513+ return not assignedNodeId or assignedNodeId == node .id
514+ end
515+
516+ local function calculateAddNodePower (power , node , output , buildPathNodes )
517+ if self .powerStat and self .powerStat .stat and not self .powerStat .ignoreForNodes then
518+ power .singleStat = self :CalculatePowerStat (self .powerStat , output , calcBase )
519+ if node .path and not node .ascendancyName then
520+ newPowerMax .singleStat = m_max (newPowerMax .singleStat , power .singleStat )
521+ power .pathPower = power .singleStat
522+ if node .pathDist > 1 then
523+ power .pathPower = self :CalculatePowerStat (self .powerStat , calcFunc ({ addNodes = buildPathNodes () }, useFullDPS ), calcBase )
524+ end
525+ end
526+ elseif not self .powerStat or not self .powerStat .ignoreForNodes then
527+ power .offence , power .defence = self :CalculateCombinedOffDefStat (output , calcBase )
528+ power .singleStat = power .offence
529+ if node .path and not node .ascendancyName then
530+ newPowerMax .offence = m_max (newPowerMax .offence , power .offence )
531+ newPowerMax .defence = m_max (newPowerMax .defence , power .defence )
532+ newPowerMax .offencePerPoint = m_max (newPowerMax .offencePerPoint , power .offence / node .pathDist )
533+ newPowerMax .defencePerPoint = m_max (newPowerMax .defencePerPoint , power .defence / node .pathDist )
534+ end
535+ end
536+ end
495537
496538 local start = GetTime ()
497539 local nodeIndex = 0
498540 local total = 0
499541
500542 for nodeId , node in pairs (self .build .spec .nodes ) do
501543 wipeTable (node .power )
544+ if node .type == " Mastery" then
545+ node .power .masteryEffects = { }
546+ end
502547 if node .modKey ~= " " and not self .mainEnv .grantedPassives [nodeId ] then
503- distanceMap [node .pathDist or 1000 ] = distanceMap [node .pathDist or 1000 ] or { }
504- distanceMap [node .pathDist or 1000 ][nodeId ] = node
505- if not (self .nodePowerMaxDepth and self .nodePowerMaxDepth < node .pathDist ) then
506- total = total + 1
548+ if node .type == " Mastery" and node .allMasteryOptions then
549+ if not (self .nodePowerMaxDepth and self .nodePowerMaxDepth < node .pathDist ) then
550+ t_insert (masteryNodeList , node )
551+ for _ , masteryEffect in ipairs (node .masteryEffects or { }) do
552+ if masteryEffectCanBeAssignedToNode (node , masteryEffect ) then
553+ total = total + 1
554+ end
555+ end
556+ end
557+ else
558+ distanceMap [node .pathDist or 1000 ] = distanceMap [node .pathDist or 1000 ] or { }
559+ distanceMap [node .pathDist or 1000 ][nodeId ] = node
560+ if not (self .nodePowerMaxDepth and self .nodePowerMaxDepth < node .pathDist ) then
561+ total = total + 1
562+ end
507563 end
508564 end
509565 end
@@ -530,29 +586,13 @@ function CalcsTabClass:PowerBuilder()
530586 cache [node .modKey ] = calcFunc ({ addNodes = { [node ] = true } }, useFullDPS )
531587 end
532588 local output = cache [node .modKey ]
533- if self .powerStat and self .powerStat .stat and not self .powerStat .ignoreForNodes then
534- node .power .singleStat = self :CalculatePowerStat (self .powerStat , output , calcBase )
535- if node .path and not node .ascendancyName then
536- newPowerMax .singleStat = m_max (newPowerMax .singleStat , node .power .singleStat )
537- node .power .pathPower = node .power .singleStat
538- local pathNodes = { }
539- for _ , node in pairs (node .path ) do
540- pathNodes [node ] = true
541- end
542- if node .pathDist > 1 then
543- node .power .pathPower = self :CalculatePowerStat (self .powerStat , calcFunc ({ addNodes = pathNodes }, useFullDPS ), calcBase )
544- end
545- end
546- elseif not self .powerStat or not self .powerStat .ignoreForNodes then
547- node .power .offence , node .power .defence = self :CalculateCombinedOffDefStat (output , calcBase )
548- node .power .singleStat = node .power .offence
549- if node .path and not node .ascendancyName then
550- newPowerMax .offence = m_max (newPowerMax .offence , node .power .offence )
551- newPowerMax .defence = m_max (newPowerMax .defence , node .power .defence )
552- newPowerMax .offencePerPoint = m_max (newPowerMax .offencePerPoint , node .power .offence / node .pathDist )
553- newPowerMax .defencePerPoint = m_max (newPowerMax .defencePerPoint , node .power .defence / node .pathDist )
589+ calculateAddNodePower (node .power , node , output , function ()
590+ local pathNodes = { }
591+ for _ , pathNode in pairs (node .path ) do
592+ pathNodes [pathNode ] = true
554593 end
555- end
594+ return pathNodes
595+ end )
556596 elseif node .alloc and node .modKey ~= " " and not self .mainEnv .grantedPassives [nodeId ] then
557597 if not cache [node .modKey .. " _remove" ] then
558598 cache [node .modKey .. " _remove" ] = calcFunc ({ removeNodes = { [node ] = true } }, useFullDPS )
@@ -572,6 +612,17 @@ function CalcsTabClass:PowerBuilder()
572612 end
573613 end
574614 end
615+ if node .type == " Mastery" then
616+ local selectedEffectId = self .build .spec .masterySelections [node .id ]
617+ if selectedEffectId then
618+ node .power .masteryEffects [selectedEffectId ] = {
619+ singleStat = node .power .singleStat ,
620+ pathPower = node .power .pathPower ,
621+ offence = node .power .offence ,
622+ defence = node .power .defence ,
623+ }
624+ end
625+ end
575626 nodeIndex = nodeIndex + 1
576627 if coroutine.running () and GetTime () - start > 100 then
577628 if self .build .powerBuilderProgressCallback then
@@ -583,6 +634,53 @@ function CalcsTabClass:PowerBuilder()
583634 end
584635 end
585636
637+ for _ , node in ipairs (masteryNodeList ) do
638+ for _ , masteryEffect in ipairs (node .masteryEffects or { }) do
639+ if masteryEffectCanBeAssignedToNode (node , masteryEffect ) then
640+ local effect = self .build .spec .tree .masteryEffects [masteryEffect .effect ]
641+ if effect then
642+ local effectNode = buildMasteryEffectNode (node , effect )
643+ if effectNode .modKey ~= " " then
644+ if not cache [effectNode .modKey ] then
645+ cache [effectNode .modKey ] = calcFunc ({ addNodes = { [effectNode ] = true } }, useFullDPS )
646+ end
647+ local output = cache [effectNode .modKey ]
648+ node .power .masteryEffects [effect .id ] = { }
649+ local effectPower = node .power .masteryEffects [effect .id ]
650+ calculateAddNodePower (effectPower , node , output , function ()
651+ local pathNodes = {
652+ [effectNode ] = true
653+ }
654+ for _ , pathNode in pairs (node .path ) do
655+ if pathNode ~= node then
656+ pathNodes [pathNode ] = true
657+ end
658+ end
659+ return pathNodes
660+ end )
661+ if self .powerStat and self .powerStat .stat and not self .powerStat .ignoreForNodes then
662+ effectPower .pathPower = effectPower .pathPower or effectPower .singleStat
663+ node .power .singleStat = m_max (node .power .singleStat or 0 , effectPower .singleStat )
664+ node .power .pathPower = m_max (node .power .pathPower or 0 , effectPower .pathPower )
665+ elseif not self .powerStat or not self .powerStat .ignoreForNodes then
666+ node .power .offence = m_max (node .power .offence or 0 , effectPower .offence )
667+ node .power .defence = m_max (node .power .defence or 0 , effectPower .defence )
668+ node .power .singleStat = m_max (node .power .singleStat or 0 , effectPower .singleStat )
669+ end
670+ end
671+ nodeIndex = nodeIndex + 1
672+ if coroutine.running () and GetTime () - start > 100 then
673+ if self .build .powerBuilderProgressCallback then
674+ self .build .powerBuilderProgressCallback (m_floor (nodeIndex / total * 100 ))
675+ end
676+ coroutine.yield ()
677+ start = GetTime ()
678+ end
679+ end
680+ end
681+ end
682+ end
683+
586684 -- Calculate the impact of every cluster notable
587685 -- used for the power report screen
588686 for nodeName , node in pairs (self .build .spec .tree .clusterNodeMap ) do
0 commit comments