Skip to content

Commit 39f2bf4

Browse files
Wires77LocalIdentity
andauthored
Add support for Entwined Realities (#1642)
* Fix 1632: Implement Entwined Realities * Draw radius around allocated keystones * Remove inner circle * remove unused variable * Fix function --------- Co-authored-by: LocalIdentity <[email protected]>
1 parent 09ec774 commit 39f2bf4

File tree

5 files changed

+146
-1
lines changed

5 files changed

+146
-1
lines changed

src/Classes/ModList.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,32 @@ function ModListClass:TabulateInternal(context, result, modType, cfg, flags, key
217217
end
218218
end
219219

220+
---HasModInternal
221+
--- Checks if a mod exists with the given properties
222+
---@param modType string @The type of the mod, e.g. "BASE"
223+
---@param flags number @The mod flags to match
224+
---@param keywordFlags number @The mod keyword flags to match
225+
---@param source string @The mod source to match
226+
---@return boolean @true if the mod is found, false otherwise.
227+
function ModListClass:HasModInternal(modType, flags, keywordFlags, source, ...)
228+
for i = 1, select('#', ...) do
229+
local modName = select(i, ...)
230+
for i = 1, #self do
231+
local mod = self[i]
232+
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
233+
return true
234+
end
235+
end
236+
end
237+
if self.parent then
238+
local parentResult = self.parent:HasModInternal(modType, flags, keywordFlags, source, ...)
239+
if parentResult == true then
240+
return true
241+
end
242+
end
243+
return false
244+
end
245+
220246
function ModListClass:Print()
221247
for _, mod in ipairs(self) do
222248
ConPrintf("%s|%s", modLib.formatMod(mod), mod.source or "?")

src/Classes/PassiveSpec.lua

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ function PassiveSpecClass:Init(treeVersion, convert)
6464
end
6565
end
6666

67+
-- Table of intuitive leap-like jewel node modifiers from one type of node to others with the given radius
68+
-- { from = nodeType, radiusIndex = index, to = { nodeType, [...] } }
69+
self.intuitiveLeapLikeNodes = { }
70+
6771
-- List of currently allocated nodes
6872
-- Keys are node IDs, values are nodes
6973
self.allocNodes = { }
@@ -1103,6 +1107,23 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
11031107
-- This table will keep track of which nodes have been visited during each path-finding attempt
11041108
local visited = { }
11051109
local attributes = { "Dexterity", "Intelligence", "Strength", "Attribute" }
1110+
1111+
-- First check for mods that affect intuitive leap-like properties of other nodes
1112+
local processed = { }
1113+
local intuitiveLeapLikeNodes = self.intuitiveLeapLikeNodes
1114+
wipeTable(intuitiveLeapLikeNodes)
1115+
for id, node in pairs(self.allocNodes) do
1116+
if node.ascendancyName then -- avoid processing potentially replaceable nodes
1117+
self.tree:ProcessStats(node)
1118+
if node.modList:HasMod("LIST", nil, "AllocateFromNodeRadius") then
1119+
for _, radius in ipairs(node.modList:List(nil, "AllocateFromNodeRadius")) do
1120+
t_insert(intuitiveLeapLikeNodes, radius)
1121+
end
1122+
end
1123+
processed[id] = true
1124+
end
1125+
end
1126+
11061127
-- Check all nodes for other nodes which depend on them (i.e. are only connected to the tree through that node)
11071128
self.switchableNodes = { }
11081129
for id, node in pairs(self.nodes) do
@@ -1155,6 +1176,32 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
11551176
end
11561177
end
11571178
end
1179+
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
1180+
local allocatable = false
1181+
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
1182+
if allocatableNodeType == node.type then
1183+
allocatable = true
1184+
break
1185+
end
1186+
end
1187+
if allocatable then
1188+
if intuitiveLeapMap.from == "Keystone" then
1189+
for keyName, keyNode in pairs(self.tree.keystoneMap) do
1190+
if self.allocNodes[keyNode.id] and keyNode.nodesInRadius and keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][id] then
1191+
t_insert(node.intuitiveLeapLikesAffecting, self.nodes[keyNode.id])
1192+
end
1193+
end
1194+
end
1195+
-- We don't keep a `nodesInRadius` map for notables, so this is disabled for now
1196+
-- if intuitiveLeapMap.from == "Notable" then
1197+
-- for keyName, keyNode in pairs(self.tree.notableMap) do
1198+
-- if keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][node.id] then
1199+
-- t_insert(node.intuitiveLeapLikesAffecting, self.nodes[nodeId])
1200+
-- end
1201+
-- end
1202+
-- end
1203+
end
1204+
end
11581205
end
11591206
if node.alloc then
11601207
node.depends[1] = node -- All nodes depend on themselves
@@ -1472,6 +1519,35 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
14721519

