Skip to content

Commit 216d9a3

Browse files
LocalIdentityLocalIdentity
andauthored
Fix Split Personality not allowing connection from other Ascendancies (#2126)
* Add support for Split Personality jewel The split personality jewel allows you to start your tree from a different ascendancy starting point. As the mod now appears on a jewel we have to parse the mod and then feed it into passive spec so it's ready in time to build the tree Added a test using a JSON from a character to test this functionality * Fix jewel art The jewel was not using the correct art as we assumed every unique jewel had their own art * ModCache --------- Co-authored-by: LocalIdentity <localidentity2@gmail.com>
1 parent 8304b1a commit 216d9a3

6 files changed

Lines changed: 85 additions & 12 deletions

File tree

spec/System/TestImportTab_spec.lua

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,59 @@ describe("ImportTab", function()
4343
assert.are.equals(1, #importTab.controls.charSelect.list)
4444
assert.True(importTab.controls.charSelect.list[1].detail:match("Future Ascendancy") ~= nil)
4545
end)
46+
47+
it("imports Split Personality alternate class start from character JSON", function()
48+
local spec = build.spec
49+
local socketNode = spec.nodes[60735]
50+
local rangerStartPassive = spec.nodes[56651]
51+
assert.is_not_nil(socketNode)
52+
assert.is_not_nil(rangerStartPassive)
53+
54+
local hashes = { socketNode.id, rangerStartPassive.id }
55+
for _, pathNode in ipairs(socketNode.path or { }) do
56+
table.insert(hashes, pathNode.id)
57+
end
58+
59+
local rangerStart = spec.nodes[spec.tree.classes[spec.tree.classNameMap.Ranger].startNodeId]
60+
local importPayload = {
61+
name = "Split Import Test",
62+
class = "Witch2",
63+
league = "Test",
64+
level = 90,
65+
jewels = {
66+
{
67+
id = "split-personality-test",
68+
frameType = 3,
69+
name = "Split Personality",
70+
typeLine = "Ruby",
71+
inventoryId = "PassiveJewels",
72+
x = 4,
73+
ilvl = 84,
74+
properties = { },
75+
explicitMods = {
76+
"Can Allocate Passive Skills from the Ranger's starting point",
77+
},
78+
},
79+
},
80+
passives = {
81+
hashes = hashes,
82+
specialisations = { },
83+
skill_overrides = { },
84+
jewel_data = { },
85+
quest_stats = { },
86+
},
87+
}
88+
89+
build.importTab:ImportPassiveTreeAndJewels(importPayload)
90+
91+
local importedSpec = build.spec
92+
local importedJewel = build.itemsTab.items[importedSpec.jewels[socketNode.id]]
93+
assert.are.equals("Ranger", importedJewel.jewelData.alternateClassStart)
94+
95+
assert.are.equals(0, importedSpec.nodes[rangerStart.id].pathDist)
96+
assert.True(importedSpec.nodes[rangerStartPassive.id].alloc)
97+
assert.True(importedSpec.nodes[rangerStartPassive.id].connectedToStart)
98+
end)
4699
end)
47100

48101
describe("ImportTab quest reward import", function()

src/Classes/Item.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,9 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
18951895
for _, value in ipairs(modList:List(nil, "JewelData")) do
18961896
jewelData[value.key] = value.value
18971897
end
1898+
for _, className in ipairs(modList:List(nil, "AlternateClassStart")) do
1899+
jewelData.alternateClassStart = className
1900+
end
18981901
if modList:List(nil, "FromNothingKeystones") then
18991902
jewelData.fromNothingKeystones = { }
19001903
for _, value in ipairs(modList:List(nil, "FromNothingKeystones")) do

src/Classes/PassiveSpec.lua

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ end
10181018

10191019
-- Attempt to find a class start node starting from the given node
10201020
-- Unless noAscent == true it will also look for an ascendancy class start node
1021-
function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode)
1021+
function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode, alternateClassStartNodes)
10221022
allocMode = allocMode or node.allocMode or 0
10231023
-- Mark the current node as visited so we don't go around in circles
10241024
node.visited = true
@@ -1029,9 +1029,10 @@ function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode)
10291029
-- - the other node is a start node, or
10301030
-- - there is a path to a start node through the other node which didn't pass through any nodes which have already been visited
10311031
local startIndex = #visited + 1
1032-
if other.alloc and self:CanPathThroughAllocMode(allocMode, other) and
1032+
local otherAlloc = other.alloc or (alternateClassStartNodes and alternateClassStartNodes[other.id])
1033+
if otherAlloc and self:CanPathThroughAllocMode(allocMode, other) and
10331034
(other.type == "ClassStart" or other.type == "AscendClassStart" or
1034-
(not other.visited and node.type ~= "Mastery" and self:FindStartFromNode(other, visited, noAscend, allocMode))
1035+
(not other.visited and node.type ~= "Mastery" and self:FindStartFromNode(other, visited, noAscend, allocMode, alternateClassStartNodes))
10351036
) then
10361037
if node.ascendancyName and not other.ascendancyName then
10371038
-- Pathing out of Ascendant, un-visit the outside nodes
@@ -1225,6 +1226,18 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
12251226
-- First check for mods that affect intuitive leap-like properties of other nodes
12261227
local processed = { }
12271228
local intuitiveLeapLikeNodes = self.intuitiveLeapLikeNodes
1229+
local alternateClassStartNodes = { }
1230+
for socketNodeId, itemId in pairs(self.jewels) do
1231+
if self.allocNodes[socketNodeId] then
1232+
local item = self:GetJewel(itemId)
1233+
local className = item and item.jewelData.alternateClassStart
1234+
local classData = className and self.tree.classes[self.tree.classNameMap[className]]
1235+
local startNode = classData and self.nodes[classData.startNodeId]
1236+
if startNode then
1237+
alternateClassStartNodes[startNode.id] = startNode
1238+
end
1239+
end
1240+
end
12281241
wipeTable(intuitiveLeapLikeNodes)
12291242
for id, node in pairs(self.allocNodes) do
12301243
if node.ascendancyName then -- avoid processing potentially replaceable nodes
@@ -1577,13 +1590,14 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
15771590
node.connectedToStart = false
15781591
local anyStartFound = (node.type == "ClassStart" or node.type == "AscendClassStart")
15791592
for _, other in ipairs(node.linked) do
1580-
if other.alloc and self:CanPathThroughAllocMode(node.allocMode or 0, other) and not isValueInArray(node.depends, other) then
1593+
local otherAlloc = other.alloc or alternateClassStartNodes[other.id]
1594+
if otherAlloc and self:CanPathThroughAllocMode(node.allocMode or 0, other) and not isValueInArray(node.depends, other) then
15811595
-- The other node is allocated and isn't already dependent on this node, so try and find a path to a start node through it
15821596
if other.type == "ClassStart" or other.type == "AscendClassStart" then
15831597
-- Well that was easy!
15841598
anyStartFound = true
15851599
node.connectedToStart = true
1586-
elseif self:FindStartFromNode(other, visited, nil, node.allocMode or 0) then
1600+
elseif self:FindStartFromNode(other, visited, nil, node.allocMode or 0, alternateClassStartNodes) then
15871601
-- We found a path through the other node, therefore the other node cannot be dependent on this node
15881602
anyStartFound = true
15891603
node.connectedToStart = true
@@ -1795,6 +1809,9 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
17951809
end
17961810
end
17971811
end
1812+
for _, node in pairs(alternateClassStartNodes) do
1813+
self:BuildPathFromNode(node)
1814+
end
17981815
end
17991816

