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
53 changes: 53 additions & 0 deletions spec/System/TestImportTab_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,59 @@ describe("ImportTab", function()
assert.are.equals(1, #importTab.controls.charSelect.list)
assert.True(importTab.controls.charSelect.list[1].detail:match("Future Ascendancy") ~= nil)
end)

it("imports Split Personality alternate class start from character JSON", function()
local spec = build.spec
local socketNode = spec.nodes[60735]
local rangerStartPassive = spec.nodes[56651]
assert.is_not_nil(socketNode)
assert.is_not_nil(rangerStartPassive)

local hashes = { socketNode.id, rangerStartPassive.id }
for _, pathNode in ipairs(socketNode.path or { }) do
table.insert(hashes, pathNode.id)
end

local rangerStart = spec.nodes[spec.tree.classes[spec.tree.classNameMap.Ranger].startNodeId]
local importPayload = {
name = "Split Import Test",
class = "Witch2",
league = "Test",
level = 90,
jewels = {
{
id = "split-personality-test",
frameType = 3,
name = "Split Personality",
typeLine = "Ruby",
inventoryId = "PassiveJewels",
x = 4,
ilvl = 84,
properties = { },
explicitMods = {
"Can Allocate Passive Skills from the Ranger's starting point",
},
},
},
passives = {
hashes = hashes,
specialisations = { },
skill_overrides = { },
jewel_data = { },
quest_stats = { },
},
}

build.importTab:ImportPassiveTreeAndJewels(importPayload)

local importedSpec = build.spec
local importedJewel = build.itemsTab.items[importedSpec.jewels[socketNode.id]]
assert.are.equals("Ranger", importedJewel.jewelData.alternateClassStart)

assert.are.equals(0, importedSpec.nodes[rangerStart.id].pathDist)
assert.True(importedSpec.nodes[rangerStartPassive.id].alloc)
assert.True(importedSpec.nodes[rangerStartPassive.id].connectedToStart)
end)
end)

describe("ImportTab quest reward import", function()
Expand Down
3 changes: 3 additions & 0 deletions src/Classes/Item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,9 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
for _, value in ipairs(modList:List(nil, "JewelData")) do
jewelData[value.key] = value.value
end
for _, className in ipairs(modList:List(nil, "AlternateClassStart")) do
jewelData.alternateClassStart = className
end
if modList:List(nil, "FromNothingKeystones") then
jewelData.fromNothingKeystones = { }
for _, value in ipairs(modList:List(nil, "FromNothingKeystones")) do
Expand Down
27 changes: 22 additions & 5 deletions src/Classes/PassiveSpec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ end

-- Attempt to find a class start node starting from the given node
-- Unless noAscent == true it will also look for an ascendancy class start node
function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode)
function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode, alternateClassStartNodes)
allocMode = allocMode or node.allocMode or 0
-- Mark the current node as visited so we don't go around in circles
node.visited = true
Expand All @@ -1029,9 +1029,10 @@ function PassiveSpecClass:FindStartFromNode(node, visited, noAscend, allocMode)
-- - the other node is a start node, or
-- - there is a path to a start node through the other node which didn't pass through any nodes which have already been visited
local startIndex = #visited + 1
if other.alloc and self:CanPathThroughAllocMode(allocMode, other) and
local otherAlloc = other.alloc or (alternateClassStartNodes and alternateClassStartNodes[other.id])
if otherAlloc and self:CanPathThroughAllocMode(allocMode, other) and
(other.type == "ClassStart" or other.type == "AscendClassStart" or
(not other.visited and node.type ~= "Mastery" and self:FindStartFromNode(other, visited, noAscend, allocMode))
(not other.visited and node.type ~= "Mastery" and self:FindStartFromNode(other, visited, noAscend, allocMode, alternateClassStartNodes))
) then
if node.ascendancyName and not other.ascendancyName then
-- Pathing out of Ascendant, un-visit the outside nodes
Expand Down Expand Up @@ -1225,6 +1226,18 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
-- First check for mods that affect intuitive leap-like properties of other nodes
local processed = { }
local intuitiveLeapLikeNodes = self.intuitiveLeapLikeNodes
local alternateClassStartNodes = { }
for socketNodeId, itemId in pairs(self.jewels) do
if self.allocNodes[socketNodeId] then
local item = self:GetJewel(itemId)
local className = item and item.jewelData.alternateClassStart
local classData = className and self.tree.classes[self.tree.classNameMap[className]]
local startNode = classData and self.nodes[classData.startNodeId]
if startNode then
alternateClassStartNodes[startNode.id] = startNode
end
end
end
wipeTable(intuitiveLeapLikeNodes)
for id, node in pairs(self.allocNodes) do
if node.ascendancyName then -- avoid processing potentially replaceable nodes
Expand Down Expand Up @@ -1577,13 +1590,14 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
node.connectedToStart = false
local anyStartFound = (node.type == "ClassStart" or node.type == "AscendClassStart")
for _, other in ipairs(node.linked) do
if other.alloc and self:CanPathThroughAllocMode(node.allocMode or 0, other) and not isValueInArray(node.depends, other) then
local otherAlloc = other.alloc or alternateClassStartNodes[other.id]
if otherAlloc and self:CanPathThroughAllocMode(node.allocMode or 0, other) and not isValueInArray(node.depends, other) then
-- 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
if other.type == "ClassStart" or other.type == "AscendClassStart" then
-- Well that was easy!
anyStartFound = true
node.connectedToStart = true
elseif self:FindStartFromNode(other, visited, nil, node.allocMode or 0) then
elseif self:FindStartFromNode(other, visited, nil, node.allocMode or 0, alternateClassStartNodes) then
-- We found a path through the other node, therefore the other node cannot be dependent on this node
anyStartFound = true
node.connectedToStart = true
Expand Down Expand Up @@ -1795,6 +1809,9 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
end
end
end
for _, node in pairs(alternateClassStartNodes) do
self:BuildPathFromNode(node)
end
end

