Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Classes/ModList.lua
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,32 @@ function ModListClass:TabulateInternal(context, result, modType, cfg, flags, key
end
end

---HasModInternal
--- Checks if a mod exists with the given properties
---@param modType string @The type of the mod, e.g. "BASE"
---@param flags number @The mod flags to match
---@param keywordFlags number @The mod keyword flags to match
---@param source string @The mod source to match
---@return boolean @true if the mod is found, false otherwise.
function ModListClass:HasModInternal(modType, flags, keywordFlags, source, ...)
for i = 1, select('#', ...) do
local modName = select(i, ...)
for i = 1, #self do
local mod = self[i]
if mod.name == modName and mod.type == modType and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or mod.source:match("[^:]+") == source) then
return true
end
end
end
if self.parent then
local parentResult = self.parent:HasModInternal(modType, flags, keywordFlags, source, ...)
if parentResult == true then
return true
end
end
return false
end

function ModListClass:Print()
for _, mod in ipairs(self) do
ConPrintf("%s|%s", modLib.formatMod(mod), mod.source or "?")
Expand Down
99 changes: 99 additions & 0 deletions src/Classes/PassiveSpec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ function PassiveSpecClass:Init(treeVersion, convert)
end
end

-- Table of intuitive leap-like jewel node modifiers from one type of node to others with the given radius
-- { from = nodeType, radiusIndex = index, to = { nodeType, [...] } }
self.intuitiveLeapLikeNodes = { }

-- List of currently allocated nodes
-- Keys are node IDs, values are nodes
self.allocNodes = { }
Expand Down Expand Up @@ -1103,6 +1107,23 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
-- This table will keep track of which nodes have been visited during each path-finding attempt
local visited = { }
local attributes = { "Dexterity", "Intelligence", "Strength", "Attribute" }

-- First check for mods that affect intuitive leap-like properties of other nodes
local processed = { }
local intuitiveLeapLikeNodes = self.intuitiveLeapLikeNodes
wipeTable(intuitiveLeapLikeNodes)
for id, node in pairs(self.allocNodes) do
if node.ascendancyName then -- avoid processing potentially replaceable nodes
self.tree:ProcessStats(node)
if node.modList:HasMod("LIST", nil, "AllocateFromNodeRadius") then
for _, radius in ipairs(node.modList:List(nil, "AllocateFromNodeRadius")) do
t_insert(intuitiveLeapLikeNodes, radius)
end
end
processed[id] = true
end
end

-- Check all nodes for other nodes which depend on them (i.e. are only connected to the tree through that node)
self.switchableNodes = { }
for id, node in pairs(self.nodes) do
Expand Down Expand Up @@ -1155,6 +1176,32 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
end
end
end
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
local allocatable = false
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
if allocatableNodeType == node.type then
allocatable = true
break
end
end
if allocatable then
if intuitiveLeapMap.from == "Keystone" then
for keyName, keyNode in pairs(self.tree.keystoneMap) do
if self.allocNodes[keyNode.id] and keyNode.nodesInRadius and keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][id] then
t_insert(node.intuitiveLeapLikesAffecting, self.nodes[keyNode.id])
end
end
end
-- We don't keep a `nodesInRadius` map for notables, so this is disabled for now
-- if intuitiveLeapMap.from == "Notable" then
-- for keyName, keyNode in pairs(self.tree.notableMap) do
-- if keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][node.id] then
-- t_insert(node.intuitiveLeapLikesAffecting, self.nodes[nodeId])
-- end
-- end
-- end
end
end
end
if node.alloc then
node.depends[1] = node -- All nodes depend on themselves
Expand Down Expand Up @@ -1472,6 +1519,35 @@ function PassiveSpecClass:BuildAllDependsAndPaths()

-- If n is a jewel socket containing an intuitive leap-like jewel, nodes in its radius (or the radius of the keystone)
-- may be dependent on this node if they're found to be unconnected to the start
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
local allocatable = false
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
if allocatableNodeType == node.type then
allocatable = true
break
end
end
if allocatable then
if intuitiveLeapMap.from == n.type then
for affectedNodeId, affectedNode in pairs(n.nodesInRadius[intuitiveLeapMap.radiusIndex]) do
if affectedNode.alloc then
if not intuitiveLeaps[node.id] then
intuitiveLeaps[node.id] = { }
end
t_insert(intuitiveLeaps[node.id], affectedNode)
end
end
end
-- We don't keep a `nodesInRadius` map for notables, so this is disabled for now
-- if intuitiveLeapMap.from == "Notable" then
-- for keyName, keyNode in pairs(self.tree.notableMap) do
-- if keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][node.id] then
-- t_insert(node.intuitiveLeapLikesAffecting, self.nodes[nodeId])
-- end
-- end
-- end
end
end
if not intuitiveLeaps[node.id] then
intuitiveLeaps[node.id] = self:NodesInIntuitiveLeapLikeRadius(n)
else
Expand Down Expand Up @@ -1517,6 +1593,29 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
end
end
end
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
local allocatable = false
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
if allocatableNodeType == depNode.type then
allocatable = true
break
end
end
if allocatable then
if intuitiveLeapMap.from == "Keystone" then
for keyName, keyNode in pairs(self.tree.keystoneMap) do
if keyNode.nodesInRadius and keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][depNode.id] then
-- Hold off on the pruning; this node could be supported by Intuitive Leap-like jewel
prune = false
if not intuitiveLeaps[keyNode.id] then
intuitiveLeaps[keyNode.id] = { }
end
t_insert(intuitiveLeaps[keyNode.id], depNode)
end
end
end
end
end
if prune then
self:DeallocSingleNode(depNode)
end
Expand Down
17 changes: 17 additions & 0 deletions src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,23 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
end
end
end

