@@ -190,14 +190,30 @@ function PassiveSpecClass:Load(xml, dbFileName)
190190 for _ , child in ipairs (node ) do
191191 if child .elem == " AttributeOverride" then
192192 for strengthId in child .attrib .strNodes :gmatch (" %d+" ) do
193- self :SwitchAttributeNode (tonumber (strengthId ), 1 )
193+ local strengthNumberId = tonumber (strengthId )
194+ local atributeIndex = self :GetAttributeIndexForNodeId (strengthNumberId , " Strength" )
195+ self :SwitchAttributeNode (strengthNumberId , atributeIndex )
194196 end
195197 for dexterityId in child .attrib .dexNodes :gmatch (" %d+" ) do
196- self :SwitchAttributeNode (tonumber (dexterityId ), 2 )
198+ local dexterityNumberId = tonumber (dexterityId )
199+ local atributeIndex = self :GetAttributeIndexForNodeId (dexterityNumberId , " Dexterity" )
200+ self :SwitchAttributeNode (dexterityNumberId , atributeIndex )
197201 end
198202 for intelligenceId in child .attrib .intNodes :gmatch (" %d+" ) do
199- self :SwitchAttributeNode (tonumber (intelligenceId ), 3 )
203+ local intelligenceNumberId = tonumber (intelligenceId )
204+ local atributeIndex = self :GetAttributeIndexForNodeId (intelligenceNumberId , " Intelligence" )
205+ self :SwitchAttributeNode (intelligenceNumberId , atributeIndex )
200206 end
207+ -- check if have child elems for other attribute types
208+ for _ , other in ipairs (child ) do
209+ if other .elem == " other" then
210+ local otherId = tonumber (other .attrib .id )
211+ local dn = other .attrib .dn
212+ local atributeIndex = self :GetAttributeIndexForNodeId (otherId , dn )
213+ self :SwitchAttributeNode (otherId , atributeIndex )
214+ end
215+ end
216+
201217 else
202218 ConPrintf (" [PassiveSpecClass:Load] Unexpected element found in Overrides: " .. child .elem )
203219 end
@@ -281,7 +297,7 @@ function PassiveSpecClass:Save(xml)
281297 elem = " Overrides"
282298 }
283299 if self .hashOverrides then
284- local strList , dexList , intList = { }, { }, { }
300+ local strList , dexList , intList , others = { }, { }, { }, { }
285301 for nodeId , node in pairs (self .hashOverrides ) do
286302 if node .isAttribute then
287303 if node .dn == " Strength" then
@@ -290,10 +306,18 @@ function PassiveSpecClass:Save(xml)
290306 t_insert (dexList , nodeId )
291307 elseif node .dn == " Intelligence" then
292308 t_insert (intList , nodeId )
309+ else
310+ -- other attribute types not currently supported
311+ t_insert (others , { elem = " other" , attrib = {id = tostring (nodeId ), dn = tostring (node .dn )} })
293312 end
294313 end
295314 end
296315 local attributeOverride = { elem = " AttributeOverride" , attrib = { strNodes = table.concat (strList , " ," ), dexNodes = table.concat (dexList , " ," ), intNodes = table.concat (intList , " ," ) } }
316+ if # others > 0 then
317+ for _ , other in pairs (others ) do
318+ t_insert (attributeOverride , other )
319+ end
320+ end
297321 t_insert (overrides , attributeOverride )
298322 end
299323 t_insert (xml , overrides )
@@ -1221,7 +1245,16 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
12211245
12221246 -- set attribute nodes
12231247 if self .hashOverrides [node .id ] then
1224- self :ReplaceNode (node , self .hashOverrides [node .id ])
1248+ -- before building path we need to check for hashOverrides still valid
1249+ local overrideNode = self .hashOverrides [node .id ]
1250+ if self :IsUnlockedAttributeForNodeId (node .id , overrideNode .dn ) then
1251+ -- valid override
1252+ self :ReplaceNode (node , self .hashOverrides [node .id ])
1253+ else
1254+ -- invalid override, remove it
1255+ self .hashOverrides [node .id ] = nil
1256+ self :ReplaceNode (node , self .tree .nodes [node .id ])
1257+ end
12251258 end
12261259
12271260 -- If node is conquered, replace it or add mods
@@ -2352,14 +2385,126 @@ function PassiveSpecClass:NodeInKeystoneRadius(keystoneNames, nodeId, radiusInde
23522385end
23532386
23542387function PassiveSpecClass :SwitchAttributeNode (nodeId , attributeIndex )
2355- if self .tree .nodes [nodeId ] then -- Make sure node exists on current tree
2356- local newNode = copyTableSafe (self .tree .nodes [nodeId ], false , true )
2357- if not newNode .isAttribute then return end -- safety check
2358-
2359- local option = newNode .options [attributeIndex ]
2360- self :ReplaceNode (newNode , option )
2361- self .tree :ProcessStats (newNode )
2362-
2363- self .hashOverrides [nodeId ] = newNode
2388+ if not self .tree .nodes [nodeId ] then -- Make sure node exists on current tree
2389+ return
2390+ end
2391+
2392+ local newNode = copyTableSafe (self .tree .nodes [nodeId ], false , true )
2393+ if not newNode .isAttribute then return end -- safety check
2394+
2395+ -- check if attributeIndex is valid
2396+ if attributeIndex < 1 or attributeIndex > # newNode .options then
2397+ return
23642398 end
2399+
2400+ local option = newNode .options [attributeIndex ]
2401+
2402+ -- check if the option have "unlockedBy" and check in the spec if this is allocated
2403+ if option .unlockedBy then
2404+ local unlocked = false
2405+ for _ , unlockNodeId in ipairs (option .unlockedBy ) do
2406+ if self .allocNodes [unlockNodeId ] then
2407+ unlocked = true
2408+ break
2409+ end
2410+ end
2411+ if not unlocked then
2412+ return
2413+ end
2414+ end
2415+
2416+ self :ReplaceNode (newNode , option )
2417+ self .tree :ProcessStats (newNode )
2418+
2419+ self .hashOverrides [nodeId ] = newNode
23652420end
2421+
2422+ function PassiveSpecClass :GetAttributeIndexForNodeId (nodeId , attributeName )
2423+ local node = self .tree .nodes [nodeId ]
2424+ if not node then return 0 end -- Make sure node exists on current tree
2425+ if not node .isAttribute then return 0 end -- safety check
2426+ for index , option in ipairs (node .options ) do
2427+ if option .dn == attributeName then
2428+ return index
2429+ end
2430+ end
2431+ return 0
2432+ end
2433+
2434+ function PassiveSpecClass :GetUnlockedAttributeListForNodeId (nodeId )
2435+ local node = self .tree .nodes [nodeId ]
2436+ if not node then return {} end -- Make sure node exists on current tree
2437+ if not node .isAttribute then return {} end -- safety check
2438+ local attributeList = {}
2439+ for index , option in ipairs (node .options ) do
2440+ if option .unlockedBy then
2441+ local unlocked = false
2442+ for _ , unlockNodeId in ipairs (option .unlockedBy ) do
2443+ if self .allocNodes [unlockNodeId ] then
2444+ unlocked = true
2445+ break
2446+ end
2447+ end
2448+ if unlocked then
2449+ t_insert (attributeList , option .dn )
2450+ end
2451+ else
2452+ t_insert (attributeList , option .dn )
2453+ end
2454+ end
2455+ return attributeList
2456+ end
2457+
2458+ function PassiveSpecClass :IsUnlockedAttributeForNodeId (nodeId , attributeName )
2459+ local node = self .tree .nodes [nodeId ]
2460+ if not node then return false end -- Make sure node exists on current tree
2461+ if not node .isAttribute then return false end -- safety check
2462+
2463+ for index , option in ipairs (node .options ) do
2464+ if option .dn == attributeName then
2465+ -- check if the option have "unlockedBy" and check in the spec if
2466+ if option .unlockedBy then
2467+ local unlocked = false
2468+ for _ , unlockNodeId in ipairs (option .unlockedBy ) do
2469+ if self .allocNodes [unlockNodeId ] then
2470+ unlocked = true
2471+ break
2472+ end
2473+ end
2474+ return unlocked
2475+ end
2476+ return true
2477+ end
2478+ end
2479+ return false
2480+ end
2481+
2482+ function PassiveSpecClass :GetNextAttributeIndexForNodeId (nodeId , currentAttributeName )
2483+ local node = self .tree .nodes [nodeId ]
2484+ if not node then return 1 end -- Make sure node exists on current tree
2485+ if not node .isAttribute then return 1 end -- safety check
2486+ local foundCurrent = false
2487+ for index , option in ipairs (node .options ) do
2488+ if foundCurrent then
2489+ -- check if the option have "unlockedBy" and check in the spec if this is allocated
2490+ if option .unlockedBy then
2491+ local unlocked = false
2492+ for _ , unlockNodeId in ipairs (option .unlockedBy ) do
2493+ if self .allocNodes [unlockNodeId ] then
2494+ unlocked = true
2495+ break
2496+ end
2497+ end
2498+ if unlocked then
2499+ return index
2500+ end
2501+ else
2502+ return index
2503+ end
2504+ end
2505+ if option .dn == currentAttributeName then
2506+ foundCurrent = true
2507+ end
2508+ end
2509+ return 1
2510+ end
0 commit comments