MediaWiki:Common.js: различия между версиями

Страница интерфейса MediaWiki
Нет описания правки
Нет описания правки
 
Строка 19: Строка 19:
      
      
     // Подключаем Tippy.js через CDN динамически
     // Подключаем Tippy.js через CDN динамически
if (!window.tippy) {
    if (!window.tippy) {
    var tippyScript = document.createElement('script');
        var tippyScript = document.createElement('script');
    tippyScript.src = "https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js";
        tippyScript.src = "https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js";
    tippyScript.onload = function() {
        tippyScript.onload = function() {
        var tippyCoreScript = document.createElement('script');
            var tippyCoreScript = document.createElement('script');
        tippyCoreScript.src = "https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.min.js";
            tippyCoreScript.src = "https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.min.js";
        tippyCoreScript.onload = initTippy;
            tippyCoreScript.onload = initTippy;
        document.head.appendChild(tippyCoreScript);
            document.head.appendChild(tippyCoreScript);
    };
        };
    document.head.appendChild(tippyScript);
        document.head.appendChild(tippyScript);


    // Подключаем CSS
        // Подключаем CSS
    var tippyCSS = document.createElement('link');
        var tippyCSS = document.createElement('link');
    tippyCSS.rel = "stylesheet";
        tippyCSS.rel = "stylesheet";
    tippyCSS.href = "https://unpkg.com/tippy.js@6/dist/tippy.css";
        tippyCSS.href = "https://unpkg.com/tippy.js@6/dist/tippy.css";
    document.head.appendChild(tippyCSS);
        document.head.appendChild(tippyCSS);
} else {
    } else {
    initTippy();
        initTippy();
}
    }


// Инициализация Tippy после загрузки скриптов
    // Инициализация Tippy после загрузки скриптов
function initTippy() {
    function initTippy() {
    $('.допуск-контейнер').each(function() {
        $('.допуск-контейнер').each(function() {
        var content = $(this).find('.допуск-подсказка').html(); // берем содержимое подсказки
            var content = $(this).find('.допуск-подсказка').html(); // берем содержимое подсказки
        tippy(this, {
            tippy(this, {
            content: content,
                content: content,
            allowHTML: true,
                allowHTML: true,
            interactive: true,
                interactive: true,
            placement: 'auto',      // автоматический выбор позиции
                placement: 'auto',      // автоматический выбор позиции
            maxWidth: '500px',
                maxWidth: '500px',
            minHeight: 'auto',
                minHeight: 'auto',
            theme: 'dark',          // темная тема
                theme: 'dark',          // темная тема
            arrow: true,          // без стрелки
                arrow: true,          // без стрелки
            duration: [200, 200],  // плавное появление/исчезание
                duration: [200, 200],  // плавное появление/исчезание
            popperOptions: {
                popperOptions: {
                modifiers: [
                    modifiers: [
                    {
                        {
                        name: 'preventOverflow',
                            name: 'preventOverflow',
                        options: {
                            options: {
                            padding: 8, // отступ от краев экрана
                                padding: 8 // отступ от краев экрана
                            }
                         },
                         },
                    },
                        {
                    {
                            name: 'flip',
                        name: 'flip',
                            options: {
                        options: {
                                fallbackPlacements: ['top', 'bottom', 'right', 'left']
                            fallbackPlacements: ['top', 'bottom', 'right', 'left'],
                            }
                         },
                         }
                     },
                     ]
                 ],
                 }
             },
             });
         });
         });
     });
     }
}


