Магия Энирина

Магия - неотъемлемая часть Энирина, связывающая всю его суть не хуже любого закона природы. Весь мир пропитан магией - незримой и таинственной, но от этого не менее настоящей силой. Любой маг или волшебное существо наделено талантом обращаться с магией, посредством неё влиять на окружающий мир, и изменять его. Знание законов магии называется Теоретической Магией и изучается многими народами. Наука эта однозначная и точная, но сложная и многогранная. И хотя учёные не один век ломают головы над Единой Теорией Волшебства, а знание Теоретической Магии отнюдь не обязательно, чтобы колдовать, несколько важных её тезисов совсем не повредят:

1. Магия требует определённого состояния сознания. Умение достигать его и называется магическим даром.
2. Заклинания, жесты, танцы и прочее направлены, главным образом, на достижение этого особого состояния. Умелые маги могут управиться и без них, и такое умение называют концентрацией.
3. Предполагается, что магический дар есть в том или ином виде у каждого живого существа, но только десятая доля людей способна с ним управляться. Как аналогию в пример часто приводят художественный талант: карандаш умеет держать почти каждый, но что с ним делать дальше? Существующий магический талант можно совершенствовать, но способов развития его "с нуля" не изобрели. Некоторые народы обладают сильным магическим даром от момента рождения, а другие, наоборот, почти не могут пользоваться магией.
4. Магия требует усилий. Их результатом является истощение. Маги, не рассчитавшие своих сил, могут получить травмы и даже умереть. Одна из самых распространённых причин таких смертей - разрыв сердца.
5. Всё так или иначе взаимодействует с магией. Некоторыми такими вещами пользуются маги. Так, например, создаются магические кристаллы, которыми волшебники пользуются для экономии собственных сил. Длительный контакт с мощными артефактами и магическими источниками может вызвать постоянные изменения в организме, привыкание и даже зависимость. Особенности таких последствий в каждом случае уникальны.
6. Артефакты - это вещи или явления, влияющие на мир посредством магии. Чтобы использовать некоторые из них, нужен магический дар.
7. В мире есть места с магическими аномалиями, их называют "местами силы". В некоторых колдовать намного труднее, в других - легче. На основе особенностей вторых были созданы Источники Силы.
8. Наделить предмет волшебными свойствами можно с помощью любого вида магии. Это называют "зачарованием". Некоторые способы зачарования более удобны, чем другие. 

https://i.gyazo.com/d930a60456ca01ba0b700987fe0c1e37.png

Волшебство, Быстрая магия, Классическое колдовство... как только не называют каноническую магию, требующую наименьшего времени "сотворения".
По сути единственное, что действительно нужно для такой магии волшебнику - это концентрация, но многие маги используют слова, жесты, а иногда даже песни или танец. В любом случае, это до сих пор архаично зовётся "чтением", даже если в процессе не было произведено ни звука. Рецепт такой магии неизменный: воспроизвёл заклинания - получил эффект.

Обычно маги имеют одну, реже - две основных магических склонности и максимум 3-4 дополнительных.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Самый быстрый вид магии. Боевые маги чаще всего пользуются именно такой магией.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Самый распространённый, изученный и понятный вид магии. Словом - каноничный. Существует масса способ научиться чему-нибудь, при условии наличия магического таланта.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Для разных эффектов можно сочетать несколько заклинаний в одном. Для этого необходима сноровка, но при желании научиться таким трюкам может каждый маг.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Существует масса изученных способов упрощения или усиления этой магии с помощью расходных материалов. Их список можно прочесть здесь.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Эффекты строго ограничены изученными магом заклинаниями. Придумывать что-то новое сложно, кропотливо, а порой - опасно.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Степень истощения от этой магии самая высокая: скорость требует жертв.

https://i.gyazo.com/6a3edfb648e3d04333681e9205600ea3.png

Считается, что эта магия - одна из самых древних. Некоторые считают, что руны - не что иное, как Истинные Имена вещей. Поэтому рунный маг наделён силой говорить на языке, который слышит само мироздание. Другие считают, что руны - способ быть услышанным древними богами, чьи имена позабыли.
В любом случае, магия рун имеет следующие особенности:

