## Вывод сообщений и ошибок в окне

`out_msg("from", "error_description")`

Для удобства также выводится весь python-стек и идёт запись всего выведенного текста в лог-файл (`../var/log.txt`).

***

## Моды

Получить кортёж (`tuple`) модов в виде `((name1, dir_name1), (name2, dir_name2), ...)`,
где `name` - название мода, а `dir_name` - название директории, в которой находится мод:  
`get_mods()`

Запуск мода в директории `mod_name`:  
`start_mod("mod_name")`  
Аналогично переход в основное меню:  
`start_mod("main_menu")`  
Немедленный выход из игры (не в меню, а вообще):  
`exit_from_game()`

***

## Размеры окна

Ширина окна игры:  
`get_stage_width()`  
Высота:  
`get_stage_height()`  
Ширина и высота окна:  
`get_stage_size()`  
Установить размер окна в 1366x768:  
`set_stage_size(1366, 768)`

Внимание, переменные `config.width` и `config.height` нужны совсем для других целей, см.
[Авто-масштабирование спрайтов](./Изображения-(ВН-спрайты)#user-content-Авто-масштабирование).

***

## Полноэкранный режим

Развернуть окно на весь экран:  
`set_fullscreen(True)`  
Выйти из полноэкранного режима:  
`set_fullscreen(False)`

***

## Изображения

Загрузить изображение (и обработать im-функциями, если есть) асинхронно, т. е. в отдельном потоке:  
`load_image("image_path")`  
Ширина изображения:  
`get_image_width("image_path")`  
Высота:  
`get_image_height("image_path")`  
Ширина и высота:  
`get_image_size("image_path")`  
Получить пиксель в точке `(x, y)` изображения `"image_path"` (число в формате RGBA, т. е. `0xRRGGBBAA`):  
`get_image_pixel("image_path", x, y)`

***

## Мышь

Получить координаты мыши:  
`get_mouse()`  
Получить координаты мыши относительно кнопки, на которую наведена мышь:  
`get_local_mouse()`  
Узнать, нажата ли левая кнопка мыши:  
`get_mouse_down()`

***

## Параметр из params.conf

Получить параметр `"param"` из файла `params.conf` как тип
`some_type` (один из `str`, `float`, `int` или `bool`):  
`get_from_hard_config("param", some_type)`

***

## FPS

Получить максимальное значение фпс (FPS, Frame Per Second, количество кадров в секунду):  
`get_fps()`  
Установить максимальное значение фпс в `30` (можно поставить любое число от `1` до `60` включительно):  
`set_fps(30)`

***

## ATL

Получить ATL изображения ("список действий"),
зарегистрированного командой `image` (см. начало главы [Изображения](./Изображения-(ВН-спрайты))):  
`get_image("image name")`

Например, если изображение было зарегистрировано так:
```renpy
image bg room = "images/bg/room.jpg"
```

Или так:
```renpy
image bg room:
	"images/bg/room.jpg"
```

То `get_image("bg room")` вернёт в обоих случаях `["images/bg/room.jpg"]`
(конечно, если `default_decl_at` пуст, см. статью про [ATL](./ATL-(анимации-и-трансформации)))

***

## Проверка существования спрайта

Узнать, было ли зарегистрировано изображение командой `image`:  
`image_was_registered("bg room")`

***

## Скрины

Показать скрин с именем `screen_name`:  
`show_screen("screen_name") # или renpy.show_screen`  
Скрыть:  
`hide_screen("screen_name") # или renpy.hide_screen`  
Узнать, отображается ли:  
`has_screen("screen_name")  # или renpy.has_screen`

***

## Метки

Узнать, существует ли метка (`label`) some_label:  
`renpy.has_label("some_label")`  
Прыгнуть (`jump`) на метку some_label:  
`renpy.jump("some_label")`  
Вызвать (`call`) метку some_label:  
`renpy.call("some_label")`  
Последние 2 функции действуют не сразу, а после окончания работы всего питон-кода, в котором они находятся, пример:
```renpy
python:
	print 123
	renpy.jump("some_label") # отмечает, что после этого блока будет выполнен jump на some_label
	print 234 # выхода из питон-блока после renpy.[jump/call] нет, поэтому эта строка тоже отработает
```

***

## Screenshot

Сделать скриншот (по умолчанию вызывается при нажатии на `P` (англ.)):  
`make_screenshot(width = None, height = None)`  
Где `width` и `height` - размеры к которым масштабируется скриншот до сохранения (`None` - не масштабировать).  
Скриншот сохраняется в `var/screenshots/` под именем `screenshotNNNN.png`.

***

## Скрытие курсора мыши

Разрешить/запретить скрывать курсор при бездействии в текущем моде:  
`set_can_mouse_hide(False) # False - не скрывать, по умолчанию - True`  
Используется, например, в главном меню.  
Время устанавливается в `resources/params.conf`.

***

Быстро преобразовать `float` в `int`:  
`ftoi(3.14)`  
Работает заметно быстрее `int(3.14)`.  
Может быть использовано для быстрого отбрасывания дробной частипри отрисовке нескольких тысяч изображений в
[ScreenLang](./ScreenLang).

***

Получить имя папки текущего мода:  
`get_current_mod()`

***

Получить время запуска текущего мода (в секундах, как и `time.time()`):  
`get_mod_start_time()`

***

## Функции для работы со временем.

Если вы попробуете засекать время между кадрами вызовами `time.time()` примерно таким образом:
```python
prev_my_update_time = time.time()
def my_update():
	global prev_my_update_time
	dtime = time.time() - prev_my_update_time
	prev_my_update_time = time.time()
	
	# using <dtime>
```
То в случае перевода системных часов или в случае загрузки сохранения вы получите неадеватные результаты,
ведь между кадрами здесь могут пройти минуты или даже месяцы.  
Для решения этой проблемы у Ren-Engine есть 2 следующих функции.

Получить время между началом текущего и началом прошлого кадров (в секундах):  
`dtime = get_last_tick()`  
Возвращает `0` в `init`-блоках или в случае, если это первый кадр после запуска с нуля или загрузки сохранения.  
Кроме решения проблемы, эта функция также избавляет нас от кучи рутинной возьни.

Получить сумму вызовов `get_last_tick()` для всех предыдущих кадров:  
`get_game_time()`  
Также возвращает `0` во время инициализации (выполнение `init`-блока).  
В некотором роде это аналог для `time.time()` без его вышеописанных недостатков.

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

***

## Текущие файл и строка

Получить путь до текущего файла:  
`get_filename(0)`

Получить номер текущей строки:  
`get_numline(0)`

Получить путь до текущего файла и номер текущей строки:  
`get_file_and_line(0)`

Число `0` здесь означает именно текущее место (при `1` будет место, откуда вызвана текущая функция, и так далее).

Полученный путь может быть использован, к примеру, для построения пути к изображению,
которое лежит рядом с текущим файлом.  
Но вообще эти данные иногда требуются самому движку для более информативного сообщения об ошибке.

***

## Сборка объекта из глобальных функций

`build_object('name')`

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

Пример создания:
```python
def my_map__some_function():
	pass

def my_map__music__play(*args):
	pass

build_object('my_map')
my_map.my_prop = 'my value'
```

`build_object` в данном случае делает примерно следующее:
```python
my_map = Object()
my_map.some_function = my_map__some_function
my_map.music = Object()
my_map.music.play = my_map__music__play
```
После этого доступен для использования объект `my_map` класса `Object`
(не путать со стандартным python-классом `object`),
который допускает (без выкидывания ошибок) обращение к любым свойствам.  
Конечно, это можно делать и вручную, но зачем, если есть специальная функция,
позволяющая делать это одной строчкой кода?

А вот и примеры использования полученного объекта, ничего неожиданного:
```python
my_map.some_function()
my_map.music.play('some_music')

my_map.my_prop += '!'
what = 'prop'
my_map['my_' + what] += '!!' # в квадратных скобках можно "вычислить" название свойства
```

Ещё может возникнуть вопрос, почему бы не делать это с помощью классов или модулей?  
Ну, у модулей в python есть свои недостатки
(например: переусложнённость, циклические зависимости, сложности с сохранением данных).  
С классами же есть 2 выхода, и оба весьма корявы:
1. Создать экземпляр класса (всего 1, что само по себе нетипично и странно) и
постоянно передавать ненужный `self` в методах,
2. Добавить `@staticmethod` к каждому методу и дать классу имя с маленькой буквы
(+`cpickle` отказывается сохранять `staticmethod`, что совсем катастрофично).

Вот и выходит, что одним из самых разумных методов становится создание таких объектов.

***

## Буфер обмена

Получить текст (строка в utf-8) из буфера обмена:  
`s = get_clipboard_text()`

Установить текст в буфер обмена:  
`res = set_clipboard_text("Your Text.")`  
Функция возвращает `True`, если всё прошло удачно и `False` в противном случае.  
Этот результат можно просто проигнорировать, вовсе не записывая его ни в какую переменную.

***

## UTF-8

Ren-Engine ведёт всю работу в кодировке `utf-8`.

Вообще, для работы с текстом
(не просто для копирования одной строки в конец другой, а для разделения её на части или взятия отдельного символа)
было бы неплохо сначала прочесть статью вроде
[этой](https://habr.com/ru/company/xakep/blog/257895/).  
Если кратко, то компьютеры работают с текстом как с набором байт, а человек - как с набором символов.  
`utf-8` - кодировка с переменным кол-вом байт в символе:
* Плюс - существенная экономия памяти,
* Минус - без расчётов нельзя узнать длину строки или подстроки.

Это не касается лишь первых 128 символов (англ. буквы, цифры, знаки препинания, пробелы и т. д.),
но касается всех других языков (на самом деле и многих других значков).

Поэтому в Ren-Engine есть несколько функций для работы с текстом в кодировке `utf-8`:
* `utf8.is_first_byte(byte)` - определить, является ли переданный байт первым в символе.
* `utf8.len(string)` - посчитать (с использованием `utf8.is_first_byte`) длину строки в символах
(обычная `len` даёт размер в байтах).
* `utf8.width(string, text_size)` - посчитать примерную длину `string`, отрисованную шрифтом размера `text_size`.
Внимание - функция не учитывает тэги (вроде `{b}` - полужирности), разный размер разных символов и
принципиальную неопределяемость размеров разных символов шрифта без самого шрифта.
Рекомендуется на всякий случай к полученному значению добавлять число от `20` до `50` (в зависимости от ситуации).

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

***

## Остановка и продолжение сценария

Добавить свою функцию, при возвращении которой значения `False` сценарий будет стоять на месте:  
`can_exec_next_check_funcs.append(your_func)`

Добавить функцию, которая "перематывает" функцию из предыдущего абзаца:  
`can_exec_next_skip_funcs.append(your_func)`

Не для каждой функции, которая "тормозит" сценарий должна быть аналогичная функция для пропуска.  
Например, этим может заниматься связанный по смыслу скрин.  
Однако, рекомендуется максимально избегать принципиальной невозможности пропуска.

Для отладочных целей иногда нужно узнавать: какая именно функция останавливает сейчас сценарий?  
Эта функция записывается в переменную `func_that_stopped_scenario`.  
Её можно посмотреть, просто вставив название в консоль движка (`Shift+O`).

***

## Показывалось ли изображение

`renpy.seen_image('rn happy')`  
Возвращает `True` если показывалось, иначе - `False`.  
Изображение `rn happy` зарегистрировано командой `image` (вроде `image rn happy = "images/sprites/rn/happy.png"`).

***

## Проигрывался ли аудио-файл

`renpy.seen_audio('sound/music/road.ogg')`

***

## Посещалась ли метка

`renpy.seen_label('label_name')`  
Где `label_name` зарегистрирована так:  
```renpy
label label_name:
	# ...
```

***

## Качество масштабирования

По умолчанию задаётся переменной `scale_quality` в файле `resources/params.conf`
(или `var/params.conf`, если было изменение положения или размеров окна).

Если какой-то мод хочет поменять при своём запуске значение этой переменной, это можно сделать так:  
`set_scale_quality('1')`

Значения (строки):
* `'0'` - оставить видимые пиксели ("лесенку") при масштабировании - используется, например, в RPG;
* `'1'` - включить сглаживание ("мыло") - используется, например, в Визуальных Новеллах;
* `'2'` - на данный момент то же самое, что и `'1'` (поведение библиотеки SDL).

Получить текущее значение можно так:  
`get_scale_quality()`

***

## Версия движка

Узнать версию движка можно функцией `get_engine_version()`, которая возвращает строку вроде `0.9.6-2022.10.12`.  
Именно эта версия пишется в лог-файле (`var/log.txt`).

До знака `-` через точку идут номера версий: мажорная, минорная и микро (major, minor, micro).  
После - дата последнего изменения в формате год, месяц и число месяца.

Предполагается, что:
1. Мажорная версия меняется при добавлении значительной функциональности (вроде поддержки 3D), также именно с этими изменениями
будут обычно идти и изменения, ломающие обратную совместимость.
2. Минорная версия меняется при изменениях средней важности, обратная совместимость будет сохраняться почти полностью.
3. Микро предназначена для мелких и незначительных изменений и исправлений.
4. До релиза (версия `1.0`) мажорная версия указывается на месте минорной, а минорная на месте микро;
обратная совместимость же может быть сломана при абсолютно любом изменении.
5. Движок берёт строку версии из файла `Ren-Engine/version`, если его нет или он пуст, то функция возвращает *строку* `"None"`.

***

Также много интересного можно найти в `Ren-Engine/rpy/renpy_api.rpy`.
