MediaWiki:ClassMasteryCalculator.js: Difference between revisions

From EQOA Sandstorm Wiki
Jump to navigationJump to search
No edit summary
No edit summary
Line 40: Line 40:


                     <label>Character Level</label>
                     <label>Character Level</label>
<input type="number" id="cm-level" min="1" max="60" value="60" style="width:70px;">
                    <input type="number" id="cm-level" min="1" max="60" value="60" style="width:70px;">
                 </div>
                 </div>


Line 52: Line 52:
                     </tr>
                     </tr>
                     <tr>
                     <tr>
                         <td id="cm-available">60</td>
                         <td id="cm-available">1500</td>
                         <td id="cm-spent">0</td>
                         <td id="cm-spent">0</td>
                         <td id="cm-remaining">60</td>
                         <td id="cm-remaining">1500</td>
                     </tr>
                     </tr>
                 </table>
                 </table>
Line 78: Line 78:
         function loadRaces() {
         function loadRaces() {
             raceSelect.innerHTML = '';
             raceSelect.innerHTML = '';


             Object.keys(data.raceClasses).forEach(function (race) {
             Object.keys(data.raceClasses).forEach(function (race) {
Line 105: Line 104:


         function getAvailablePoints() {
         function getAvailablePoints() {
    var level = parseInt(levelInput.value, 10);
            var level = parseInt(levelInput.value, 10);


    if (isNaN(level) || level < 1) level = 1;
            if (isNaN(level) || level < 1) level = 1;
    if (level > 60) level = 60;
            if (level > 60) level = 60;


    levelInput.value = level;
            levelInput.value = level;


    return level * 25;
            return level * 25;
}
        }


         function updateSummary() {
         function updateSummary() {
    var available = getAvailablePoints();
            var available = getAvailablePoints();
    var spent = 0;
            var spent = 0;
    var remaining = available - spent;
            var remaining = available - spent;
 
            document.getElementById('cm-available').textContent = available;
            document.getElementById('cm-spent').textContent = spent;
            document.getElementById('cm-remaining').textContent = remaining;
 
            renderMasteryList();
        }


    document.getElementById('cm-available').textContent = available;
    document.getElementById('cm-spent').textContent = spent;
    document.getElementById('cm-remaining').textContent = remaining;


    renderMasteryList();
        function renderMasteryList() {
}
            var masteryPanel = document.getElementById('cm-mastery-panel');
            if (!masteryPanel) return;


function renderMasteryList() {
            var selectedRace = raceSelect.value;
    var masteryPanel = document.getElementById('cm-mastery-panel');
            var selectedRaceCode = data.raceCodes[selectedRace];
    if (!masteryPanel) return;
            var selectedClass = classSelect.value;
            var level = parseInt(levelInput.value, 10) || 1;


    var selectedRace = raceSelect.value;
            var filtered = (data.masteries || []).filter(function (cm) {
    var selectedRaceCode = data.raceCodes[selectedRace];
                var raceOk =
    var selectedClass = classSelect.value;
                    !cm.races.length ||
    var level = parseInt(levelInput.value, 10) || 1;
                    cm.races.indexOf(selectedRaceCode) !== -1;


    var filtered = (data.masteries || []).filter(function (cm) {
                var classOk =
        var raceOk =
                    !cm.classes.length ||
            !cm.races.length ||
                    cm.classes.indexOf(selectedClass) !== -1;
            cm.races.indexOf(selectedRaceCode) !== -1;


        var classOk =
                var levelOk =
            !cm.classes.length ||
                    !cm.level ||
            cm.classes.indexOf(selectedClass) !== -1;
                    cm.level <= level;


        var levelOk =
                return raceOk && classOk && levelOk;
             !cm.level ||
             });
            cm.level <= level;


        return raceOk && classOk && levelOk;
            if (!filtered.length) {
    });
                masteryPanel.innerHTML = 'No Class Masteries found for this selection.';
                return;
            }


    if (!filtered.length) {
            var groups = {};
        masteryPanel.innerHTML = 'No Class Masteries found for this selection.';
        return;
    }


    var groups = {};
            filtered.forEach(function (cm) {
                var key = cm.classification || 'Other';


    filtered.forEach(function (cm) {
                if (!groups[key]) {
        var key = cm.classification || 'Other';
                    groups[key] = [];
                }


        if (!groups[key]) {
                groups[key].push(cm);
             groups[key] = [];
             });
        }


        groups[key].push(cm);
            var html = '';
    });


    var html = '';
            Object.keys(groups).forEach(function (groupName) {
                html += '<div class="cm-group-title">' + groupName + '</div>';


    Object.keys(groups).forEach(function (groupName) {
                groups[groupName].forEach(function (cm) {
        html += '<div class="cm-group-title">' + groupName + '</div>';
                    html +=
                        '<div class="cm-card">' +
                            '<div class="cm-card-title">' + cm.name + '</div>' +
                            '<div class="cm-card-desc">' + cm.description + '</div>' +
                            '<div class="cm-card-meta">' +
                                'Level: ' + cm.level +
                                ' | Cost: ' + cm.points +
                                (cm.cmSpentReq ? ' | CM Spent Req: ' + cm.cmSpentReq : '') +
                            '</div>' +
                        '</div>';
                });
            });


        groups[groupName].forEach(function (cm) {
             masteryPanel.innerHTML = html;
             html +=
         }
                '<div class="cm-card">' +
                    '<div class="cm-card-title">' + cm.name + '</div>' +
                    '<div class="cm-card-desc">' + cm.description + '</div>' +
                    '<div class="cm-card-meta">' +
                        'Level: ' + cm.level +
                        ' | Cost: ' + cm.points +
                        (cm.cmSpentReq ? ' | CM Spent Req: ' + cm.cmSpentReq : '') +
                    '</div>' +
                '</div>';
         });
    });


    masteryPanel.innerHTML = html;
}
         raceSelect.addEventListener('change', loadClasses);
         raceSelect.addEventListener('change', loadClasses);
         classSelect.addEventListener('change', updateSummary);
         classSelect.addEventListener('change', updateSummary);

Revision as of 18:08, 14 May 2026

mw.hook('wikipage.content').add(function () {

    function waitForCMData(attemptsLeft) {
        if (window.EQOA_CM_DATA) {
            initClassMasteryCalculator();
            return;
        }

        if (attemptsLeft <= 0) {
            var app = document.getElementById('cm-calculator-app');
            if (app) {
                app.innerHTML = '<div style="color:red;">EQOA_CM_DATA failed to load.</div>';
            }
            return;
        }

        setTimeout(function () {
            waitForCMData(attemptsLeft - 1);
        }, 100);
    }

    waitForCMData(30);

    function initClassMasteryCalculator() {
        var app = document.getElementById('cm-calculator-app');
        if (!app) return;

        var data = window.EQOA_CM_DATA;

        app.innerHTML = `
            <div class="cm-calculator-box">
                <div class="character-builder-title">Class Mastery Calculator</div>

                <div class="character-builder-controls">
                    <label>Race</label>
                    <select id="cm-race"></select>

                    <label>Class</label>
                    <select id="cm-class"></select>

                    <label>Character Level</label>
                    <input type="number" id="cm-level" min="1" max="60" value="60" style="width:70px;">
                </div>

                <div class="character-builder-section-title" style="margin-top:15px;">Point Summary</div>

                <table class="character-builder-stat-table">
                    <tr>
                        <th>Available</th>
                        <th>Spent</th>
                        <th>Remaining</th>
                    </tr>
                    <tr>
                        <td id="cm-available">1500</td>
                        <td id="cm-spent">0</td>
                        <td id="cm-remaining">1500</td>
                    </tr>
                </table>

                <div class="character-builder-section-title" style="margin-top:18px;">Class Masteries</div>
                <div id="cm-mastery-panel" class="character-builder-warning-box">
                    Select a race and class to begin.
                </div>
            </div>
        `;

        var raceSelect = document.getElementById('cm-race');
        var classSelect = document.getElementById('cm-class');
        var levelInput = document.getElementById('cm-level');

        function addOption(select, value, label) {
            var option = document.createElement('option');
            option.value = value;
            option.textContent = label;
            select.appendChild(option);
        }

        function loadRaces() {
            raceSelect.innerHTML = '';

            Object.keys(data.raceClasses).forEach(function (race) {
                addOption(raceSelect, race, race);
            });

            loadClasses();
        }

        function loadClasses() {
            classSelect.innerHTML = '';

            var race = raceSelect.value;
            var classList = data.raceClasses[race] || [];

            classList.forEach(function (classCode) {
                addOption(
                    classSelect,
                    classCode,
                    classCode + ' - ' + (data.classes[classCode] || classCode)
                );
            });

            updateSummary();
        }

        function getAvailablePoints() {
            var level = parseInt(levelInput.value, 10);

            if (isNaN(level) || level < 1) level = 1;
            if (level > 60) level = 60;

            levelInput.value = level;

            return level * 25;
        }

        function updateSummary() {
            var available = getAvailablePoints();
            var spent = 0;
            var remaining = available - spent;

            document.getElementById('cm-available').textContent = available;
            document.getElementById('cm-spent').textContent = spent;
            document.getElementById('cm-remaining').textContent = remaining;

            renderMasteryList();
        }


        function renderMasteryList() {
            var masteryPanel = document.getElementById('cm-mastery-panel');
            if (!masteryPanel) return;

            var selectedRace = raceSelect.value;
            var selectedRaceCode = data.raceCodes[selectedRace];
            var selectedClass = classSelect.value;
            var level = parseInt(levelInput.value, 10) || 1;

            var filtered = (data.masteries || []).filter(function (cm) {
                var raceOk =
                    !cm.races.length ||
                    cm.races.indexOf(selectedRaceCode) !== -1;

                var classOk =
                    !cm.classes.length ||
                    cm.classes.indexOf(selectedClass) !== -1;

                var levelOk =
                    !cm.level ||
                    cm.level <= level;

                return raceOk && classOk && levelOk;
            });

            if (!filtered.length) {
                masteryPanel.innerHTML = 'No Class Masteries found for this selection.';
                return;
            }

            var groups = {};

            filtered.forEach(function (cm) {
                var key = cm.classification || 'Other';

                if (!groups[key]) {
                    groups[key] = [];
                }

                groups[key].push(cm);
            });

            var html = '';

            Object.keys(groups).forEach(function (groupName) {
                html += '<div class="cm-group-title">' + groupName + '</div>';

                groups[groupName].forEach(function (cm) {
                    html +=
                        '<div class="cm-card">' +
                            '<div class="cm-card-title">' + cm.name + '</div>' +
                            '<div class="cm-card-desc">' + cm.description + '</div>' +
                            '<div class="cm-card-meta">' +
                                'Level: ' + cm.level +
                                ' | Cost: ' + cm.points +
                                (cm.cmSpentReq ? ' | CM Spent Req: ' + cm.cmSpentReq : '') +
                            '</div>' +
                        '</div>';
                });
            });

            masteryPanel.innerHTML = html;
        }

        raceSelect.addEventListener('change', loadClasses);
        classSelect.addEventListener('change', updateSummary);
        levelInput.addEventListener('input', updateSummary);

        loadRaces();
    }

});