Module:Sandbox/SkillTree: Difference between revisions

From Melvor Idle
No edit summary
No edit summary
 
(34 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local p = {}


local Constants = require('Module:Constants')
local Num = require('Module:Number')
local Shared = require('Module:Shared')
local Common = require('Module:Common')
local GameData = require('Module:GameData')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local Skills = require('Module:Skills')
local Items = require('Module:Items')
local Icons = require('Module:Icons')


local function deepPrint(tbl, indent)
function p.getSkillTreeNodes(checkFunc)
     if not indent then indent = 0 end
     local nodes = {}
     for k, v in pairs(tbl) do
   
         local formatting = string.rep("  ", indent) .. k .. ": "
     for skillName, skillData in pairs(GameData.skillData) do
         if type(v) == "table" then
         local skillTrees = skillData.skillTrees
             mw.log(formatting)
         if skillTrees then
            deepPrint(v, indent + 1)
             for _, skillTree in ipairs(skillTrees) do
        else
                for _, node in ipairs(GameData.getEntities(skillTree.nodes, checkFunc)) do
            mw.log(formatting .. tostring(v))
                    local nodeCopy = {}
                    for k, v in pairs(node) do
                        nodeCopy[k] = v
                    end
 
                    nodeCopy.skillName = skillName
 
                    table.insert(nodes, nodeCopy)
                end
            end
         end
         end
     end
     end
    return nodes
end
end


function p.printAllSkillTrees()
function p.getSkillTreeNodesFromSkillName(skillName)
     -- Iterate through all skills in GameData.skillData
mw.log(GameData.skillData)
     for skillName, skillData in pairs(GameData.skillData) do
         local skillTrees = skillData.skillTrees
     local skillData = GameData.skillData[skillName]
    if not skillData then return nil end
 
    local nodes = {}
     for _, node in ipairs(skillData.skillTrees[1].nodes) do
         table.insert(nodes, node)
    end
    return nodes
end
 
function p.generateSkillTree(frame)
    local args = frame.args ~= nil and frame.args or frame
    local skillName = args[1]
 
    if not skillName then
        return "Invalid skillName"
    end


        if skillTrees then
    local skillNodes = p.getSkillTreeNodesFromSkillName(skillName)
            mw.log("Skill Trees for " .. skillName .. ":")
            for _, skillTree in ipairs(skillTrees) do
                mw.log("------------------------------")
                mw.log("Skill Tree ID: " .. skillTree.id)
                mw.log("Skill Tree Name: " .. skillTree.name)
                mw.log("Points Available: " .. (skillTree.points or "N/A"))
                mw.log("Number of Nodes: " .. #skillTree.nodes)


                -- Print information for each node in the skill tree
    if not skillNodes or #skillNodes == 0 then
                for _, node in ipairs(skillTree.nodes) do
        return "No skill tree found for: " .. skillName
                    mw.log("  Node ID: " .. node.id)
    end
                    mw.log("  Node Name: " .. node.name)
                    mw.log("  Costs: " .. (node.costs.points or 0) .. " points")
                    mw.log("  Unlocked: " .. tostring(node.isUnlocked))


                    -- Print the node's modifiers
    -- Helper function to calculate the level of each node
                    if node.modifiers then
    local function calculateNodeLevels(nodes)
                        mw.log("  Modifiers:")
        local levels = {}
                        deepPrint(node.modifiers, 2)
        local function findLevel(node, currentLevel)
                    end
            if not levels[node.name] then
                levels[node.name] = currentLevel
            else
                levels[node.name] = math.max(levels[node.name], currentLevel)
            end


                    -- Print the node's parents (if any)
            -- Recursively set level for child nodes
                    if node.parents then
            if node.children then
                        mw.log("  Parents:")
                for _, child in ipairs(node.children) do
                        for _, parentID in ipairs(node.parents) do
                    findLevel(child, currentLevel + 1)
                            mw.log("    Parent Node ID: " .. parentID)
                        end
                    end
                 end
                 end
             end
             end
        else
            mw.log("No skill trees found for " .. skillName .. ".")
         end
         end
        -- Start with nodes that have no parents (root nodes)
        for _, node in ipairs(nodes) do
            if not node.parents or #node.parents == 0 then
                findLevel(node, 0) -- Root nodes start at level 0
            end
        end
        return levels
    end
    -- Calculate levels for each node
    local nodeLevels = calculateNodeLevels(skillNodes)
    -- Calculate maxLevel based on the calculated levels
    local maxLevel = 0
    for _, level in pairs(nodeLevels) do
        if level > maxLevel then
            maxLevel = level
        end
    end
    -- Constants for layout
    local containerWidth = 1000  -- Adjust container width as needed
    local baseY = 50  -- Start Y position (top of the screen)
    local verticalSpacing = 200  -- Distance between levels (Y-axis)
    local horizontalSpacing = 300  -- Distance between nodes at the same level (X-axis)
    -- Count nodes per level for horizontal positioning
    local nodesPerLevel = {}
    for nodeName, level in pairs(nodeLevels) do
        if not nodesPerLevel[level] then
            nodesPerLevel[level] = 0
        end
        nodesPerLevel[level] = nodesPerLevel[level] + 1
    end
    -- Container for the skill tree
    local html = mw.html.create('div'):addClass('skill-tree-container'):css({
        ['position'] = 'relative',
        ['width'] = containerWidth .. 'px',
        ['height'] = (maxLevel + 1) * verticalSpacing .. 'px',  -- Adjust height dynamically
        ['margin'] = 'auto',
        ['border'] = '1px solid red' -- Debug border for the entire tree
    })
    -- SVG container for the node connections
    local svg = html:tag('svg'):attr('height', '100%'):attr('width', '100%')
        :attr('preserveAspectRatio', 'none')
        :attr('viewBox', '0 0 ' .. containerWidth .. ' ' .. (maxLevel + 1) * verticalSpacing)
    -- Track positions for each node
    local nodePositions = {}
    -- Keep track of how many nodes we've placed on each level
    local nodeIndexPerLevel = {}
    -- Position each node dynamically
    for i, node in ipairs(skillNodes) do
        local level = nodeLevels[node.name]
        nodeIndexPerLevel[level] = (nodeIndexPerLevel[level] or 0) + 1
        local indexInLevel = nodeIndexPerLevel[level]
        -- Center the nodes in each level
        local baseX = (containerWidth / 2) - ((nodesPerLevel[level] - 1) / 2) * horizontalSpacing
        -- Calculate X and Y positions for this node
        local xPos = baseX + (indexInLevel - 1) * horizontalSpacing
        local yPos = baseY + level * verticalSpacing
        -- Store node position for connections
        nodePositions[node.name] = { x = xPos, y = yPos }
        -- Node container
        local nodeDiv = html:tag('div'):css({
            ['position'] = 'absolute',
            ['width'] = '150px',
            ['height'] = '100px',
            ['top'] = yPos .. 'px',
            ['left'] = xPos .. 'px',
            ['background-color'] = '#f5f5f5',
            ['border'] = '2px solid black',
            ['text-align'] = 'center'
        })
        -- Node title (e.g., skill name)
        nodeDiv:tag('span'):wikitext(node.name):css({
            ['font-size'] = '14px',
            ['font-weight'] = '700',
        }):done()
        -- Append nodeDiv to HTML
        html:done()
     end
     end
end


function p.getSkillTreeNodes(checkFunc)
     -- Draw connections between nodes
     local nodes = {}
     for _, node in ipairs(skillNodes) do
   
         if node.parents then
     for _, skillData in pairs(GameData.skillData) do
             for _, parent in ipairs(node.parents) do
         local skillTrees = skillData.skillTrees
                 local parentPos = nodePositions[parent.name]
        if skillTrees then
                local childPos = nodePositions[node.name]
             for _, skillTree in ipairs(skillTrees) do
                if parentPos and childPos then
                 for _, node in ipairs(GameData.getEntities(skillTree.nodes, checkFunc)) do
                    local path = string.format("M%d,%d L%d,%d", parentPos.x + 75, parentPos.y + 100, childPos.x + 75, childPos.y)
                nodeWithSkill = {
                    svg:tag('path')
                    skillName = "balls",
                        :attr('d', path)
                    nodeData = node
                        :css({
                }
                            ['stroke'] = 'yellow',  -- Connection color (could be dynamic)
                table.insert(nodes, node)
                            ['stroke-width'] = '3',
                            ['fill'] = 'none'
                        })
                        :done()
                 end
                 end
             end
             end
         end
         end
     end
     end
     return nodes
 
    -- Close the SVG tag
    svg:done()
 
     return tostring(html)
end
end


return p
return p

Latest revision as of 12:49, 5 September 2024

Documentation for this module may be created at Module:Sandbox/SkillTree/doc

local p = {}

local GameData = require('Module:GameData')

function p.getSkillTreeNodes(checkFunc)
    local nodes = {}
    
    for skillName, skillData in pairs(GameData.skillData) do
        local skillTrees = skillData.skillTrees
        if skillTrees then
            for _, skillTree in ipairs(skillTrees) do
                for _, node in ipairs(GameData.getEntities(skillTree.nodes, checkFunc)) do
                    local nodeCopy = {}
                    for k, v in pairs(node) do
                        nodeCopy[k] = v
                    end

                    nodeCopy.skillName = skillName

                    table.insert(nodes, nodeCopy)
                end
            end
        end
    end
    return nodes
end

function p.getSkillTreeNodesFromSkillName(skillName)
	mw.log(GameData.skillData)
	
    local skillData = GameData.skillData[skillName]
    if not skillData then return nil end

    local nodes = {}
    for _, node in ipairs(skillData.skillTrees[1].nodes) do
        table.insert(nodes, node)
    end
    return nodes
end

function p.generateSkillTree(frame)
    local args = frame.args ~= nil and frame.args or frame
    local skillName = args[1]

    if not skillName then
        return "Invalid skillName"
    end

    local skillNodes = p.getSkillTreeNodesFromSkillName(skillName)

    if not skillNodes or #skillNodes == 0 then
        return "No skill tree found for: " .. skillName
    end

    -- Helper function to calculate the level of each node
    local function calculateNodeLevels(nodes)
        local levels = {}
        local function findLevel(node, currentLevel)
            if not levels[node.name] then
                levels[node.name] = currentLevel
            else
                levels[node.name] = math.max(levels[node.name], currentLevel)
            end

            -- Recursively set level for child nodes
            if node.children then
                for _, child in ipairs(node.children) do
                    findLevel(child, currentLevel + 1)
                end
            end
        end

        -- Start with nodes that have no parents (root nodes)
        for _, node in ipairs(nodes) do
            if not node.parents or #node.parents == 0 then
                findLevel(node, 0) -- Root nodes start at level 0
            end
        end

        return levels
    end

    -- Calculate levels for each node
    local nodeLevels = calculateNodeLevels(skillNodes)

    -- Calculate maxLevel based on the calculated levels
    local maxLevel = 0
    for _, level in pairs(nodeLevels) do
        if level > maxLevel then
            maxLevel = level
        end
    end

    -- Constants for layout
    local containerWidth = 1000  -- Adjust container width as needed
    local baseY = 50   -- Start Y position (top of the screen)
    local verticalSpacing = 200  -- Distance between levels (Y-axis)
    local horizontalSpacing = 300  -- Distance between nodes at the same level (X-axis)

    -- Count nodes per level for horizontal positioning
    local nodesPerLevel = {}
    for nodeName, level in pairs(nodeLevels) do
        if not nodesPerLevel[level] then
            nodesPerLevel[level] = 0
        end
        nodesPerLevel[level] = nodesPerLevel[level] + 1
    end

    -- Container for the skill tree
    local html = mw.html.create('div'):addClass('skill-tree-container'):css({
        ['position'] = 'relative',
        ['width'] = containerWidth .. 'px',
        ['height'] = (maxLevel + 1) * verticalSpacing .. 'px',  -- Adjust height dynamically
        ['margin'] = 'auto',
        ['border'] = '1px solid red' -- Debug border for the entire tree
    })

    -- SVG container for the node connections
    local svg = html:tag('svg'):attr('height', '100%'):attr('width', '100%')
        :attr('preserveAspectRatio', 'none')
        :attr('viewBox', '0 0 ' .. containerWidth .. ' ' .. (maxLevel + 1) * verticalSpacing)

    -- Track positions for each node
    local nodePositions = {}

    -- Keep track of how many nodes we've placed on each level
    local nodeIndexPerLevel = {}

    -- Position each node dynamically
    for i, node in ipairs(skillNodes) do
        local level = nodeLevels[node.name]
        nodeIndexPerLevel[level] = (nodeIndexPerLevel[level] or 0) + 1
        local indexInLevel = nodeIndexPerLevel[level]

        -- Center the nodes in each level
        local baseX = (containerWidth / 2) - ((nodesPerLevel[level] - 1) / 2) * horizontalSpacing

        -- Calculate X and Y positions for this node
        local xPos = baseX + (indexInLevel - 1) * horizontalSpacing
        local yPos = baseY + level * verticalSpacing

        -- Store node position for connections
        nodePositions[node.name] = { x = xPos, y = yPos }

        -- Node container
        local nodeDiv = html:tag('div'):css({
            ['position'] = 'absolute',
            ['width'] = '150px',
            ['height'] = '100px',
            ['top'] = yPos .. 'px',
            ['left'] = xPos .. 'px',
            ['background-color'] = '#f5f5f5',
            ['border'] = '2px solid black',
            ['text-align'] = 'center'
        })

        -- Node title (e.g., skill name)
        nodeDiv:tag('span'):wikitext(node.name):css({
            ['font-size'] = '14px',
            ['font-weight'] = '700',
        }):done()

        -- Append nodeDiv to HTML
        html:done()
    end

    -- Draw connections between nodes
    for _, node in ipairs(skillNodes) do
        if node.parents then
            for _, parent in ipairs(node.parents) do
                local parentPos = nodePositions[parent.name]
                local childPos = nodePositions[node.name]
                if parentPos and childPos then
                    local path = string.format("M%d,%d L%d,%d", parentPos.x + 75, parentPos.y + 100, childPos.x + 75, childPos.y)
                    svg:tag('path')
                        :attr('d', path)
                        :css({
                            ['stroke'] = 'yellow',  -- Connection color (could be dynamic)
                            ['stroke-width'] = '3',
                            ['fill'] = 'none'
                        })
                        :done()
                end
            end
        end
    end

    -- Close the SVG tag
    svg:done()

    return tostring(html)
end

return p