-- Draw ring overlays for other sources of intuitive leap-like effects
for _, effectData in ipairs(spec.intuitiveLeapLikeNodes) do
local radData = build.data.jewelRadius[effectData.radiusIndex]
local outerSize = radData.outer * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale
if effectData.from == "Keystone" then
for keystoneName, keystoneNode in pairs(spec.tree.keystoneMap) do
if keystoneNode and spec.allocNodes[keystoneNode.id]
and keystoneName == keystoneNode.name -- keystoneMap contains both TitleCase and lowercase names, so we only need to draw once
and keystoneNode.x and keystoneNode.y then
local keyX, keyY = treeToScreen(keystoneNode.x, keystoneNode.y)
self:DrawImageRotated(self.jewelShadedOuterRing, keyX, keyY, outerSize * 2, outerSize * 2, -0.7)
self:DrawImageRotated(self.jewelShadedOuterRingFlipped, keyX, keyY, outerSize * 2, outerSize * 2, 0.7)
end
end
end
end
end

-- Draws the given asset at the given position
Expand Down
2 changes: 1 addition & 1 deletion src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5665,7 +5665,7 @@ c["Non-Channelling Spells deal 10% increased Damage per 100 maximum Life"]={{[1]
c["Non-Channelling Spells deal 6% increased Damage per 100 maximum Life"]={{[1]={[1]={neg=true,skillType=48,type="SkillType"},[2]={div=100,stat="Life",type="PerStat"},flags=2,keywordFlags=0,name="Damage",type="INC",value=6}},nil}
c["Non-Channelling Spells have 3% increased Critical Hit Chance per 100 maximum Life"]={{[1]={[1]={neg=true,skillType=48,type="SkillType"},[2]={div=100,stat="Life",type="PerStat"},flags=2,keywordFlags=0,name="CritChance",type="INC",value=3}},nil}
c["Non-Channelling Spells have 5% increased Critical Hit Chance per 100 maximum Life"]={{[1]={[1]={neg=true,skillType=48,type="SkillType"},[2]={div=100,stat="Life",type="PerStat"},flags=2,keywordFlags=0,name="CritChance",type="INC",value=5}},nil}
c["Non-Keystone Passive Skills in Medium Radius of allocated Keystone Passive Skills can be allocated without being connected to your tree"]={nil,"Non-Keystone Passive Skills in Medium Radius of allocated Keystone Passive Skills can be allocated without being connected to your tree "}
c["Non-Keystone Passive Skills in Medium Radius of allocated Keystone Passive Skills can be allocated without being connected to your tree"]={{[1]={flags=0,keywordFlags=0,name="AllocateFromNodeRadius",type="LIST",value={from="Keystone",radiusIndex=2,to={[1]="Notable",[2]="Normal"}}}},nil}
c["Non-Minion Skills have 50% less Reservation Efficiency"]={nil,"Non-Minion Skills have 50% less Reservation Efficiency "}
c["Non-Unique Time-Lost Jewels have 40% increased radius"]={nil,"Non-Unique Time-Lost Jewels have 40% increased radius "}
c["Offering Skills have 15% increased Buff effect"]={{[1]={[1]={skillType=154,type="SkillType"},flags=0,keywordFlags=0,name="BuffEffect",type="INC",value=15}},nil}
Expand Down
3 changes: 3 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5317,6 +5317,9 @@ local specialModList = {
} end,
["charms applied to you have (%d+)%% increased effect"] = function(num) return { mod("CharmEffect", "INC", num, { type = "ActorCondition", actor = "player"}) } end,
-- Jewels
["non%-keystone passive skills in medium radius of allocated keystone passive skills can be allocated without being connected to your tree"] = function(_, radius) return {
mod("AllocateFromNodeRadius", "LIST", { from = "Keystone", radiusIndex = 2, to = { "Notable", "Normal" } }),
} end,
["passives in radius of ([%a%s']+) can be allocated without being connected to your tree"] = function(_, name) return {
mod("JewelData", "LIST", { key = "fromNothingKeystone", value = name }),
mod("FromNothingKeystones", "LIST", { key = name, value = true }),
Expand Down
Loading