https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Гибкость. Заклинания состоят из нескольких магических символов, обычно в пределах пяти. Опытные маги могут пользоваться большим числом, что позволяет добиться практически любого магического эффекта.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Доступность. Даже слабого магического таланта достаточно для использования магических символов, поэтому руническая магия особенно в почёте у гномов.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png  Один из самых распространённых видов зачарования предметов. Поэтому рунных магов очень ценят в качестве зачарователей!
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png С помощью этой магии можно подготовить значительное количество расходных магических предметов вроде свитков с заклинаниями. Такие вещи очень ценны в бою, поскольку экономят силы мага.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Создание магических символов - дело тонкое и очень кропотливое, оно требует чрезвычайного количества времени. Даже опытный маг не создаст символ быстрее, чем произнесёт заклинание.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Распространено мнение, что это "магия дикарей", ведь создавать магические знаки - особенно древние, - проще, если использовать кровь, кость или соки редких ядовитых растений.

https://i.gyazo.com/79bf8288f9c574481b8ce3b83649bbf8.png

Ремесло магических преобразований. В большинстве случаев требует расходных материалов магической природы. Иконической стезёй алхимии является зельеварение. Раньше этим занимались преимущественно колдуны и ведьмы, потому простой люд нередко относится к алхимикам с недоверием.

https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Значительная часть известных алхимических преобразований не требует наличия магического таланта, а использование зелий - семи пядей во лбу. Сплошной плюс!
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Алхимия - наука древняя. Известных алхимических "рецептур" - великое множество. Следуй их инструкциям внимательно, и всё получится!
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Многообразие возможностей алхимии сравнимо с рунной магией. Подобное можно сказать и о востребованности алхимиков.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Алхимия требует жертв. Даже простые алхимические преобразования могут изрядно облегчить кошелёк, а некоторые из редких расходных материалов так и вовсе не достать за деньги.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Дороговизна и редкость некоторых материалов не позволяют большинству алхимиков заводить большое число учеников. Попасть к алхимику в подмастерья - уже большая удача. Ну а место в престижном заведении для изучения алхимии требует внушительного "взноса на расходуемые материалы".
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Распространённое шарлатанство часто портит репутацию и создаёт неприятности честным алхимикам.

https://i.gyazo.com/1f3cde18d6fe6204686434c27c71e982.png

Малопонятная, практически не поддающаяся изучению магия. И это неудивительно - ведь это магия богов. Кто-либо наделённый такой магией - явление редкое и привлекающее к себе много внимания как простых людей, так и власть имущих. Где-то такие кудесники появляются чаще, но почему - этого смертным знать не дано. Можно только предположить, что сила этого дара зависит от угодности деяний смертного на благо его бога-покровителя. Как следствие, Единый или Сильветтара чаще помогают исцелить больных и раненных, чем покарать грешников. Жрецы же Вулкхора помогают воинам или сами сеют смуту. Впрочем, бывают и исключения.
Эта магия сама по себе не требует никакого магического таланта, поскольку "происходит" не от смертного. Обладающие божественной магией очень, очень редко практикуют другую магию.

https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Божественная магия расходует силы ничуть не хуже канонической. Впрочем, на всё воля богов.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Божественная магия недаром называется божественной: в некоторых случаях она способна излечить целую деревню или стереть её с лица земли.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Нет чётких границ того, на что способна божественная магия.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Боги своенравны. Нельзя быть полностью уверенным, что божественная магия сработает здесь и сейчас. А стоит только не угодить своему божественному покровителю, и кара его может быть страшной.

https://i.gyazo.com/3754bbe3407145f460a5f74db073252c.png

Можно спорить, что каждая магия относится к ритуальной, то есть требует особого подхода, установленного обряда. В каком-то смысле, так оно и есть. Здесь же речь идёт о такой магии, которая строится в первую очередь на знаниях, некоторые из которых произросли из незапамятных глубин времён - самих основ мироздания.