14731520
-- If n is a jewel socket containing an intuitive leap-like jewel, nodes in its radius (or the radius of the keystone)
14741521
-- may be dependent on this node if they're found to be unconnected to the start
1522+
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
1523+
local allocatable = false
1524+
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
1525+
if allocatableNodeType == node.type then
1526+
allocatable = true
1527+
break
1528+
end
1529+
end
1530+
if allocatable then
1531+
if intuitiveLeapMap.from == n.type then
1532+
for affectedNodeId, affectedNode in pairs(n.nodesInRadius[intuitiveLeapMap.radiusIndex]) do
1533+
if affectedNode.alloc then
1534+
if not intuitiveLeaps[node.id] then
1535+
intuitiveLeaps[node.id] = { }
1536+
end
1537+
t_insert(intuitiveLeaps[node.id], affectedNode)
1538+
end
1539+
end
1540+
end
1541+
-- We don't keep a `nodesInRadius` map for notables, so this is disabled for now
1542+
-- if intuitiveLeapMap.from == "Notable" then
1543+
-- for keyName, keyNode in pairs(self.tree.notableMap) do
1544+
-- if keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][node.id] then
1545+
-- t_insert(node.intuitiveLeapLikesAffecting, self.nodes[nodeId])
1546+
-- end
1547+
-- end
1548+
-- end
1549+
end
1550+
end
14751551
if not intuitiveLeaps[node.id] then
14761552
intuitiveLeaps[node.id] = self:NodesInIntuitiveLeapLikeRadius(n)
14771553
else
@@ -1517,6 +1593,29 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
15171593
end
15181594
end
15191595
end
1596+
for _, intuitiveLeapMap in ipairs(intuitiveLeapLikeNodes) do
1597+
local allocatable = false
1598+
for _, allocatableNodeType in ipairs(intuitiveLeapMap.to) do
1599+
if allocatableNodeType == depNode.type then
1600+
allocatable = true
1601+
break
1602+
end
1603+
end
1604+
if allocatable then
1605+
if intuitiveLeapMap.from == "Keystone" then
1606+
for keyName, keyNode in pairs(self.tree.keystoneMap) do
1607+
if keyNode.nodesInRadius and keyNode.nodesInRadius[intuitiveLeapMap.radiusIndex][depNode.id] then
1608+
-- Hold off on the pruning; this node could be supported by Intuitive Leap-like jewel
1609+
prune = false
1610+
if not intuitiveLeaps[keyNode.id] then
1611+
intuitiveLeaps[keyNode.id] = { }
1612+
end
1613+
t_insert(intuitiveLeaps[keyNode.id], depNode)
1614+
end
1615+
end
1616+
end
1617+
end
1618+
end
15201619
if prune then
15211620
self:DeallocSingleNode(depNode)
15221621
end

src/Classes/PassiveTreeView.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,23 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
10551055
end
10561056
end
10571057
end
1058+
1059+
-- Draw ring overlays for other sources of intuitive leap-like effects
1060+
for _, effectData in ipairs(spec.intuitiveLeapLikeNodes) do
1061+
local radData = build.data.jewelRadius[effectData.radiusIndex]
1062+
local outerSize = radData.outer * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale
1063+
if effectData.from == "Keystone" then
1064+
for keystoneName, keystoneNode in pairs(spec.tree.keystoneMap) do
1065+
if keystoneNode and spec.allocNodes[keystoneNode.id]
1066+
and keystoneName == keystoneNode.name -- keystoneMap contains both TitleCase and lowercase names, so we only need to draw once
1067+
and keystoneNode.x and keystoneNode.y then
1068+
local keyX, keyY = treeToScreen(keystoneNode.x, keystoneNode.y)
1069+
self:DrawImageRotated(self.jewelShadedOuterRing, keyX, keyY, outerSize * 2, outerSize * 2, -0.7)
1070+
self:DrawImageRotated(self.jewelShadedOuterRingFlipped, keyX, keyY, outerSize * 2, outerSize * 2, 0.7)
1071+
end
1072+
end
1073+
end
1074+
end
10581075
end
10591076

10601077
-- Draws the given asset at the given position

src/Data/ModCache.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5665,7 +5665,7 @@ c["Non-Channelling Spells deal 10% increased Damage per 100 maximum Life"]={{[1]
56655665
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}
56665666
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}
56675667
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}
5668-
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 "}
5668+
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}
56695669
c["Non-Minion Skills have 50% less Reservation Efficiency"]={nil,"Non-Minion Skills have 50% less Reservation Efficiency "}
56705670
c["Non-Unique Time-Lost Jewels have 40% increased radius"]={nil,"Non-Unique Time-Lost Jewels have 40% increased radius "}
56715671
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}

src/Modules/ModParser.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5317,6 +5317,9 @@ local specialModList = {
53175317
} end,
53185318
["charms applied to you have (%d+)%% increased effect"] = function(num) return { mod("CharmEffect", "INC", num, { type = "ActorCondition", actor = "player"}) } end,
53195319
-- Jewels
5320+
["non%-keystone passive skills in medium radius of allocated keystone passive skills can be allocated without being connected to your tree"] = function(_, radius) return {
5321+
mod("AllocateFromNodeRadius", "LIST", { from = "Keystone", radiusIndex = 2, to = { "Notable", "Normal" } }),
5322+
} end,
53205323
["passives in radius of ([%a%s']+) can be allocated without being connected to your tree"] = function(_, name) return {
53215324
mod("JewelData", "LIST", { key = "fromNothingKeystone", value = name }),
53225325
mod("FromNothingKeystones", "LIST", { key = name, value = true }),

0 commit comments

Comments
 (0)