> For the complete documentation index, see [llms.txt](https://docs.nursultan.fun/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nursultan.fun/scripting-api-ru/eshyo/svoi-komandy.md).

# Свои команды

Скрипт может добавить команду клиента — такую же, как `.party` или `.macros`: белую в чате и с подсказками по Tab.

## Простая команда

```kotlin
command("ping") {
    runs { reply("понг") }
}
```

Готово: `.ping` в чате отвечает «понг».

## Подкоманды

```kotlin
command("home") {
    usage("<set|go|list>")
    alias("h")

    sub("set") {
        usage("<имя>")
        runs {
            storage.put("home." + arg(0), player.position().toString())
            storage.save()
            reply("дом " + arg(0) + " сохранён")
        }
    }

    sub("go") {
        usage("<имя>")
        runs {
            val target = storage.get("home." + arg(0), "")
            if (target.isEmpty()) replyError("нет дома " + arg(0)) else reply("дом тут: " + target)
        }
    }

    sub("list") {
        runs {
            val homes = storage.keys().filter { it.startsWith("home.") }
            reply("домов: " + homes.size)
        }
    }
}
```

`usage` — подсказка в сообщении об ошибке, `alias` — второе имя команды. Подкоманды можно вкладывать друг в друга.

## Аргументы

Внутри `runs { }` доступно:

```kotlin
arg(0)                  // первый аргумент, ошибка если его нет
argOr(0, "по умолчанию")
intArg(0)
doubleArg(0)
booleanArg(0)           // true/on/yes/1 и false/off/no/0
args()                  // все аргументы списком
argCount()
rest()                  // всё после команды одной строкой
rest(1)                 // всё начиная со второго аргумента
label()                 // как команду вызвали
```

`arg(0)` и типизированные варианты сами кидают понятную ошибку, если аргумента нет или он не того вида — писать проверки руками не нужно.

## Ответы

```kotlin
reply("готово")
replyError("так не получится")
```

Оба пишут только тебе.

## Подсказки по Tab

```kotlin
sub("go") {
    completes(0) {
        storage.keys()
            .filter { it.startsWith("home.") }
            .map { it.removePrefix("home.") }
    }
    runs { ... }
}
```

`completes(индекс) { ... }` даёт варианты для одного аргумента. Лямбда вызывается, пока игрок печатает, так что держи её дешёвой — никаких обходов мира и запросов на диск.

Фиксированный список пишется короче:

```kotlin
completes(0, "toggle", "hold", "action")
```

## Занятые имена

Имя команды занимается на весь клиент. Если такое уже есть — у другого скрипта или у самого клиента — регистрация упадёт с понятной ошибкой. Имена сравниваются без регистра, `.Home` и `.home` — одно и то же.

## Команды и переключатель

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