function PassiveSpecClass:ReplaceNode(old, newNode)
Expand Down
5 changes: 3 additions & 2 deletions src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -912,8 +912,9 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)

local socket, jewel = build.itemsTab:GetSocketAndJewelForNodeID(nodeId)
if isAlloc and jewel then
if jewel.rarity == "UNIQUE" and jewel.title ~= "Grand Spectrum" then
overlay = jewel.title
if jewel.rarity == "UNIQUE" then
local hasUniqueJewelArt = tree.ddsMap[jewel.title] or tree.assets[jewel.title] or tree.spriteMap[jewel.title]
overlay = hasUniqueJewelArt and jewel.title or jewel.baseName
else
overlay = jewel.baseName
end
Expand Down
6 changes: 2 additions & 4 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4701,10 +4701,8 @@ c["Buffs on you expire 10% slower"]={{[1]={[1]={skillType=5,type="SkillType"},fl
c["Bulwark"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Bulwark"}},nil}
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 "}
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}
c["Can Allocate Passive Skills from the Sorceress's starting point"]={nil,"Can Allocate Passive Skills from the Sorceress's starting point "}
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 "}
c["Can Allocate Passive Skills from the Warrior's starting point"]={nil,"Can Allocate Passive Skills from the Warrior's starting point "}
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 "}
c["Can Allocate Passive Skills from the Sorceress's starting point"]={{[1]={flags=0,keywordFlags=0,name="AlternateClassStart",type="LIST",value="Sorceress"}},nil}
c["Can Allocate Passive Skills from the Warrior's starting point"]={{[1]={flags=0,keywordFlags=0,name="AlternateClassStart",type="LIST",value="Warrior"}},nil}
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}
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 "}
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: "}
Expand Down
3 changes: 2 additions & 1 deletion src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2727,7 +2727,8 @@ local specialModList = {
["evasion rating from equipped body armour is halved"] = { mod("Evasion", "MORE", -50, { type = "SlotName", slotName = "Body Armour" }) },
-- Ascendant
["grants (%d+) passive skill points?"] = function(num) return { mod("ExtraPoints", "BASE", num) } end,
["can allocate passives from the %a+'s starting point"] = { },
["can allocate passives from the (%a+)'s starting point"] = function(_, className) return { mod("AlternateClassStart", "LIST", firstToUpper(className)) } end,
["can allocate passive skills from the (%a+)'s starting point"] = function(_, className) return { mod("AlternateClassStart", "LIST", firstToUpper(className)) } end,
["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,
["(%d+)%% chance to gain elusive on kill"] = {
flag("Condition:CanBeElusive"),
Expand Down
Loading