https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png В некоторых случаях ритуальную магию по силе может превзойти разве что божественная.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png В большинстве случаев, ритуальная магия является несколько более надёжным способом достижения цели, чем божественная.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Любая ошибка стоит дорого. В лучшем случае ритуал не принесёт результатов. В худшем же случае смерть может показаться избавлением.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Эта магия требует времени, терпения, и тщательной подготовки. Но прежде всего времени. Часто дело не только в длительности ритуала, но и особенностях времени года, например.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Подготовка нередко подразумевает особенное место и/или расходные материалы: иногда дешёвые и легкодоступные, вроде мела или угля, но в зависимости от ритуала это может быть что угодно. Бесценные артефакты и человеческие жертвоприношения тут далеко не в конце списка.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Большинство могущественных ритуалов практически невозможно воспроизвести в одиночку безошибочно.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Из-за своей чрезвычайной опасности ритуальная магия не очень-то популярна, местами запрещена, а кое-где её практикующих и вовсе преследуют.

https://i.gyazo.com/d78c75a2173bb901eadf4a3e585b82af.png

Эта магия во многом похожа на божественную, но шаманы - те, кто её практикует, - контактируют с духами. Духи помогают шаманам, делятся с ними особыми силами и даже сражаются на их стороне. В отличие от божественной магии, здесь без магического таланта не обойтись. Шаманы часто знают какие-нибудь приёмы "канонической" магии, алхимии, а также рунной и ритуальной магии.

https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Духи не являются богами, но они тоже сверхъестественные существа, и их силы им под стать.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Духи - несколько более надёжный источник сил, чем боги.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Шаман может просить помощи у любых духов, поэтому эта магия очень разнообразна.
https://i.gyazo.com/43bd9b4358e408bd179b80bccbe03ba1.png Можно стать "любимчиком" духа, а то и нескольких.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Использование этой магии требует некоторого времени, а обучение ей - много времени.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Одного магического таланта недостаточно - нужно ещё и нравиться духам.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Это магия "варварских племён и дикарей", потому научиться ей можно только у наставника. Принцип отбора таких учеников ведом только самим шаманам.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Быть любимчиком одних духов - значит провоцировать других. Быть втянутым в распри духов - сомнительное счастье.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Многие духи очень изворотливы, и не прочь обмануть шамана и весь его род в придачу.
https://i.gyazo.com/0a92b06719470be93ccd27505452a5ae.png Смертность на стадии ученичества очень высока за счёт различных практик изменения состояния сознания.


Калькулятор баллов заклинаний


