Module:Sandbox/SkillTree

From Melvor Idle
Revision as of 11:22, 5 September 2024 by Toadmilk (talk | contribs) (def not chatgpt)

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

    -- Constants for layout
    local baseX = 500  -- Start X position (middle of the screen)
    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)

    -- Find the maximum level (depth) of the skill tree
    local maxLevel = 0
    for _, node in ipairs(skillNodes) do
        if node.level > maxLevel then
            maxLevel = node.level
        end
    end

    -- Calculate the number of nodes per level
    local nodesPerLevel = {}
    for _, node in ipairs(skillNodes) do
        local level = node.level
        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'] = '1000px', -- Adjust based on max width
        ['height'] = (maxLevel + 1) * verticalSpacing .. 'px',  -- Adjust height dynamically
        ['margin'] = 'auto'
    })

    -- SVG container for the node connections
    local svg = html:tag('svg'):attr('height', '100%'):attr('width', '100%')
        :attr('preserveAspectRatio', 'none')
        :attr('viewBox', '0 0 1000 ' .. (maxLevel + 1) * verticalSpacing)
    
    -- Keep track of node positions for connections
    local nodePositions = {}

    -- Render each node and calculate its position
    for _, node in ipairs(skillNodes) do
        local level = node.level
        local indexInLevel = nodesPerLevel[level]

        -- Calculate X and Y positions for this node
        local xPos = baseX + (indexInLevel - nodesPerLevel[level] / 2) * horizontalSpacing
        local yPos = baseY + level * verticalSpacing

        -- Store the node's position for later use in drawing connections
        nodePositions[node.name] = { x = xPos, y = yPos }

        -- Node container
        local nodeDiv = html:tag('div'):css({
            ['position'] = 'absolute',
            ['width'] = '200px',
            ['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()

        -- Display modifiers (if present)
        if node.modifiers then
            local modifierText = ""
            for modifier, data in pairs(node.modifiers) do
                if type(data) == "table" then
                    modifierText = modifierText .. modifier .. ": Skill: " .. (data.skillID or "N/A") .. ", Value: " .. (data.value or "N/A") .. "<br>"
                else
                    modifierText = modifierText .. modifier .. ": " .. tostring(data) .. "<br>"
                end
            end
            nodeDiv:tag('p'):wikitext(modifierText):done()
        end

        -- Display combat effects (if present)
        if node.combatEffects then
            local combatEffectText = ""
            for _, effect in pairs(node.combatEffects) do
                combatEffectText = combatEffectText .. "Effect ID: " .. (effect.effectID or "N/A") .. ", Chance: " .. (effect.chance or "N/A") .. "%<br>"
                if effect.condition then
                    combatEffectText = combatEffectText .. "Condition Type: " .. (effect.condition.type or "N/A") .. "<br>"
                end
            end
            nodeDiv:tag('p'):wikitext(combatEffectText):done()
        end

        -- 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 + 100, parentPos.y + 100, childPos.x + 100, 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