const laws = {
    // Данные о законах SS14
    '100': { name: 'Оскорбительное поведение', category: 1, minTime: 5, maxTime: 10 },
    window.ss14Laws = {
    '101': { name: 'Лёгкий ущерб здоровью', category: 1, minTime: 5, maxTime: 10 },
        '100': { name: 'Оскорбительное поведение', category: 1, minTime: 5, maxTime: 10 },
    '102': { name: 'Порча имущества', category: 1, minTime: 5, maxTime: 10 },
        '101': { name: 'Лёгкий ущерб здоровью', category: 1, minTime: 5, maxTime: 10 },
    '103': { name: 'Мелкая кража', category: 1, minTime: 5, maxTime: 10 },
        '102': { name: 'Порча имущества', category: 1, minTime: 5, maxTime: 10 },
    '104': { name: 'Владение регулируемыми веществами', category: 1, minTime: 5, maxTime: 10 },
        '103': { name: 'Мелкая кража', category: 1, minTime: 5, maxTime: 10 },
    '105': { name: 'Злоупотребление экипировкой', category: 1, minTime: 5, maxTime: 10 },
        '104': { name: 'Владение регулируемыми веществами', category: 1, minTime: 5, maxTime: 10 },
    '106': { name: 'Помеха работе сотрудников', category: 1, minTime: 5, maxTime: 10 },
        '105': { name: 'Злоупотребление экипировкой', category: 1, minTime: 5, maxTime: 10 },
    '107': { name: 'Проникновение', category: 1, minTime: 5, maxTime: 10 },
        '106': { name: 'Помеха работе сотрудников', category: 1, minTime: 5, maxTime: 10 },
    '108': { name: 'Жестокое обращение с животными', category: 1, minTime: 5, maxTime: 10 },
        '107': { name: 'Проникновение', category: 1, minTime: 5, maxTime: 10 },
    '109': { name: 'Клевета', category: 1, minTime: 5, maxTime: 10 },
        '108': { name: 'Жестокое обращение с животными', category: 1, minTime: 5, maxTime: 10 },
   
        '109': { name: 'Клевета', category: 1, minTime: 5, maxTime: 10 },
    '200': { name: 'Оскорбление власти', category: 2, minTime: 10, maxTime: 15 },
       
    '201': { name: 'Средний ущерб здоровью', category: 2, minTime: 10, maxTime: 15 },
        '200': { name: 'Оскорбление власти', category: 2, minTime: 10, maxTime: 15 },
    '202': { name: 'Вандализм', category: 2, minTime: 10, maxTime: 15 },
        '201': { name: 'Средний ущерб здоровью', category: 2, minTime: 10, maxTime: 15 },
    '204': { name: 'Распространение регулируемых веществ', category: 2, minTime: 10, maxTime: 15 },
        '202': { name: 'Вандализм', category: 2, minTime: 10, maxTime: 15 },
    '205': { name: 'Владение боевым приспособлением', category: 2, minTime: 10, maxTime: 15 },
        '204': { name: 'Распространение регулируемых веществ', category: 2, minTime: 10, maxTime: 15 },
    '206': { name: 'Помеха правосудию', category: 2, minTime: 10, maxTime: 15 },
        '205': { name: 'Владение боевым приспособлением', category: 2, minTime: 10, maxTime: 15 },
    '207': { name: 'Проникновение со взломом', category: 2, minTime: 10, maxTime: 15 },
        '206': { name: 'Помеха правосудию', category: 2, minTime: 10, maxTime: 15 },
    '208': { name: 'Убийство животного', category: 2, minTime: 10, maxTime: 15 },
        '207': { name: 'Проникновение со взломом', category: 2, minTime: 10, maxTime: 15 },
    '209': { name: 'Халатность', category: 2, minTime: 10, maxTime: 15 },
        '208': { name: 'Убийство животного', category: 2, minTime: 10, maxTime: 15 },
    '210': { name: 'Ограничение свободы', category: 2, minTime: 10, maxTime: 15 },
        '209': { name: 'Халатность', category: 2, minTime: 10, maxTime: 15 },
    '211': { name: 'Шпионаж', category: 2, minTime: 10, maxTime: 15 },
        '210': { name: 'Ограничение свободы', category: 2, minTime: 10, maxTime: 15 },
   
        '211': { name: 'Шпионаж', category: 2, minTime: 10, maxTime: 15 },
    '300': { name: 'Забастовка', category: 3, minTime: 15, maxTime: 20, dismissal: true },
       
    '301': { name: 'Тяжкий ущерб здоровью', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '300': { name: 'Забастовка', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '302': { name: 'Саботаж', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '301': { name: 'Тяжкий ущерб здоровью', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '303': { name: 'Кража', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '302': { name: 'Саботаж', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '304': { name: 'Оборот контрабанды', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '303': { name: 'Кража', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '305': { name: 'Владение нелетальным оружием', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '304': { name: 'Оборот контрабанды', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '306': { name: 'Мошенничество', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '305': { name: 'Владение нелетальным оружием', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '307': { name: 'Проникновение в стратегическую точку', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '306': { name: 'Мошенничество', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '308': { name: 'Распространение опасной флоры и фауны', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '307': { name: 'Проникновение в стратегическую точку', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '309': { name: 'Серьёзная халатность', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '308': { name: 'Распространение опасной флоры и фауны', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '310': { name: 'Похищение', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '309': { name: 'Серьёзная халатность', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '311': { name: 'Проникновение в защищённый канал', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '310': { name: 'Похищение', category: 3, minTime: 15, maxTime: 20, dismissal: true },
   
        '311': { name: 'Проникновение в защищённый канал', category: 3, minTime: 15, maxTime: 20, dismissal: true },
    '400': { name: 'Бунт', category: 4, minTime: 20, maxTime: 25, dismissal: true },
       
    '401': { name: 'Убийство', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '400': { name: 'Бунт', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '403': { name: 'Крупная кража', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '401': { name: 'Убийство', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '404': { name: 'Производство регулируемых веществ', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '403': { name: 'Крупная кража', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '405': { name: 'Владение летальным оружием', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '404': { name: 'Производство регулируемых веществ', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '406': { name: 'Растрата активов корпорации', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '405': { name: 'Владение летальным оружием', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '408': { name: 'Убийство особого животного', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '406': { name: 'Растрата активов корпорации', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '409': { name: 'Грубая халатность', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '408': { name: 'Убийство особого животного', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '410': { name: 'Похищение должностного лица', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '409': { name: 'Грубая халатность', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '411': { name: 'Антикорпоративный шпионаж', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '410': { name: 'Похищение должностного лица', category: 4, minTime: 20, maxTime: 25, dismissal: true },
   
        '411': { name: 'Антикорпоративный шпионаж', category: 4, minTime: 20, maxTime: 25, dismissal: true },
    '500': { name: 'Мятеж', category: 5, dClass: true, dismissal: true },
       
    '501': { name: 'Уничтожение тела', category: 5, dClass: true, dismissal: true },
        '500': { name: 'Мятеж', category: 5, dClass: true, dismissal: true },
    '502': { name: 'Крупный саботаж', category: 5, dClass: true, dismissal: true },
        '501': { name: 'Уничтожение тела', category: 5, dClass: true, dismissal: true },
    '503': { name: 'Особая кража', category: 5, dClass: true, dismissal: true },
        '502': { name: 'Крупный саботаж', category: 5, dClass: true, dismissal: true },
    '504': { name: 'Владение вражеским снаряжением', category: 5, dClass: true, dismissal: true },
        '503': { name: 'Особая кража', category: 5, dClass: true, dismissal: true },
    '505': { name: 'Распространение оружия', category: 5, dClass: true, dismissal: true },
        '504': { name: 'Владение вражеским снаряжением', category: 5, dClass: true, dismissal: true },
    '507': { name: 'Проникновение в защищённую стратегическую точку', category: 5, dClass: true, dismissal: true },
        '505': { name: 'Распространение оружия', category: 5, dClass: true, dismissal: true },
    '510': { name: 'Похищение высокопоставленных лиц', category: 5, dClass: true, dismissal: true },
        '507': { name: 'Проникновение в защищённую стратегическую точку', category: 5, dClass: true, dismissal: true },
    '511': { name: 'Разглашение секретной информации', category: 5, dClass: true, dismissal: true }
        '510': { name: 'Похищение высокопоставленных лиц', category: 5, dClass: true, dismissal: true },
};
        '511': { name: 'Разглашение секретной информации', category: 5, dClass: true, dismissal: true }
    };


let currentLawCode = null;
    // Глобальные функции для SS14 калькулятора
    window.ss14CurrentLawCode = null;


function toggleCalculator(lawCode) {
    window.toggleCalculator = function(lawCode) {
    const calculator = document.getElementById('ss14-calculator');
        var calculator = document.getElementById('ss14-calculator');
    currentLawCode = lawCode;
        window.ss14CurrentLawCode = lawCode;
   
       
    if (calculator.style.display === 'none' || !calculator.classList.contains('active')) {
        if (!calculator) return;
        calculator.classList.add('active');
        generateLawCheckboxes();
          
          
         // Автоматически выбираем нажатый закон
         if (calculator.style.display === 'none' || !calculator.classList.contains('active')) {
        const checkbox = document.getElementById('law-' + lawCode);
            calculator.classList.add('active');
        if (checkbox) {
            generateLawCheckboxes();
            checkbox.checked = true;
           
            // Автоматически выбираем нажатый закон
            var checkbox = document.getElementById('law-' + lawCode);
            if (checkbox) {
                checkbox.checked = true;
            }
           
            calculateSentence();
        } else {
            calculator.classList.remove('active');
         }
         }
    };
    window.generateLawCheckboxes = function() {
        var container = document.getElementById('law-checkboxes');
        if (!container) return;
          
          
         calculateSentence();
         container.innerHTML = '';
    } else {
       
        calculator.classList.remove('active');
        // Группируем законы по категориям
    }
        var categories = {
}
            1: { name: 'Лёгкие нарушения (1XX)', color: '#0F4F27' },
            2: { name: 'Средние нарушения (2XX)', color: '#414700' },
            3: { name: 'Тяжкие нарушения (3XX)', color: '#611300' },
            4: { name: 'Особо тяжкие нарушения (4XX)', color: '#57000C' },
            5: { name: 'Критические нарушения (5XX)', color: '#121212' }
        };
       
        for (var cat = 1; cat <= 5; cat++) {
            var categoryDiv = document.createElement('div');
            categoryDiv.style.marginBottom = '15px';
            categoryDiv.innerHTML = '<h5 style="color: ' + categories[cat].color + '; margin-bottom: 8px;">' + categories[cat].name + '</h5>';
           
            var lawsInCategory = Object.keys(window.ss14Laws).filter(function(code) {
                return window.ss14Laws[code].category === cat;
            });
           
            lawsInCategory.forEach(function(code) {
                var law = window.ss14Laws[code];
                var label = document.createElement('label');
                label.className = 'law-checkbox';
                label.innerHTML = '<input type="checkbox" id="law-' + code + '" onchange="calculateSentence()"> ' + code + ' - ' + law.name;
                categoryDiv.appendChild(label);
            });
           
            container.appendChild(categoryDiv);
        }
    };


function generateLawCheckboxes() {
    window.calculateSentence = function() {
    const container = document.getElementById('law-checkboxes');
        var selectedLaws = [];
    container.innerHTML = '';
        var checkboxes = document.querySelectorAll('[id^="law-"]:checked');
   
       
    // Группируем законы по категориям
        checkboxes.forEach(function(checkbox) {
    const categories = {
            var lawCode = checkbox.id.replace('law-', '');
        1: { name: 'Лёгкие нарушения (1XX)', color: '#0F4F27' },
            selectedLaws.push(lawCode);
         2: { name: 'Средние нарушения (2XX)', color: '#414700' },
        });
         3: { name: 'Тяжкие нарушения (3XX)', color: '#611300' },
       
         4: { name: 'Особо тяжкие нарушения (4XX)', color: '#57000C' },
        if (selectedLaws.length === 0) {
         5: { name: 'Критические нарушения (5XX)', color: '#121212' }
            var resultDiv = document.getElementById('calculation-result');
            if (resultDiv) {
                resultDiv.style.display = 'none';
            }
            return;
        }
          
        var modifierSelect = document.getElementById('modifier-select');
        var repeatOffense = document.getElementById('repeat-offense');
        var cooperation = document.getElementById('cooperation');
        var dClass = document.getElementById('d-class');
       
         var modifier = modifierSelect ? modifierSelect.value : 'none';
        var isRepeat = repeatOffense ? repeatOffense.checked : false;
         var hasCooperation = cooperation ? cooperation.checked : false;
        var isDClass = dClass ? dClass.checked : false;
       
        var result = calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass);
         displayResult(result, selectedLaws);
     };
     };
   
 
     for (let cat = 1; cat <= 5; cat++) {
     function calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass) {
         const categoryDiv = document.createElement('div');
         var totalTime = 0;
         categoryDiv.style.marginBottom = '15px';
         var punishmentType = 'Заключение под стражу';
         categoryDiv.innerHTML = `<h5 style="color: ${categories[cat].color}; margin-bottom: 8px;">${categories[cat].name}</h5>`;
         var hasDismissal = false;
        var hasDClass = false;
        var categoryGroups = {};
          
          
         const lawsInCategory = Object.entries(laws).filter(([code, law]) => law.category === cat);
         // Группируем по категориям (одинаковые категории не складываются)
        selectedLaws.forEach(function(lawCode) {
            var law = window.ss14Laws[lawCode];
            var categoryCode = lawCode.substring(1); // получаем последние 2 цифры (тип нарушения)
           
            if (!categoryGroups[categoryCode] || law.category > window.ss14Laws[categoryGroups[categoryCode]].category) {
                categoryGroups[categoryCode] = lawCode;
            }
        });
          
          
         lawsInCategory.forEach(([code, law]) => {
         // Рассчитываем время для каждой группы
             const label = document.createElement('label');
        Object.keys(categoryGroups).forEach(function(categoryCode) {
             label.className = 'law-checkbox';
             var lawCode = categoryGroups[categoryCode];
             label.innerHTML = `<input type="checkbox" id="law-${code}" onchange="calculateSentence()"> ${code} - ${law.name}`;
             var law = window.ss14Laws[lawCode];
             categoryDiv.appendChild(label);
              
            if (law.dClass) {
                hasDClass = true;
                totalTime += 70; // для расчёта модификаторов
            } else {
                totalTime += law.maxTime; // берём максимальное время
            }
              
            if (law.dismissal) {
                hasDismissal = true;
            }
         });
         });
          
          
         container.appendChild(categoryDiv);
         // Применяем модификаторы
    }
        switch (modifier) {
}
            case 'M-CLEM':
 
                // Помилование - только для категорий 3 и 4
function calculateSentence() {
                var hasEligibleLaws = Object.keys(categoryGroups).some(function(categoryCode) {
    const selectedLaws = [];
                    var lawCode = categoryGroups[categoryCode];
    const checkboxes = document.querySelectorAll('[id^="law-"]:checked');
                    var law = window.ss14Laws[lawCode];
   
                    return law.category === 3 || law.category === 4;
    checkboxes.forEach(checkbox => {
                });
        const lawCode = checkbox.id.replace('law-', '');
                if (hasEligibleLaws) {
        selectedLaws.push(lawCode);
                    totalTime = Math.max(0, totalTime - 10);
    });
                }
   
                break;
    if (selectedLaws.length === 0) {
               
        document.getElementById('calculation-result').style.display = 'none';
            case 'M-SURR':
        return;
                // Немедленная капитуляция
    }
                totalTime = Math.max(0, totalTime - 5);
   
                break;
    const modifier = document.getElementById('modifier-select').value;
               
    const isRepeat = document.getElementById('repeat-offense').checked;
            case 'M-DEFENSE':
    const hasCooperation = document.getElementById('cooperation').checked;
            case 'M-HELP':
    const isDClass = document.getElementById('d-class').checked;
                // Самооборона или спасение - снимает все обвинения
   
                totalTime = 0;
    let result = calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass);
                hasDClass = false;
   
                punishmentType = 'Обвинения сняты (требуется обыск)';
    displayResult(result, selectedLaws);
                break;
}
         }
 
function calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass) {
    let totalTime = 0;
    let punishmentType = 'Заключение под стражу';
    let hasDismissal = false;
    let hasDClass = false;
    let categoryGroups = {};
   
    // Группируем по категориям (одинаковые категории не складываются)
    selectedLaws.forEach(lawCode => {
        const law = laws[lawCode];
         const categoryCode = lawCode.substring(1); // получаем последние 2 цифры (тип нарушения)
          
          
         if (!categoryGroups[categoryCode] || law.category > laws[categoryGroups[categoryCode]].category) {
        // Повторное нарушение
             categoryGroups[categoryCode] = lawCode;
         if (isRepeat && totalTime > 0) {
             totalTime = Math.min(totalTime + 10, 50);
         }
         }
    });
   
    // Рассчитываем время для каждой группы
    Object.values(categoryGroups).forEach(lawCode => {
        const law = laws[lawCode];
          
          
         if (law.dClass) {
         // Сотрудничество со следствием
            hasDClass = true;
         if (hasCooperation && totalTime > 0) {
            totalTime += 70; // для расчёта модификаторов
             totalTime = Math.max(0, totalTime - 3);
         } else {
             totalTime += law.maxTime; // берём максимальное время
         }
         }
          
          
         if (law.dismissal) {
         // Определяем тип наказания
             hasDismissal = true;
        if (hasDClass) {
            punishmentType = 'Перевод в Д-класс';
            if (modifier === 'M-LOW' && isDClass) {
                punishmentType = 'Условная ликвидация (M-LOW)';
            } else if (modifier === 'M-VITAL' && isDClass) {
                punishmentType = 'Взаимодействие с SCP (M-VITAL)';
            }
        } else if (totalTime >= 50) {
            punishmentType = 'Перевод в Д-класс (срок ≥50 мин)';
            if (totalTime >= 35 && isDClass) {
                punishmentType += ' или добровольный перевод';
            }
        } else if (totalTime >= 35 && isDClass) {
             punishmentType = 'Возможен добровольный перевод в Д-класс';
         }
         }
    });
       
   
         return {
    // Применяем модификаторы
             totalTime: totalTime,
    switch (modifier) {
             punishmentType: punishmentType,
         case 'M-CLEM':
             hasDismissal: hasDismissal,
            // Помилование - только для категорий 3 и 4
             hasDClass: hasDClass,
            const hasEligibleLaws = Object.values(categoryGroups).some(lawCode => {
             categoryGroups: categoryGroups
                const law = laws[lawCode];
         };
                return law.category === 3 || law.category === 4;
             });
            if (hasEligibleLaws) {
                totalTime = Math.max(0, totalTime - 10);
             }
             break;
              
        case 'M-SURR':
            // Немедленная капитуляция
            totalTime = Math.max(0, totalTime - 5);
             break;
           
        case 'M-DEFENSE':
         case 'M-HELP':
            // Самооборона или спасение - снимает все обвинения
            totalTime = 0;
            hasDClass = false;
            punishmentType = 'Обвинения сняты (требуется обыск)';
            break;
     }
     }
   
 
    // Повторное нарушение
     function displayResult(result, selectedLaws) {
     if (isRepeat && totalTime > 0) {
         var resultDiv = document.getElementById('calculation-result');
         totalTime = Math.min(totalTime + 10, 50);
        if (!resultDiv) return;
    }
       
   
        var html = '<h4>📋 Результат расчёта:</h4>';
    // Сотрудничество со следствием
       
    if (hasCooperation && totalTime > 0) {
        html += '<div><strong>Выбранные статьи:</strong><br>';
        totalTime = Math.max(0, totalTime - 3);
        selectedLaws.forEach(function(lawCode) {
    }
            var law = window.ss14Laws[lawCode];
   
            html += '• ' + lawCode + ' - ' + law.name + '<br>';
    // Определяем тип наказания
        });
    if (hasDClass) {
         html += '</div><br>';
         punishmentType = 'Перевод в Д-класс';
          
         if (modifier === 'M-LOW' && isDClass) {
        html += '<div class="punishment-type">Тип наказания: ' + result.punishmentType + '</div>';
            punishmentType = 'Условная ликвидация (M-LOW)';
          
         } else if (modifier === 'M-VITAL' && isDClass) {
        if (result.totalTime > 0 && !result.hasDClass) {
             punishmentType = 'Взаимодействие с SCP (M-VITAL)';
             html += '<div class="time-result">Время заключения: ' + result.totalTime + ' минут</div>';
         }
         }
    } else if (totalTime >= 50) {
          
         punishmentType = 'Перевод в Д-класс (срок ≥50 мин)';
         if (result.hasDismissal) {
         if (totalTime >= 35 && isDClass) {
             html += '<div style="color: #f44336; margin-top: 10px;">⚠️ <strong>Обязательное увольнение с текущей должности</strong></div>';
             punishmentType += ' или добровольный перевод';
         }
         }
    } else if (totalTime >= 35 && isDClass) {
       
         punishmentType = 'Возможен добровольный перевод в Д-класс';
        // Дополнительная информация
        html += '<div style="margin-top: 15px; font-size: 12px; color: #666;">';
        html += '<strong>Примечания:</strong><br>';
        html += '• Статьи одной категории (одинаковые последние 2 цифры) не складываются<br>';
        html += '• Статьи разных категорий складываются<br>';
         html += '• При сроке 50+ минут - обязательный перевод в Д-класс<br>';
        html += '• При сроке 35+ минут класс Д может добровольно перейти в Д-класс';
        html += '</div>';
       
        resultDiv.innerHTML = html;
        resultDiv.style.display = 'block';
     }
     }
   
    return {
        totalTime: totalTime,
        punishmentType: punishmentType,
        hasDismissal: hasDismissal,
        hasDClass: hasDClass,
        categoryGroups: categoryGroups
    };
}


function displayResult(result, selectedLaws) {
    // Инициализация при загрузке страницы
     const resultDiv = document.getElementById('calculation-result');
     if (document.getElementById('law-checkboxes')) {
   
         generateLawCheckboxes();
    let html = '<h4>📋 Результат расчёта:</h4>';
   
    html += '<div><strong>Выбранные статьи:</strong><br>';
    selectedLaws.forEach(lawCode => {
        const law = laws[lawCode];
        html += `• ${lawCode} - ${law.name}<br>`;
    });
    html += '</div><br>';
   
    html += `<div class="punishment-type">Тип наказания: ${result.punishmentType}</div>`;
   
    if (result.totalTime > 0 && !result.hasDClass) {
         html += `<div class="time-result">Время заключения: ${result.totalTime} минут</div>`;
    }
   
    if (result.hasDismissal) {
        html += '<div style="color: #f44336; margin-top: 10px;">⚠️ <strong>Обязательное увольнение с текущей должности</strong></div>';
     }
     }
   
    // Дополнительная информация
    html += '<div style="margin-top: 15px; font-size: 12px; color: #666;">';
    html += '<strong>Примечания:</strong><br>';
    html += '• Статьи одной категории (одинаковые последние 2 цифры) не складываются<br>';
    html += '• Статьи разных категорий складываются<br>';
    html += '• При сроке 50+ минут - обязательный перевод в Д-класс<br>';
    html += '• При сроке 35+ минут класс Д может добровольно перейти в Д-класс';
    html += '</div>';
   
    resultDiv.innerHTML = html;
    resultDiv.style.display = 'block';
}
// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
    generateLawCheckboxes();
});
});
});

Текущая версия от 14:24, 9 сентября 2025

$(document).ready(function() {
    // Инициализация боковой панели
    $('.боковая-панель-кнопка').on('click', function() {
        var targetId = $(this).data('target');
        
        // Удаляем активный класс у всех кнопок
        $('.боковая-панель-кнопка').removeClass('active');
        // Добавляем активный класс текущей кнопке
        $(this).addClass('active');
        
        // Скрываем все разделы
        $('.боковая-панель-раздел').removeClass('default');
        // Показываем выбранный раздел
        $('#' + targetId).addClass('default');
    });
    
    // Активируем первую кнопку по умолчанию
    $('.боковая-панель-кнопка:first').click();
    
    // Подключаем Tippy.js через CDN динамически
    if (!window.tippy) {
        var tippyScript = document.createElement('script');
        tippyScript.src = "https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js";
        tippyScript.onload = function() {
            var tippyCoreScript = document.createElement('script');
            tippyCoreScript.src = "https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.min.js";
            tippyCoreScript.onload = initTippy;
            document.head.appendChild(tippyCoreScript);
        };
        document.head.appendChild(tippyScript);

        // Подключаем CSS
        var tippyCSS = document.createElement('link');
        tippyCSS.rel = "stylesheet";
        tippyCSS.href = "https://unpkg.com/tippy.js@6/dist/tippy.css";
        document.head.appendChild(tippyCSS);
    } else {
        initTippy();
    }

    // Инициализация Tippy после загрузки скриптов
    function initTippy() {
        $('.допуск-контейнер').each(function() {
            var content = $(this).find('.допуск-подсказка').html(); // берем содержимое подсказки
            tippy(this, {
                content: content,
                allowHTML: true,
                interactive: true,
                placement: 'auto',      // автоматический выбор позиции
                maxWidth: '500px',
                minHeight: 'auto',
                theme: 'dark',          // темная тема
                arrow: true,           // без стрелки
                duration: [200, 200],   // плавное появление/исчезание
                popperOptions: {
                    modifiers: [
                        {
                            name: 'preventOverflow',
                            options: {
                                padding: 8 // отступ от краев экрана
                            }
                        },
                        {
                            name: 'flip',
                            options: {
                                fallbackPlacements: ['top', 'bottom', 'right', 'left']
                            }
                        }
                    ]
                }
            });
        });
    }

    // Данные о законах SS14
    window.ss14Laws = {
        '100': { name: 'Оскорбительное поведение', category: 1, minTime: 5, maxTime: 10 },
        '101': { name: 'Лёгкий ущерб здоровью', category: 1, minTime: 5, maxTime: 10 },
        '102': { name: 'Порча имущества', category: 1, minTime: 5, maxTime: 10 },
        '103': { name: 'Мелкая кража', category: 1, minTime: 5, maxTime: 10 },
        '104': { name: 'Владение регулируемыми веществами', category: 1, minTime: 5, maxTime: 10 },
        '105': { name: 'Злоупотребление экипировкой', category: 1, minTime: 5, maxTime: 10 },
        '106': { name: 'Помеха работе сотрудников', category: 1, minTime: 5, maxTime: 10 },
        '107': { name: 'Проникновение', category: 1, minTime: 5, maxTime: 10 },
        '108': { name: 'Жестокое обращение с животными', category: 1, minTime: 5, maxTime: 10 },
        '109': { name: 'Клевета', category: 1, minTime: 5, maxTime: 10 },
        
        '200': { name: 'Оскорбление власти', category: 2, minTime: 10, maxTime: 15 },
        '201': { name: 'Средний ущерб здоровью', category: 2, minTime: 10, maxTime: 15 },
        '202': { name: 'Вандализм', category: 2, minTime: 10, maxTime: 15 },
        '204': { name: 'Распространение регулируемых веществ', category: 2, minTime: 10, maxTime: 15 },
        '205': { name: 'Владение боевым приспособлением', category: 2, minTime: 10, maxTime: 15 },
        '206': { name: 'Помеха правосудию', category: 2, minTime: 10, maxTime: 15 },
        '207': { name: 'Проникновение со взломом', category: 2, minTime: 10, maxTime: 15 },
        '208': { name: 'Убийство животного', category: 2, minTime: 10, maxTime: 15 },
        '209': { name: 'Халатность', category: 2, minTime: 10, maxTime: 15 },
        '210': { name: 'Ограничение свободы', category: 2, minTime: 10, maxTime: 15 },
        '211': { name: 'Шпионаж', category: 2, minTime: 10, maxTime: 15 },
        
        '300': { name: 'Забастовка', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '301': { name: 'Тяжкий ущерб здоровью', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '302': { name: 'Саботаж', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '303': { name: 'Кража', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '304': { name: 'Оборот контрабанды', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '305': { name: 'Владение нелетальным оружием', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '306': { name: 'Мошенничество', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '307': { name: 'Проникновение в стратегическую точку', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '308': { name: 'Распространение опасной флоры и фауны', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '309': { name: 'Серьёзная халатность', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '310': { name: 'Похищение', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        '311': { name: 'Проникновение в защищённый канал', category: 3, minTime: 15, maxTime: 20, dismissal: true },
        
        '400': { name: 'Бунт', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '401': { name: 'Убийство', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '403': { name: 'Крупная кража', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '404': { name: 'Производство регулируемых веществ', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '405': { name: 'Владение летальным оружием', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '406': { name: 'Растрата активов корпорации', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '408': { name: 'Убийство особого животного', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '409': { name: 'Грубая халатность', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '410': { name: 'Похищение должностного лица', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        '411': { name: 'Антикорпоративный шпионаж', category: 4, minTime: 20, maxTime: 25, dismissal: true },
        
        '500': { name: 'Мятеж', category: 5, dClass: true, dismissal: true },
        '501': { name: 'Уничтожение тела', category: 5, dClass: true, dismissal: true },
        '502': { name: 'Крупный саботаж', category: 5, dClass: true, dismissal: true },
        '503': { name: 'Особая кража', category: 5, dClass: true, dismissal: true },
        '504': { name: 'Владение вражеским снаряжением', category: 5, dClass: true, dismissal: true },
        '505': { name: 'Распространение оружия', category: 5, dClass: true, dismissal: true },
        '507': { name: 'Проникновение в защищённую стратегическую точку', category: 5, dClass: true, dismissal: true },
        '510': { name: 'Похищение высокопоставленных лиц', category: 5, dClass: true, dismissal: true },
        '511': { name: 'Разглашение секретной информации', category: 5, dClass: true, dismissal: true }
    };

    // Глобальные функции для SS14 калькулятора
    window.ss14CurrentLawCode = null;

    window.toggleCalculator = function(lawCode) {
        var calculator = document.getElementById('ss14-calculator');
        window.ss14CurrentLawCode = lawCode;
        
        if (!calculator) return;
        
        if (calculator.style.display === 'none' || !calculator.classList.contains('active')) {
            calculator.classList.add('active');
            generateLawCheckboxes();
            
            // Автоматически выбираем нажатый закон
            var checkbox = document.getElementById('law-' + lawCode);
            if (checkbox) {
                checkbox.checked = true;
            }
            
            calculateSentence();
        } else {
            calculator.classList.remove('active');
        }
    };

    window.generateLawCheckboxes = function() {
        var container = document.getElementById('law-checkboxes');
        if (!container) return;
        
        container.innerHTML = '';
        
        // Группируем законы по категориям
        var categories = {
            1: { name: 'Лёгкие нарушения (1XX)', color: '#0F4F27' },
            2: { name: 'Средние нарушения (2XX)', color: '#414700' },
            3: { name: 'Тяжкие нарушения (3XX)', color: '#611300' },
            4: { name: 'Особо тяжкие нарушения (4XX)', color: '#57000C' },
            5: { name: 'Критические нарушения (5XX)', color: '#121212' }
        };
        
        for (var cat = 1; cat <= 5; cat++) {
            var categoryDiv = document.createElement('div');
            categoryDiv.style.marginBottom = '15px';
            categoryDiv.innerHTML = '<h5 style="color: ' + categories[cat].color + '; margin-bottom: 8px;">' + categories[cat].name + '</h5>';
            
            var lawsInCategory = Object.keys(window.ss14Laws).filter(function(code) {
                return window.ss14Laws[code].category === cat;
            });
            
            lawsInCategory.forEach(function(code) {
                var law = window.ss14Laws[code];
                var label = document.createElement('label');
                label.className = 'law-checkbox';
                label.innerHTML = '<input type="checkbox" id="law-' + code + '" onchange="calculateSentence()"> ' + code + ' - ' + law.name;
                categoryDiv.appendChild(label);
            });
            
            container.appendChild(categoryDiv);
        }
    };

    window.calculateSentence = function() {
        var selectedLaws = [];
        var checkboxes = document.querySelectorAll('[id^="law-"]:checked');
        
        checkboxes.forEach(function(checkbox) {
            var lawCode = checkbox.id.replace('law-', '');
            selectedLaws.push(lawCode);
        });
        
        if (selectedLaws.length === 0) {
            var resultDiv = document.getElementById('calculation-result');
            if (resultDiv) {
                resultDiv.style.display = 'none';
            }
            return;
        }
        
        var modifierSelect = document.getElementById('modifier-select');
        var repeatOffense = document.getElementById('repeat-offense');
        var cooperation = document.getElementById('cooperation');
        var dClass = document.getElementById('d-class');
        
        var modifier = modifierSelect ? modifierSelect.value : 'none';
        var isRepeat = repeatOffense ? repeatOffense.checked : false;
        var hasCooperation = cooperation ? cooperation.checked : false;
        var isDClass = dClass ? dClass.checked : false;
        
        var result = calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass);
        displayResult(result, selectedLaws);
    };

    function calculatePunishment(selectedLaws, modifier, isRepeat, hasCooperation, isDClass) {
        var totalTime = 0;
        var punishmentType = 'Заключение под стражу';
        var hasDismissal = false;
        var hasDClass = false;
        var categoryGroups = {};
        
        // Группируем по категориям (одинаковые категории не складываются)
        selectedLaws.forEach(function(lawCode) {
            var law = window.ss14Laws[lawCode];
            var categoryCode = lawCode.substring(1); // получаем последние 2 цифры (тип нарушения)
            
            if (!categoryGroups[categoryCode] || law.category > window.ss14Laws[categoryGroups[categoryCode]].category) {
                categoryGroups[categoryCode] = lawCode;
            }
        });
        
        // Рассчитываем время для каждой группы
        Object.keys(categoryGroups).forEach(function(categoryCode) {
            var lawCode = categoryGroups[categoryCode];
            var law = window.ss14Laws[lawCode];
            
            if (law.dClass) {
                hasDClass = true;
                totalTime += 70; // для расчёта модификаторов
            } else {
                totalTime += law.maxTime; // берём максимальное время
            }
            
            if (law.dismissal) {
                hasDismissal = true;
            }
        });
        
        // Применяем модификаторы
        switch (modifier) {
            case 'M-CLEM':
                // Помилование - только для категорий 3 и 4
                var hasEligibleLaws = Object.keys(categoryGroups).some(function(categoryCode) {
                    var lawCode = categoryGroups[categoryCode];
                    var law = window.ss14Laws[lawCode];
                    return law.category === 3 || law.category === 4;
                });
                if (hasEligibleLaws) {
                    totalTime = Math.max(0, totalTime - 10);
                }
                break;
                
            case 'M-SURR':
                // Немедленная капитуляция
                totalTime = Math.max(0, totalTime - 5);
                break;
                
            case 'M-DEFENSE':
            case 'M-HELP':
                // Самооборона или спасение - снимает все обвинения
                totalTime = 0;
                hasDClass = false;
                punishmentType = 'Обвинения сняты (требуется обыск)';
                break;
        }
        
        // Повторное нарушение
        if (isRepeat && totalTime > 0) {
            totalTime = Math.min(totalTime + 10, 50);
        }
        
        // Сотрудничество со следствием
        if (hasCooperation && totalTime > 0) {
            totalTime = Math.max(0, totalTime - 3);
        }
        
        // Определяем тип наказания
        if (hasDClass) {
            punishmentType = 'Перевод в Д-класс';
            if (modifier === 'M-LOW' && isDClass) {
                punishmentType = 'Условная ликвидация (M-LOW)';
            } else if (modifier === 'M-VITAL' && isDClass) {
                punishmentType = 'Взаимодействие с SCP (M-VITAL)';
            }
        } else if (totalTime >= 50) {
            punishmentType = 'Перевод в Д-класс (срок ≥50 мин)';
            if (totalTime >= 35 && isDClass) {
                punishmentType += ' или добровольный перевод';
            }
        } else if (totalTime >= 35 && isDClass) {
            punishmentType = 'Возможен добровольный перевод в Д-класс';
        }
        
        return {
            totalTime: totalTime,
            punishmentType: punishmentType,
            hasDismissal: hasDismissal,
            hasDClass: hasDClass,
            categoryGroups: categoryGroups
        };
    }

    function displayResult(result, selectedLaws) {
        var resultDiv = document.getElementById('calculation-result');
        if (!resultDiv) return;
        
        var html = '<h4>📋 Результат расчёта:</h4>';
        
        html += '<div><strong>Выбранные статьи:</strong><br>';
        selectedLaws.forEach(function(lawCode) {
            var law = window.ss14Laws[lawCode];
            html += '• ' + lawCode + ' - ' + law.name + '<br>';
        });
        html += '</div><br>';
        
        html += '<div class="punishment-type">Тип наказания: ' + result.punishmentType + '</div>';
        
        if (result.totalTime > 0 && !result.hasDClass) {
            html += '<div class="time-result">Время заключения: ' + result.totalTime + ' минут</div>';
        }
        
        if (result.hasDismissal) {
            html += '<div style="color: #f44336; margin-top: 10px;">⚠️ <strong>Обязательное увольнение с текущей должности</strong></div>';
        }
        
        // Дополнительная информация
        html += '<div style="margin-top: 15px; font-size: 12px; color: #666;">';
        html += '<strong>Примечания:</strong><br>';
        html += '• Статьи одной категории (одинаковые последние 2 цифры) не складываются<br>';
        html += '• Статьи разных категорий складываются<br>';
        html += '• При сроке 50+ минут - обязательный перевод в Д-класс<br>';
        html += '• При сроке 35+ минут класс Д может добровольно перейти в Д-класс';
        html += '</div>';
        
        resultDiv.innerHTML = html;
        resultDiv.style.display = 'block';
    }

    // Инициализация при загрузке страницы
    if (document.getElementById('law-checkboxes')) {
        generateLawCheckboxes();
    }
});