[html]
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Калькулятор баллов заклинаний</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background: #4a4a4a;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
            padding: 1.2rem;
        }
        .calculator {
            max-width: 520px;
            width: 100%;
            background: #666666;
            border-radius: 24px;
            padding: 2rem 2rem 2.2rem;
            box-shadow: 0 16px 40px rgba(0,0,0,0.5), 0 0 0 1px #303030 inset, 0 0 0 2px #4d4d4d inset;
            border: 1px solid #303030;
            transition: all 0.2s;
        }
        h1 {
            font-size: 1.9rem;
            font-weight: 700;
            letter-spacing: 1.5px;
            color: #FFDB70;
            text-shadow: 0 2px 4px #1f1f1f;
            text-align: center;
            margin-bottom: 0.2rem;
            font-family: 'Segoe UI', 'Roboto', sans-serif;
            word-break: break-word;
        }
        .sub {
            text-align: center;
            color: #FFDB70;
            font-size: 0.95rem;
            letter-spacing: 1px;
            border-bottom: 1px solid #303030;
            padding-bottom: 0.7rem;
            margin-bottom: 1.8rem;
            font-weight: 400;
            opacity: 0.9;
        }
        .field-group {
            margin-bottom: 1.8rem;
        }
        label {
            display: block;
            font-weight: 600;
            color: #FFDB70;
            text-shadow: 0 1px 2px #1f1f1f;
            margin-bottom: 0.4rem;
            font-size: 1rem;
            letter-spacing: 0.3px;
        }
        .input-wrapper {
            background: #303030;
            border-radius: 40px;
            padding: 0.1rem 0.1rem 0.1rem 1.5rem;
            border: 1px solid #4a4a4a;
            box-shadow: inset 0 4px 8px rgba(0,0,0,0.5), 0 1px 0 #4a4a4a;
            display: flex;
            align-items: center;
        }
        .input-wrapper input {
            width: 100%;
            background: transparent;
            border: none;
            padding: 0.9rem 0.9rem 0.9rem 0;
            font-size: 1.1rem;
            font-weight: 500;
            color: #FFDB70;
            outline: none;
            font-family: 'Segoe UI', 'Roboto', sans-serif;
            letter-spacing: 0.5px;
        }
        .input-wrapper input::placeholder {
            color: #888888;
            font-weight: 300;
            font-size: 0.95rem;
            opacity: 0.8;
        }
        .input-wrapper input:focus {
            color: #FFE48A;
        }
        .input-wrapper span {
            background: #303030;
            padding: 0.5rem 1.2rem;
            border-radius: 40px;
            color: #FFDB70;
            font-weight: 600;
            font-size: 0.9rem;
            letter-spacing: 0.5px;
            background: #3a3a3a;
            border-left: 1px solid #4a4a4a;
            white-space: nowrap;
        }
        .hint {
            display: block;
            text-align: right;
            color: #d4d4d4;
            font-size: 0.75rem;
            margin-top: 0.2rem;
            padding-right: 0.5rem;
            opacity: 0.85;
        }
        .action {
            display: flex;
            gap: 1rem;
            justify-content: center;
            margin: 2rem 0 1.8rem;
        }
        .btn {
            background: #303030;
            border: none;
            border-radius: 60px;
            padding: 0.9rem 2.2rem;
            font-weight: 700;
            font-size: 1.2rem;
            color: #FFDB70;
            text-shadow: 0 2px 3px #1a1a1a;
            border-bottom: 4px solid #1a1a1a;
            border-right: 1px solid #4a4a4a;
            border-left: 1px solid #4a4a4a;
            cursor: pointer;
            transition: 0.1s ease;
            box-shadow: 0 8px 0 #202020, 0 6px 12px rgba(0,0,0,0.5);
            letter-spacing: 1px;
            background: #303030;
            flex: 1;
        }
        .btn:hover {
            background: #3d3d3d;
            border-bottom-width: 3px;
            transform: translateY(2px);
            box-shadow: 0 5px 0 #1a1a1a, 0 6px 12px rgba(0,0,0,0.6);
            color: #FFE48A;
        }
        .btn:active {
            transform: translateY(6px);
            border-bottom-width: 1px;
            box-shadow: 0 1px 0 #151515;
        }
        .result-box {
            background: #303030;
            border-radius: 60px;
            padding: 0.5rem 1.5rem;
            margin: 1.2rem 0 0.2rem;
            border: 1px solid #4a4a4a;
            box-shadow: inset 0 0 18px #1a1a1a, 0 6px 12px rgba(0,0,0,0.3);
            text-align: center;
        }
        .result-label {
            font-size: 0.85rem;
            color: #aaaaaa;
            letter-spacing: 3px;
            font-weight: 300;
            text-transform: uppercase;
        }
        .result-value {
            font-size: 3.8rem;
            font-weight: 800;
            color: #FFDB70;
            text-shadow: 0 0 18px #b38f3a, 0 4px 8px #1a1a1a;
            line-height: 1.3;
            font-family: 'Segoe UI', 'Roboto', sans-serif;
            letter-spacing: 4px;
            word-break: break-word;
        }
        .result-unit {
            font-size: 1rem;
            color: #d4d4d4;
            font-weight: 400;
            letter-spacing: 1px;
            margin-top: -0.3rem;
        }
        .footnote {
            margin-top: 1.5rem;
            font-size: 0.75rem;
            text-align: center;
            color: #b0b0b0;
            border-top: 1px solid #3a3a3a;
            padding-top: 1rem;
        }
        .footnote span {
            display: inline-block;
            background: #303030;
            padding: 0.1rem 1.2rem;
            border-radius: 30px;
            border: 1px solid #4a4a4a;
            color: #FFDB70;
        }

        /* Стили для кнопки распределения */
        .distribute-action {
            display: none;
            gap: 1rem;
            justify-content: center;
            margin: 0.5rem 0 0.5rem;
        }
        .distribute-action.show {
            display: flex;
        }
        .btn-distribute {
            background: #FFDB70;
            border: none;
            border-radius: 60px;
            padding: 0.9rem 2.2rem;
            font-weight: 700;
            font-size: 1.2rem;
            color: #1a1a1a;
            text-shadow: 0 1px 2px rgba(255,255,255,0.3);
            border-bottom: 4px solid #b38f3a;
            border-right: 1px solid #e8c85a;
            border-left: 1px solid #e8c85a;
            cursor: pointer;
            transition: 0.1s ease;
            box-shadow: 0 8px 0 #8f6f2a, 0 6px 12px rgba(0,0,0,0.5);
            letter-spacing: 1px;
            flex: 1;
        }
        .btn-distribute:hover {
            background: #ffe48a;
            border-bottom-width: 3px;
            transform: translateY(2px);
            box-shadow: 0 5px 0 #7a5d22, 0 6px 12px rgba(0,0,0,0.6);
        }
        .btn-distribute:active {
            transform: translateY(6px);
            border-bottom-width: 1px;
            box-shadow: 0 1px 0 #6b4f1d;
        }

        @media (max-width: 480px) {
            .calculator { padding: 1.5rem; }
            .btn { font-size: 1rem; padding: 0.7rem 1rem; }
            .result-value { font-size: 2.8rem; }
            .input-wrapper { padding-left: 1rem; }
            .btn-distribute { font-size: 1rem; padding: 0.7rem 1rem; }
        }
    </style>
