09 January 2023

Heroes of Might and Magic III: как работает сложная система правил

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

К огромному сожалению, оригинальный код игры так и не стал доступен публично, но так как игра имеет прямо таки культовый статус (особенно в русскоязычном пространстве), собралась команда энтузиастов, которая решила просто взять и переписать игру с нуля, стараясь по максимуму повторять поведение оригинала. Проект называется VCMI engine и я, не без интереса, покопался в его исходниках. Особенно в той части, которая касалась реализации описанных выше "исключений из правил". 

Надо сказать, авторы VCMI подошли к решению вопроса основательно. 

Во-первых, они изначально вели разработку с прицелом на моды. Поэтому все правила игры описываются огромной конфигурацией на основании json файлов, которые полностью описывают и все замки и всех его обитателей вплоть до малейших нюансов. 

Во-вторых, та самая сложная система исключений из правил получила название "бонус" и это стало общим механизмом, пронизывающим все игру насквозь. Свойства любого артефакта это перечень бонусов. Любая особенность монстра это тоже бонус. Скиллы героя это бонусы. И все эти бонусы сведены и описаны в одной огромной таблице. Герой, которые научился ходить по воде, имеет в игре бонус WATER_WALKING. Стреляющий во время битвы монстр отмечен как SHOOTER. А если на него кастанули Forgetfulness, то он получит "бонус" FORGETFULL  и разучится стрелять на определенное время (время жизни -- один из атрибутов бонуса). 

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

Схема распространения бонусов в игре

В итоге, к примеру, Ангелы описаны в конфигурационном файле castle.json таким вот образом:

    "angel" :
    {
        "index": 12,
        "level": 7,
        "faction": "castle",
        "abilities":
        {
            "hateDevils" :
            {
                "type" : "HATE",
                "subtype" : "creature.devil",
                "val" : 50
            },
            "hateArchDevils" :
            {
                "type" : "HATE",
                "subtype" : "creature.archDevil",
                "val" : 50
            },
            "const_raises_morale" :
            {
                "stacking" : "Angels"
            }
        },
        "upgrades": ["archangel"],

Массив abilities как раз и описывает бонусы, например, ненависть к дьяволам имеет бонус типа HATE, subtype указывает класс существ, против которых он работает, а val -- процент дополнительного урона.