18001817
function PassiveSpecClass:ReplaceNode(old, newNode)

src/Classes/PassiveTreeView.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,8 +912,9 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
912912

913913
local socket, jewel = build.itemsTab:GetSocketAndJewelForNodeID(nodeId)
914914
if isAlloc and jewel then
915-
if jewel.rarity == "UNIQUE" and jewel.title ~= "Grand Spectrum" then
916-
overlay = jewel.title
915+
if jewel.rarity == "UNIQUE" then
916+
local hasUniqueJewelArt = tree.ddsMap[jewel.title] or tree.assets[jewel.title] or tree.spriteMap[jewel.title]
917+
overlay = hasUniqueJewelArt and jewel.title or jewel.baseName
917918
else
918919
overlay = jewel.baseName
919920
end

src/Data/ModCache.lua

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4701,10 +4701,8 @@ c["Buffs on you expire 10% slower"]={{[1]={[1]={skillType=5,type="SkillType"},fl
47014701
c["Bulwark"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Bulwark"}},nil}
47024702
c["Burning Enemies you kill have a 5% chance to Explode, dealing a"]={nil,"Burning Enemies you kill have a 5% chance to Explode, dealing a "}
47034703
c["Burning Enemies you kill have a 5% chance to Explode, dealing a tenth of their maximum Life as Fire Damage"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Burning"},flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=10,keyOfScaledMod="value",type="Fire",value=5}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil}
4704-
c["Can Allocate Passive Skills from the Sorceress's starting point"]={nil,"Can Allocate Passive Skills from the Sorceress's starting point "}
4705-
c["Can Allocate Passive Skills from the Sorceress's starting point Grants 4 Passive Skill Point"]={nil,"Can Allocate Passive Skills from the Sorceress's starting point Grants 4 Passive Skill Point "}
4706-
c["Can Allocate Passive Skills from the Warrior's starting point"]={nil,"Can Allocate Passive Skills from the Warrior's starting point "}
4707-
c["Can Allocate Passive Skills from the Warrior's starting point Grants 4 Passive Skill Point"]={nil,"Can Allocate Passive Skills from the Warrior's starting point Grants 4 Passive Skill Point "}
4704+
c["Can Allocate Passive Skills from the Sorceress's starting point"]={{[1]={flags=0,keywordFlags=0,name="AlternateClassStart",type="LIST",value="Sorceress"}},nil}
4705+
c["Can Allocate Passive Skills from the Warrior's starting point"]={{[1]={flags=0,keywordFlags=0,name="AlternateClassStart",type="LIST",value="Warrior"}},nil}
47084706
c["Can Attack as though using a One Handed Mace while both of your hand slots are empty"]={{[1]={flags=0,keywordFlags=0,name="CanAttackAsOneHandMaceUnarmed",type="FLAG",value=true}},nil}
47094707
c["Can Attack as though using a Quarterstaff while both of your hand slots are empty"]={nil,"Can Attack as though using a Quarterstaff while both of your hand slots are empty "}
47104708
c["Can Attack as though using a Quarterstaff while both of your hand slots are empty Unarmed Attacks that would use an Equipped Quarterstaff's damage have:"]={nil,"Can Attack as though using a Quarterstaff while both of your hand slots are empty Unarmed Attacks that would use an Equipped Quarterstaff's damage have: "}

src/Modules/ModParser.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2728,7 +2728,8 @@ local specialModList = {
27282728
["evasion rating from equipped body armour is halved"] = { mod("Evasion", "MORE", -50, { type = "SlotName", slotName = "Body Armour" }) },
27292729
-- Ascendant
27302730
["grants (%d+) passive skill points?"] = function(num) return { mod("ExtraPoints", "BASE", num) } end,
2731-
["can allocate passives from the %a+'s starting point"] = { },
2731+
["can allocate passives from the (%a+)'s starting point"] = function(_, className) return { mod("AlternateClassStart", "LIST", firstToUpper(className)) } end,
2732+
["can allocate passive skills from the (%a+)'s starting point"] = function(_, className) return { mod("AlternateClassStart", "LIST", firstToUpper(className)) } end,
27322733
["projectiles gain damage as they travel farther, dealing up to (%d+)%% increased damage with hits to targets"] = function(num) return { mod("Damage", "INC", num, nil, bor(ModFlag.Hit, ModFlag.Projectile), { type = "DistanceRamp", ramp = { {35,0},{70,1} } }) } end,
27332734
["(%d+)%% chance to gain elusive on kill"] = {
27342735
flag("Condition:CanBeElusive"),

0 commit comments

Comments
 (0)