</head>
<body>
<div style="display: flex; justify-content: center; width: 100%;">
    <div class="calculator" role="main" aria-label="Калькулятор заклинаний">
        <h1>БАЛЛЫ ЗАКЛИНАНИЙ</h1>
        <div class="sub">1 балл = 1 заклинание / +1 уровень</div>

        <div class="field-group">
            <label for="months">Месяцев обучения</label>
            <div class="input-wrapper">
                <input type="text" id="months" placeholder="например 6" value="">
                <span>мес.</span>
            </div>
            <span class="hint">(допускаются дробные, например 3.5)</span>
        </div>

        <div class="field-group">
            <label for="hoursPerWeek">Часов в неделю</label>
            <div class="input-wrapper">
                <input type="text" id="hoursPerWeek" placeholder="например 14" value="">
                <span>ч/нед</span>
            </div>
            <span class="hint">(минимум 0.5, шаг 0.5)</span>
        </div>

        <div class="action">
            <button class="btn" id="calculateBtn">РАССЧИТАТЬ</button>
        </div>

        <div class="result-box" id="resultBox">
            <div class="result-label">итоговые баллы</div>
            <div class="result-value" id="resultValue">0</div>
            <div class="result-unit">заклинаний / уровней</div>
        </div>

        <!-- Кнопка распределения (по умолчанию скрыта) -->
        <div class="distribute-action" id="distributeAction">
            <button class="btn-distribute" id="distributeBtn">РАСПРЕДЕЛИТЬ</button>
        </div>

        <div class="footnote">
            <span>200 часов = 1 балл</span>
        </div>
    </div>
