Скрипты для Dota 2 чаще всего пишут, чтобы оживлять кастомки: менять поведение юнитов, делать события в матчах, связывать UI с логикой и запускать всё это на сервере игры. Если вы никогда не программировали, это всё равно реально, просто нужно начать с правильной базы: где лежит код, как он подключается и как читать примеры.

Ниже - практичный маршрут от нуля до первого работающего скрипта на Lua.


Что именно вы “создаёте” в Dota 2

В кастомном проекте Dota 2 код обычно разделён на несколько частей:

  • Материал/карта/контент (не код, но без этого кастомка не взлетит)
  • Lua-скрипты (логика)
  • NPC TXT (описания героев, способностей, предметов и т.д. для аддона)
  • UI (интерфейс), который общается с серверной частью через команды

По сути, ваша задача - собрать аддон так, чтобы движок нашёл нужные файлы и вызвал ваши функции в нужный момент игры.


Подготовка: что скачать и где что лежит

Установите Dota 2 Workshop Tools DLC

В Steam:
1. Откройте библиотеку Dota 2
2. В свойствах включите Dota 2 Workshop Tools DLC
3. Запустите инструменты: Launch Dota 2 - Tools

Возьмите “пустую базу” для кастомок (barebones)

Часто для старта используют базовый шаблон, чтобы не городить всё с нуля.

  • barebones: https://github.com/bmddota/barebones

Дальше обычно делают так: распаковывают barebones и переносят содержимое в корень вашей Dota 2 tools-папки (все точные пути зависят от версии, но логика одна - чтобы мод подтянулся движком).


Первый большой шаг: создание кастомной карты и запуск tools

  1. В инструментах откройте Asset Browser
  2. Откройте Hammer (Map Editor)
  3. File > New
  4. Создайте .vmap в папке вашей кастомки
  5. Убедитесь, что редактор позволяет вам двигаться и ориентироваться (в некоторых ситуациях помогает переключить раскладку на английскую)

Смысл на этом этапе простой: вы должны увидеть, что кастомка вообще грузится и работает в окружении Workshop Tools.


Где писать Lua: папки и точки входа

В Dota 2 (кастомки) серверная Lua-логика обычно лежит в папке аддона:

  • your_name_addon/scripts/vscripts/

Там движок ожидает точки входа, и на практике почти всё стартует так:

  • addon_init.lua - первичная настройка
  • addon_game_mode.lua - инициализация игрового режима
  • ваши основные файлы (например addon_main.lua) - где хранится логика проекта

Идея такая: addon_init.lua подключает остальные файлы через require, а addon_game_mode.lua создаёт объект мода и запускает его.

Опорный материал по структуре инициализации:
- Valve: https://developer.valvesoftware.com/wiki/Ru/Dota_2_Workshop_Tools/Scripting/Getting_Started

(Если сайт не открылся из-за защиты, ориентируйтесь на логику и примеры из других гайдов и на структуру ваших файлов.)


Минимальный каркас: addon_init.lua и addon_game_mode.lua

addon_init.lua

Типовой паттерн - сделать require для ваших модулей:

require("util")
require("addon_main")

Если вы копируете готовые примеры, не бойтесь - в начале вам важнее понять “где что подключается”, чем сразу строить систему.

addon_game_mode.lua

Тут обычно создают экземпляр режима и вызывают инициализацию:

local gameMode = CustomGameMode:new()
gameMode:InitGameMode()

“Ядро” аддона: addon_main.lua и Think

В addon_main.lua обычно держат ваш объект игрового режима.

Ключевые элементы:
- конструктор объекта
- метод InitGameMode()
- “мыслитель” Think(), который периодически выполняется

Пример из гайдов по моддингу показывает типичную механику:
- ищем dota_base_game_mode
- назначаем SetThink
- в Think возвращаем интервал до следующего вызова

Смысл: вы задаёте циклическую логику, чтобы что-то происходило в игре регулярно.


События и команды: как связывать логику и UI

Это то, без чего многие скрипты не “ощущаются живыми”.

События (Game Events)

События - это когда в движке произошло что-то важное (например игрок получил уровень), и вы ловите это событие.

