С помощью **сигналов** можно реагировать на определённые события (и/или запускать их самостоятельно).  
**Таймауты** позволяют вызвать какую-либо функцию через определённое время.  
**Интервалы** позволяют вызывать функцию через определённые промежутки времени.

Всё это работает на уровне питона, т. е. должно быть либо в блоке `python`, либо в команде `$`.

***

## Сигналы

Добавить реакцию на сигнал "event" - выполнить функцию `function`:  
`signals.add("event", function, priority = 0, times = -1)`  
Если на одно событие повешено несколько функций, то сначала выполнится та, что с меньшим приоритетом.
Если 2 функции имеют одинаковый приоритет, то первой будет первая добавленная.  
`times` определяет число вызовов, после которого эта функция будет удалена из реакций на данное событие (`-1` - никогда не удалять).

Пример:
```python
def my_function(arg = "world"):
	out_msg("Hello, %s!" % arg)

signals.add("my_super_event", my_function)
```

Удалить реакцию на событие "event":  
`signals.remove("event", function)`  
Здесь `function` - функция, указанная ранее в `signals.add`.

Отправить сигнал (вызвать все функции, подписанные на "event"):  
`signals.send("event", *args, **kwargs)`  
2 последние аргумента обозначают, что вы можете добавлять какие-угодно аргументы, и они будут переданы вызываемым функциям.

Например: `signals.send("my_super_event", "My Super World")`  
Или даже с именованым параметром: `signals.send("my_super_event", arg="another world")`

При отправке сигнала все функции, реагирующие на этот сигнал, вызываются сразу же.  
Список **стандартных** сигналов - в конце.

***

## Таймауты

Таймауты и интервалы работают примерно также, как и в JS (`javascript` в вашем браузере).

Вызвать `function` через `time_sec` секунд (может быть нецелым числом):  
`my_id = set_timeout(function, time_sec)`  
Результат - идентификатор таймаута (его номер), через который его можно отменить (и это **единственный** способ сделать это).

Отменить вышеуказанную операцию:  
`clear_timeout(my_id)`  
Если вызвать эту функцию несколько раз для одного и того же идентификатора, то это не будет считаться ошибкой.

***

## Интервалы

Интервалы очень похожи на таймауты, но указанная функция вызывается не 1 раз, а постоянно через указанные промежутки времени:  
`my_id = set_interval(function, time_sec)`  
Отмена:  
`clear_interval(my_id)`

***

## Дополнительные пояснения

Вместо функций могут приниматься вызываемые (`callable`) объекты, в том числе такие как `Function`, `AddVariable`, `SetDict` и т. д.  
Однако следует помнить, что все эти функции должны где-то храниться, а значит и уметь сохраняться и восстанавливаться с помощью `pickle`.  
Причём проверка на это занимает какое-то время, так что делать это по тысяче раз за кадр - плохая идея.

Функции таймаутов никогда не выполнятся сразу же - только в следующем кадре, даже если указано выполнить их через `0` секунд.
Таймауты и интервалы реализованы через сигналы, конкретно - через "enter_frame".
Поэтому их точность зависит от текущего FPS (кол-ва кадров в секунду).
При максимальном FPS (`60`) можно рассчитывать на максимальную точность в `16.7` милисекунды (если не будет зависаний по каким-либо причинам).

Таким образом, нельзя рассчитывать на то, что нужные функции будут вызваны милисекунда в милисекунду (или даже в нужный десяток милисекунд).
Также интервал будет вызван между 2 соседними кадрами не более одного раза.

Непонятно зачем, но если вдруг есть реальная причина, то можно создать собственный экземпляр сигналов,
**полностью** независимый от стандартного: `my_signals = Signals()`  
Разумеется, при отправке событий в стандартные сигналы, ваши не будут их получать (на то он и полностью независимый).

***

## Список стандартных сигналов

Общие:
* `"enter_frame"` - "вход" в кадр (перед отрисовкой скринов),
* `"exit_frame"` - "выход" из кадра (после отрисовки всех скринов),
* `"show_screen"` - на экран добавлен какой-то скрин (функция должна принимать 1 аргумент - название скрина),
* `"hide_screen"` - с экрана был скрыт какой-то скрин (функция должна принимать 1 аргумент - название скрина),
* `"resized_stage"` - размер окна был изменён (см. функцию `get_stage_size`).

РПГ-часть:
* `"rpg-location"` - игрок перешёл из одной локации в другую (см. переменные `cur_location` и `cur_location_name`),
* `"rpg-place"` - игрок вошёл в определённое место на локации (см. `cur_place` и `cur_place_name`),
* `"rpg-no_exit"` - игрок попытался перейти туда, куда у него нет доступа (см. систему запретов в РПГ),
* `"rpg-stand_up"` - игрок встал,
* `"rpg-sit_down"` - игрок сел,
* `"rpg-action"` - нажата "кнопка действия".

Инвентарь РПГ-части (функция должна принимать 1 аргумент - название объекта):
* `"inventory-remove"` - выбрасывание предмета из инвентаря,
* `"inventory-using"` - использование предмета в инвентаре,
* `"inventory-taking"` - взятие предмета в инвентарь.

Прочее:
* `"time"` - изменено [время суток](./Времена-суток) (функция должна принимать название нового времени суток),
* `"language"` - был установлен язык игры (см. [Система переводов](./Система-переводов)).