</div>

    <script>
        (function() {
            const monthsInput = document.getElementById('months');
            const hoursInput = document.getElementById('hoursPerWeek');
            const calculateBtn = document.getElementById('calculateBtn');
            const resultDisplay = document.getElementById('resultValue');
            const distributeAction = document.getElementById('distributeAction');
            const distributeBtn = document.getElementById('distributeBtn');

            // Очистка ввода: разрешаем только цифры, точку и запятую (заменяем на точку)
            function sanitizeNumberInput(e) {
                const input = e.target;
                let val = input.value;
                // заменяем запятые на точки
                val = val.replace(',', '.');
                // удаляем всё кроме цифр, точки и минуса (минус только в начале, но мы его уберем)
                val = val.replace(/[^0-9.]/g, '');
                // предотвращаем множественные точки
                const parts = val.split('.');
                if (parts.length > 2) {
                    val = parts[0] + '.' + parts.slice(1).join('');
                }
                // если после точки больше 2 знаков — ограничим (для аккуратности)
                if (val.includes('.')) {
                    const intPart = val.split('.')[0];
                    let decPart = val.split('.')[1] || '';
                    if (decPart.length > 6) decPart = decPart.slice(0, 6);
                    val = intPart + (decPart ? '.' + decPart : '');
                }
                input.value = val;
            }

            monthsInput.addEventListener('input', sanitizeNumberInput);
            hoursInput.addEventListener('input', sanitizeNumberInput);

            // Функция вычисления
            function calculateSpellPoints() {
                // Получаем значения, заменяем запятую на точку (уже заменено в sanitize, но на всякий случай)
                let months = parseFloat(monthsInput.value.trim().replace(',', '.'));
                let hoursPerWeek = parseFloat(hoursInput.value.trim().replace(',', '.'));

                // Проверка на валидность
                const isMonthsValid = !isNaN(months) && months >= 0 && monthsInput.value.trim() !== '';
                const isHoursValid = !isNaN(hoursPerWeek) && hoursPerWeek >= 0 && hoursInput.value.trim() !== '';

                if (!isMonthsValid || !isHoursValid) {
                    resultDisplay.textContent = '?';
                    distributeAction.classList.remove('show');
                    return;
                }

                // Округление для чистоты
                months = Math.round(months * 100) / 100;
                hoursPerWeek = Math.round(hoursPerWeek * 100) / 100;

                // Расчёт: месяцы * недели_в_месяце * часы_в_неделю / 200
                const weeksPerMonth = 365.25 / 12 / 7; // ≈ 4.348
                const totalHours = months * weeksPerMonth * hoursPerWeek;
                let points = totalHours / 200;

                if (points < 0) points = 0;
                points = Math.round(points * 100) / 100;

                if (!isFinite(points)) {
                    resultDisplay.textContent = '∞';
                    distributeAction.classList.remove('show');
                    return;
                }

                // Форматирование: убираем лишние нули, но оставляем минимум 1 знак после запятой, если есть дробная часть
                let formatted = points.toFixed(2);
                // Если число целое — убираем .00
                if (formatted.endsWith('.00')) {
                    formatted = formatted.slice(0, -3);
                } else {
                    // убираем завершающие нули, но оставляем один знак, если это не целое
                    formatted = formatted.replace(/\.?0+$/, '');
                    // если после точки ничего не осталось, убираем точку
                    if (formatted.endsWith('.')) formatted = formatted.slice(0, -1);
                }
                if (formatted === '' || formatted === '-') formatted = '0';
                resultDisplay.textContent = formatted;

                // Показываем кнопку "Распределить", если баллы > 0
                const intPoints = Math.floor(points);
                if (intPoints > 0) {
                    distributeAction.classList.add('show');
                } else {
                    distributeAction.classList.remove('show');
                }
            }

            // Обработчик кнопки распределения
            function handleDistribute() {
                // Получаем текущее значение баллов (как число)
                let points = parseFloat(resultDisplay.textContent.replace(/\s/g, ''));
                if (isNaN(points) || points < 0) points = 0;
               
                // Округляем в меньшую сторону до целого
                const intPoints = Math.floor(points);
               
                if (intPoints <= 0) {
                    alert('Нет баллов для распределения. Сначала рассчитайте количество баллов.');
                    return;
                }
               
                // Формируем ссылку и открываем
                const url = `https://forumstatic.ru/files/0006/f5/43/25683.html?points=${intPoints}`;
                window.open(url, '_blank');
            }

            // Обработчик кнопки
            calculateBtn.addEventListener('click', calculateSpellPoints);

            // Обработчик кнопки распределения
            distributeBtn.addEventListener('click', handleDistribute);

            // Обработчик Enter
            function handleKeyPress(e) {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    calculateBtn.click();
                }
            }
            monthsInput.addEventListener('keypress', handleKeyPress);
            hoursInput.addEventListener('keypress', handleKeyPress);

            // При загрузке показываем 0
            window.addEventListener('load', function() {
                if (monthsInput.value.trim() === '' && hoursInput.value.trim() === '') {
                    resultDisplay.textContent = '0';
                    distributeAction.classList.remove('show');
                } else {
                    calculateSpellPoints();
                }
                if (monthsInput.value === '') monthsInput.value = '';
                if (hoursInput.value === '') hoursInput.value = '';
            });

            // Дополнительная защита: если поле пустое, при потере фокуса не трогаем
            function cleanEmpty(e) {
                const val = e.target.value.trim();
                if (val === '.' || val === ',' || val === '') {
                    e.target.value = '';
                }
            }
            monthsInput.addEventListener('blur', cleanEmpty);
            hoursInput.addEventListener('blur', cleanEmpty);
        })();
    </script>
</body>
</html>
[/html]

Отредактировано Лиша (Понедельник, 5 марта, 2018г. 16:45:43)