Шаблон:
- ListenToGameEvent(...)
- обработчик-функция получает keys

Пример подхода:
- слушаете dota_player_gained_level
- в обработчике проверяете уровень игрока
- меняете золото, выдаёте награду и т.п.

Команды (Convars:RegisterCommand)

Команды - удобный мост “UI -> Lua”.
UI вызывает команду в консоли сервера, а Lua обрабатывает её и делает нужное.

Логика такая:
- регистрируете команду
- в обработчике получаете параметр
- находите нужного игрока/героя
- меняете состояние


NPC TXT: когда без этого не обойтись

Если вы планируете менять способности/героев/предметы кастомки, часть описаний задаётся через файлы в стиле:

  • npc_abilities_custom.txt
  • npc_heroes_custom.txt
  • npc_items_custom.txt
  • npc_units_custom.txt

Эти файлы не заменяют Lua, они задают “данные”, которые Lua затем использует или на которые вы опираетесь через скрипты способностей/юнитов.

Ориентир по месту и роли файлов есть в гайдах по скриптингу на customgames.ru (и в их структуре для начинающих).


Практика без боли: как учиться писать скрипт, а не просто “копировать”

Вот рабочая последовательность, которая реально помогает.

Шаг 1. Скопируйте минимальный пример аддона

Не пытайтесь сразу сделать “большую систему”. Сначала добейтесь, чтобы:
- кастомка грузилась
- ваш InitGameMode вызывался
- Think реально выполнялся (часто это видно по print в логах)

Шаг 2. Добавьте 1-2 события и отследите, что обработчик срабатывает

Например:
- выдайте золото при достижении уровня 6
- выведите в консоль, что событие пришло

Шаг 3. Свяжите UI и Lua через command

Сделайте кнопку в интерфейсе и пусть она вызывает команду, а Lua меняет параметр героя.

Шаг 4. Дальше уже разбирайте детали

Только после того, как вы поняли “как оно работает”:
- переходите к более сложной архитектуре
- подключайте утилиты
- выносите логику в отдельные модули


Самое частое “почему не работает”: короткий чек-лист

Симптом Частая причина Что проверить
Скрипт вообще не выполняется Неверно указаны пути и файлы не подхватились движком Убедитесь, что Lua лежит в scripts/vscripts, а точки входа (addon_init.lua, addon_game_mode.lua) существуют
require не находит файл Имя модуля не совпадает с файлом или неверная папка Проверьте названия: require("addon_main") должен соответствовать addon_main.lua
Ничего не происходит в игре Think не назначен или интервал/вызов некорректный Убедитесь, что SetThink стоит и Think возвращает интервал
UI вызывает команду, но эффекта нет Команда не зарегистрирована или параметр не тот Проверьте Convars:RegisterCommand(...) и обработчик, а также тип параметра
Событие не ловится Неправильное имя события или обработчик не подписан Проверьте ListenToGameEvent(...) и используйте корректный event name

Ресурсы, на которые стоит опираться

  • Valve - Getting Started по scripting в Workshop Tools:
    https://developer.valvesoftware.com/wiki/Ru/Dota_2_Workshop_Tools/Scripting/Getting_Started
  • CustomGames - “Скриптинг Dota 2 — руководство для начинающих” (с разбором структуры аддона и мест, куда писать код):
    https://customgames.ru/forum/threads/%D0%A1%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3-dota-2-%E2%80%94-%D1%80%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%B4%D0%BB%D1%8F-%D0%BD%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D1%8E%D1%89%D0%B8%D1%85.1684/
  • Примерные учебные материалы с кодом и объяснениями по Lua-системе (как дополнение к каркасу):
    https://xgm.guru/p/blog-sleep/132844

Итог: что нужно, чтобы реально начать создавать скрипты для Dota

Вам не нужен “идеальный набор знаний”. Вам нужны три вещи:
- правильно разложить аддон и найти, где именно писать Lua-скрипт
- понять точки входа (addon_init.lua, addon_game_mode.lua) и как запускается ваш Think/логика
- научиться ловить события и делать взаимодействие с UI через команды

Когда это заработало, дальше уже можно наращивать функциональность шаг за шагом: события, способности, предметы, логика лобби, генерация контента и т.д.