Много полезного в одном модуле

Материал из Ren'Py Wiki
Перейти к навигации Перейти к поиску

init:
    # отзеркаливание
    transform hflip():
        xzoom -1.0
    transform vflip():
        yzoom -1.0

    # подпрыгивание персонажа
    transform leap(dyz=0.01, dxz=0.005, dt=.4):
        yzoom 1.0
        easein dt*0.25 yzoom 1.0+dyz xzoom 1.0-dxz
        easeout dt*0.25 yzoom 1.0 xzoom 1.0
        easein dt*0.25 yzoom 1.0-dyz xzoom 1.0+dxz
        easeout dt*0.25 yzoom 1.0 xzoom 1.0

    # относительное положение на экране по х(/y)-координате
    transform at_axy(ax=.5, ay=1.0):
        align (ax, ay)

    # вращение вокруг указанной точки
    transform at_rot(x=0, y=0, delay=30, xa=.5, ya=.5):
        rotate 0.0
        anchor(xa, ya)
        pos(x, y)
        linear delay rotate 360
        repeat

    # слева, но не у самого края
    transform left2(xa=.35):
        xalign xa xanchor .5 ypos 1.0 yanchor 1.0

    # справа, но не у самого края
    transform right2(xa=.65):
        xalign xa xanchor .5 ypos 1.0 yanchor 1.0

    # слева, за краем
    transform left0():
        xpos .0 xanchor 1.0 ypos 1.0 yanchor 1.0

    # справа, за краем
    transform right0():
        xpos 1.0 xanchor .0 ypos 1.0 yanchor 1.0

    # однократное спрайтотрясение
    transform shake(dt=.05, dxy=10, dxy_from=5):
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset rnd(dxy_from, dxy) - rnd(dxy_from, dxy) yoffset rnd(dxy_from, dxy)
        pause dt
        xoffset 0 yoffset 0
        pause dt

    # увеличение/уменьшение в центре экрана
    transform wow(dt=.25, z=1.25):
        anchor(.5, .5) align(.5, .5) zoom 1.0
        easeout dt*.5 anchor(.5, .5) align(.5, .5) zoom z
        easein dt*.5 anchor(.5, .5) align(.5, .5) zoom 1.0
        repeat

    # выстрел по дуге
    transform bow(x1, y1, x2, y2, dy=300, dt=1.0, rot=0):
        pos(x1, y1) anchor(.5, .5) alpha 1.0 rotate 0
        parallel:
            alpha .0
            easein dt*.15 alpha 1.0
            pause dt*.7
            easein dt*.15 alpha .0
        parallel:
            linear dt xpos x2 rotate rot
        parallel:
            easein dt*.5 ypos(-dy+(y1+y2)/2)
            easeout dt*.5 ypos(y2)

init -999 python:
    # сканируем папку музыки, на выходе - список мелодий без указанного расширения и папки
    def get_music_list(folder="music", ext="ogg"):
        res = []
        list = renpy.list_files()
        for i in list:
            if i.startswith(folder):
                s = i[(len(folder) + 1):]
                if s.endswith("." + ext):
                    res.append(s[:(-len(ext) - 1)])
        return res

    # сканируем папку, на выходе - список файлов нужного расширения
    # по умолчанию расширения убираются
    def get_file_list(folder="", ext="", hideext=True):
        res = []
        list = renpy.list_files()
        for i in list:
            if i.startswith(folder) or (not folder):
                if folder:
                    s = i[(len(folder) + 1):]
                else:
                    s = i
                if ext:
                    if s.endswith("." + ext):
                        if hideext:
                            s = s[:(-len(ext) - 1)]
                        res.append(s)
                else:
                    res.append(s)
        if len(res) > 1:
            # сортировка без учета регистра
            res = sorted(res, key=lambda s: s.lower())
        return res

    # получить цвета для матрицы
    def get_rgba(color):
        col = Color(color)
        rgb = col.rgb
        return rgb[0], rgb[1], rgb[2], col.alpha

    # получить спрайт с искажением цветов
    def LiveMatrix(img, matrix):
        return im.MatrixColor(renpy.easy.displayable(img), matrix)

    # получить спрайт с искажением цветов
    def LiveTint(img, r=1.0, g=1.0, b=1.0):
        return LiveMatrix(img, im.matrix.tint(r, g, b))

    # изменить насыщенность
    def LiveBlind(img, blind=.01):
        return LiveMatrix(img, im.matrix.saturation(blind))

    # изменить яркость
    def LiveBright(img, bright=.1):
        return LiveMatrix(img, im.matrix.brightness(bright))

    # силуэт спрайта
    # использовать в init 1901 и выше (после автообъявления изображений)
    def LiveShadow(img, color="#000"):
        r, g, b, a = get_rgba(color)
        return LiveMatrix(img, im.matrix((0, 0, 0, 0, r, 0, 0, 0, 0, g, 0, 0, 0, 0, b, 0, 0, 0, a, 0,)))

    # выстрел снарядом shell от перса spr_from к персу spr_to
    # по дуге высотой -dy
    def shoot(shell, spr_from, spr_to, dy=300, dt=1.0, rot=0, shell_as=None):
        if shell_as is None:
            shell_as = shell
        if spr_from == "left":
            x1, y1 = 0, config.screen_height / 2
        elif spr_from == "right":
            x1, y1 = config.screen_width / 2, config.screen_height / 2
        else:
            x, y, w, h = renpy.get_image_bounds(spr_from)
            x1, y1 = int(x + w/2), int(y + h/2)
        if spr_to == "left":
            x2, y2 = 0, config.screen_height / 2
        elif spr_to == "right":
            x2, y2 = config.screen_width / 2, config.screen_height / 2
        else:
            x, y, w, h = renpy.get_image_bounds(spr_to)
            x2, y2 = int(x + w/2), int(y + h/2)
        renpy.show(shell_as, what=shell, at_list=[bow(x1, y1, x2, y2, dy, dt, rot)])
        renpy.pause(dt)

    # сменить размер шрифта в игре
    # вызывать из init -1 python, не раньше
    def font_size(say=26, who=None, prf=None, mm=None):
        style.say_dialogue.size = say # текст в текстбоксе
        style.say_thought.size = say # текст в текстбоксе
        if not who is None:
            style.say_label.size = who # имя персонажа
        if not prf is None:
            # интерфейс (настройки и сохранения)
            style.pref_label_text.size = prf
            style.pref_button_text.size = prf
            style.small_button_text.size = prf
            style.large_button_text.size = prf
            style.file_picker_text.size = prf
            style.file_picker_button_text.size = prf
            style.file_picker_nav_button_text.size = prf
            style.button_text.size = prf # текст на кнопках
            style.label_text.size = prf # надписи
        if not mm is None:
            style.mm_button_text.size = mm # кнопки главного меню
        # применяем изменения
        style.rebuild()

    # окно игры в центре экрана (вызывается из init)
    def window_center():
        import os
        os.environ['SDL_VIDEO_CENTERED'] = '1'

    # автоматическое объявление изображений (вызывается из init)
    def images_auto(folders=["images", "gui"]):
        config.automatic_images_minimum_components = 1
        config.automatic_images = [' ', '_', '/']
        config.automatic_images_strip = folders

    # остановить перемотку
    def stop_skip():
        renpy.config.skipping = None

    # узнать текущие размеры изображения типа displayable
    # например, после масштабирования и других операций
    # не работает в разделе init
    def get_size(displayable):
        return renpy.render(renpy.easy.displayable(displayable), 0, 0, 0, 0).get_size()
    def get_width(displayable):
        return get_size(displayable)[0]
    def get_height(displayable):
        return get_size(displayable)[1]

    # если это не список, то сделать единственным элементом списка
    def make_list(param):
        if param is None:
            return None
        if not isinstance(param, list):
            param = [param]
        return param

    # эффект dissolve, но с учетом прозрачности спрайта. пример:
    # with diss
    diss = Dissolve(.1, alpha=True)
    diss25 = Dissolve(.25, alpha=True)

    # эффект вспышки нужного цвета для смены фонов. пример:
    # with flash("#822")
    def flash(color="#fff", t=1.0, w=0):
        return Fade(t*.25, w, t*.75, color=color)

# автоматическое объявление анимации
    # описание функции Ani:
    # автоматическое объявление картинки с анимацией,
    # например есть кадры "images/neko%s.png",
    # где %s - числа от 1 до 5, тогда объявляем анимацию так:
    # image neko = Ani("neko", 5, 0.5, reverse = False)
    # где:
    # img_name - имя файла без номера (например, "neko")
    # frames - количество кадров
    # delay - пауза между кадрами в секундах
    # если delay это кортеж, например (1, 2), то скорость будет меняться от 1 до 2 секунд
    # loop - зациклить анимацию (по умолчанию включено)
    # reverse - нужно ли проигрывание анимации в обратную сторону
    # effect - эффект для смены кадров
    # start - с какой цифры начинать отсчет кадров
    # ext - расширение, если оно отлично от Null, то работаем с файлами,
    # при ext=Null - с displayable (уже объявленными или даже измененными изображениями)
    # так же можно добавлять любые стандартные для изображений параметры, типа масштабирования или прозрачности:
    # image neko = Ani("neko", 5, 0.5, zoom=2.0, alpha=0.75)
    def Ani(img_name, frames, delay=.1, loop=True, reverse=False, effect=diss, start=1, ext=None, **properties):
        args = []
        # если пауза переменная, то вычисляем ее шаг
        if isinstance(delay, tuple):
            d0 = delay[0]
            d1 = delay[1]
            f = (frames - 1)
            if f <= 0:
                dp = 0
            else:
                dp = (d1 - d0) * 1.0 / f
            delay = d0
        else:
            dp = 0
        # перебираем все кадры анимации
        for i in range(start, start + frames):
            if ext:
                img = renpy.display.im.image(img_name + str(i) + "." + ext)
            else:
                img = renpy.easy.displayable(img_name + str(i))
            img = Transform(img, **properties)
            args.append(img)
            if reverse or loop or (i < start + frames - 1):
                args.append(delay)
                delay += dp
                # добавляем эффект для смены кадров
                args.append(effect)
        if reverse: # обратная анимация, если нужна
            dp = -dp
            delay += dp
            for i in range(start + frames - 2, start, -1):
                if ext:
                    img = renpy.display.im.image(img_name + str(i) + "." + ext)
                else:
                    img = renpy.easy.displayable(img_name + str(i))
                img = Transform(img, **properties)
                args.append(img)
                if loop or (i > start + 1):
                    args.append(delay)
                    delay += dp
                    args.append(effect)
        return anim.TransitionAnimation(*args)

    # анимированная текстура с вырезанием по маске
    def AniMask(mask_name, img_name, frames, delay=.1, loop=True, reverse=False, effect=diss, start=1, ext=None, **properties):
        args = []
        # если пауза переменная, то вычисляем ее шаг
        if isinstance(delay, tuple):
            d0 = delay[0]
            d1 = delay[1]
            f = (frames - 1)
            if f <= 0:
                dp = 0
            else:
                dp = (d1 - d0) * 1.0 / f
            delay = d0
        else:
            dp = 0
        # перебираем все кадры анимации
        for i in range(start, start + frames):
            if ext:
                img = renpy.display.im.image(img_name + str(i) + "." + ext)
            else:
                img = renpy.easy.displayable(img_name + str(i))
            img = AlphaMask(img, renpy.easy.displayable(mask_name))
            img = Transform(img, **properties)
            args.append(img)
            if reverse or loop or (i < start + frames - 1):
                args.append(delay)
                delay += dp
                # добавляем эффект для смены кадров
                args.append(effect)
        if reverse: # обратная анимация, если нужна
            dp = -dp
            delay += dp
            for i in range(start + frames - 2, start, -1):
                if ext:
                    img = renpy.display.im.image(img_name + str(i) + "." + ext)
                else:
                    img = renpy.easy.displayable(img_name + str(i))
                img = AlphaMask(img, renpy.easy.displayable(mask_name))
                img = Transform(img, **properties)
                args.append(img)
                if loop or (i > start + 1):
                    args.append(delay)
                    delay += dp
                    args.append(effect)
        return anim.TransitionAnimation(*args)

    # показать фон с именем bg указанного цвета color
    def bg(color="#000", bg="bg"):
        renpy.scene()
        renpy.show(bg, what=renpy.easy.displayable(color))

    # меняем стандартное время всех или некоторых эффектов для появления/исчезновения спрайтов
    def move_time(delay=.5, effects=["move", "ease"]):
        effects = make_list(effects)
        for i in effects:
            define.move_transitions(i, delay)

    # для цифровых часиков (не менять, не вызывать)
    clock_properties = None
    def show_digital_clock(st, at):
        import datetime
        cur_time = datetime.datetime.now().strftime("%H:%M:%S")
        img = Text(cur_time, **clock_properties)
        return img, .25

    # создать цифровые часики с любым именем картинки (только в init!):
    # $ create_clock("digital_clock", size=48, color="#fff8", outlines=[(2, "#0008", 0, 0)], align=(.05, .05))
    # применение - на любом экране screen:
    # add "digital_clock"
    # или в виде спрайта:
    # show digital_clock
    def create_clock(name, **properties):
        global clock_properties
        clock_properties = properties
        renpy.image(name, DynamicDisplayable(show_digital_clock))

    # показать экран на слое "мастер",
    # чтобы он не исчезал, когда прячем интерфейс
    def show_s(screen):
        renpy.show_screen(screen, _layer="master")

    # убрать экран со слоя "мастер"
    def hide_s(screen):
        renpy.show_screen(screen, layer="master")

    # показать рамку, неубирающуюся вместе с другими экранами
    # вызов: $ show_forever("имя_картинки_для_рамки")
    def show_forever(forever_frame):
        renpy.show_screen("forever_screen", forever_frame, _layer="foreverlayer")

    # спрятать рамку, неубирающуюся вместе с другими экранами
    def hide_forever():
        renpy.hide_screen("forever_screen", layer="foreverlayer")

    # получить английское название времени суток
    # если не указывать время в часах,
    # то будет взято системное время
    # можно задать начало утра, дня, вечера и ночи в часах от 0 до 23
    def time_of_day(hours=None, morning=7, day=11, evening=18, night=23):
        if hours is None:
            hours = int(datetime.datetime.now().strftime("%H"))
        res = "night" # по умолчанию ночь
        # границы любого времени суток можно поменять
        if (hours >= morning) and (hours <= day):
            res = "morning"
        if (hours > day) and (hours <= evening):
            res = "day"
        if (hours > evening) and (hours < night):
            res = "evening"
        return res

    # словарь цветов для времен суток
    color_filters = {"morning": "#8404", "day": "#0000", "evening": "#0484", "night": "#000b"}

    # получить цвет фильтра, соответствующий времени суток
    def color_of_day(hours=None):
        return color_filters[time_of_day(hours)]

    # действие - продолжить игру оттуда, где закончили
    # если загружать пока нечего, то кнопка неактивна
    # textbutton _("Продолжить игру") action Continue()
    class Continue(Action, DictEquality):
        def __call__(self):
            FileLoad(1, confirm=False, page="auto", newest=True)()
        # кликабельность кнопки
        def get_sensitive(self):
            return FileLoadable(1, page="auto")

    # объявлена ли картинка с именем name
    def has_image(name):
        for i in renpy.display.image.images:
            # такая конструкция позволяет исключить пустые теги
            if name == " ".join(" ".join(i).split()):
                return True
        return False

    # задан ли курсор с таким именем
    def has_mouse(mouse):
        if config.mouse:
            if mouse in config.mouse.keys():
                return True
        return False

    # рандомное целое число в заданных пределах
    # (i_to можно не указывать, тогда максимум берется из i_from)
    def rnd(i_from=0, i_to=None):
        if i_to is None:
            i_to = i_from
            i_from = 0
        return renpy.random.randint(int(i_from), int(i_to))

    # рандомное дробное число в заданных пределах
    # (f_to можно не указывать, тогда максимум берется из f_from)
    def rndf(f_from=0, f_to=None):
        if f_to is None:
            f_to = f_from
            f_from = .0
        return f_from + renpy.random.random() * (f_to - f_from)

    # канал для эффекта
    renpy.music.register_channel("effect", "sfx", loop=True)

    # зацикленный звуковой эффект, не музыка
    def sfxplay(name, channel="effect", loop=True, fadein=0, fadeout=0, ext="ogg"):
        if name:
            renpy.music.play("sounds/" + name + "." + ext, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)

    # костыли для звуков и музыки - сокращают писанину
    # можно запускать музыку или звуки, не указывая папки и расширения
    # по умолчанию для музыки music/*.ogg
    # по умолчанию для звуков sounds/*.ogg

    # запустить музыку, если она еще не играет
    def mplay(mname, fadein=1.5, fadeout=1.5, loop=True, channel="music", ext="ogg"):
        old_fn = renpy.music.get_playing()
        new_fn = "music/"+ mname + "." + ext
        if mname:
            if old_fn != new_fn:
                renpy.music.play(new_fn, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)

    # перезапустить музыку, даже если уже играет она же
    def mreplay(mname, fadein=1.5, fadeout=1.5, loop=True, channel="music", ext="ogg"):
        new_fn = "music/"+ mname + "." + ext
        renpy.play(new_fn, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)

    # запустить музыку для имени файла и пути
    def fnplay(new_fn, fadein=1.5, fadeout=1.5, channel="music"):
        old_fn = renpy.music.get_playing()
        if old_fn != new_fn and new_fn:
            renpy.play(new_fn, channel=channel, loop=True, fadein=fadein, fadeout=fadeout)

    # последняя сохраненная мелодия
    last_music_fn = ""

    # сохранить в памяти играющую мелодию
    def msave():
        global last_music_fn
        last_music_fn = renpy.music.get_playing()

    # восстановить игравшую при сохранении мелодию
    def mrestore(fadein=1.5, fadeout=1.5, channel="music"):
        fnplay(last_music_fn, fadein=fadein, fadeout=fadeout, channel=channel)

    # воспроизвести звук для канала audio, который поддерживает многопоточность
    def splay(mname, fadein=0, fadeout=0, channel="audio", ext="ogg"):
        if mname:
            renpy.play("sounds/" + mname + "." + ext, channel=channel, fadein=fadein, fadeout=fadeout)

    # воспроизвести звук
    def sndplay(mname, fadein=0, fadeout=0, channel="sound", ext="ogg"):
        if mname:
            renpy.play("sounds/" + mname + "." + ext, channel=channel, fadein=fadein, fadeout=fadeout)

    # голос
    def vplay(mname, fadein=0, fadeout=0, channel="voice", ext="ogg"):
        if mname:
            renpy.play("voices/" + mname + "." + ext, channel=channel, fadein=fadein, fadeout=fadeout)

    # остановить звук
    def sstop(fadeout=None, channel='audio'):
        renpy.music.stop(channel=channel, fadeout=fadeout)

    # остановить звук
    def sndstop(fadeout=0, channel='sound'):
        renpy.music.stop(channel=channel, fadeout=fadeout)

    # остановить музыку
    def mstop(fadeout=1.5, channel='music'):
        renpy.music.stop(channel=channel, fadeout=fadeout)

    # остановить зацикленный эффект
    def sfxstop(fadeout=1.5, channel='effect'):
        renpy.music.stop(channel=channel, fadeout=fadeout)

    # превращаем функции в action для экранов screen
    SPlay = renpy.curry(splay)
    SFXPlay = renpy.curry(sfxplay)
    MPlay = renpy.curry(mplay)
    FNPlay = renpy.curry(fnplay)
    VPlay = renpy.curry(vplay)
    SStop = renpy.curry(sstop)
    MStop = renpy.curry(mstop)

    # установить громкость канала в коэффициенте от громкости звуков
    def sfxvolume(volume=1.0, channel='effect', delay=1.0):
        volume = _preferences.get_volume('sfx') * volume
        if volume < 0:
            volume = 0
        if volume > 1.0:
            volume = 1.0
        renpy.music.set_volume(volume, delay, channel=channel)

    import re

    def get_tags(text, prefix='#'):
        res = {}
        # выуживаем все теги ремарок
        tags = re.findall('{' + prefix + '([^}]+)}', text)
        # перебираем полученные теги
        for i in tags:
            parts = i.split('=')
            if len(parts) > 0:
                key = parts[0].strip()
                val = None
                if len(parts) > 1:
                    val = parts[1]
                # добавляем тэг и его значение в словарь
                res[key] = val
        # возвращаем значения тэгов в виде словаря
        return res

    # убрать все тэги из строки
    def del_tags(txt, prefix='#'):
        return re.sub(r'{' + prefix + '([^}]+)}', '', txt)

    # разделить строку на две части - до и после знака равно
    # (или другого разделителя) и убрать пробелы вокруг этих частей
    def get_key_val(text, sep='='):
        txt = text.split(sep, 1)
        val, key = None, None
        if len(txt) > 0:
            key = txt[0].strip()
        if len(txt) > 1:
            val = txt[1].strip()
        return key, val

    # поиск в строке значения невидимого читателю тега
    # пример использования:
    # $ text = "Текст текст {#image=logo.png} текст."
    # $ img = get_tag(text, 'image')
    # на выходе в img будет logo.png
    def get_tag(text, tag, default=None, prefix='#'):
        tag = tag.strip()
        tags = get_tags(text, prefix)
        if tag in tags.keys():
            return tags[tag]
        return None

    # есть ли тэг в строке
    def have_tag(text, tag, prefix='#'):
        return tag in get_tags(text, prefix).keys()

    # получить цвета для матрицы
    def get_rgba(color):
        col = Color(color)
        rgb = col.rgb
        return rgb[0], rgb[1], rgb[2], col.alpha

    # показать спрайт с искажением цветов
    def LiveMatrix(img, matrix):
        return im.MatrixColor(renpy.easy.displayable(img), matrix)

    # изменить насыщенность
    def LiveBlind(img, blind=.01):
        return LiveMatrix(img, im.matrix.saturation(blind))

    # силуэт спрайта
    def LiveShadow(img, color="#000"):
        r, g, b, a = get_rgba(color)
        return LiveMatrix(img, im.matrix((0, 0, 0, 0, r, 0, 0, 0, 0, g, 0, 0, 0, 0, b, 0, 0, 0, a, 0,)))

    # список слоев. наш экран не будет исчезать при нажатии 'h'
    config.layers.insert(config.layers.index("transient") + 1, "foreverlayer")

    # нужно включить автоматические сохранения, чтобы работала Continue (подставить = True)
    config.has_autosave = False

    # для input
    current_input_text = ""
    input_changes = False

    # функция вызова поля ввода с кнопками ок и отмена. пример:
    # $ s = input("Введите имя:", default="Аноним")
    def input(prompt=None, default=None, allow=None, caption_bg=None):
        global current_input_text, input_changes
        input_changes = False
        current_input_text = ""
        ShowMenu("my_input", prompt, default, allow, caption_bg=caption_bg)()
        if current_input_text is None:
            return None
        if not input_changes:
            current_input_text = default
        return current_input_text
    Input = renpy.curry(input)

    # функция вызова сообщения с кнопкой ок. пример:
    # $ message("Всё в норме.", size=26, color="#8a8")
    def message(message_text=" ", **args):
        ShowMenu("my_message", message_text, **args)()
    Message = renpy.curry(message)

    # узнать, что за символ введён или стёрт
    def input_changed(input_str):
        global current_input_text, input_changes
        current_input_text = input_str
        input_changes = True

init 1 python:
    # параметры текста для ввода
    style.input_text.xalign = .5
    style.input_text.font = style.say_dialogue.font
    style.input_text.size = style.say_dialogue.size

# экран ввода с кнопками ок и отмена
screen my_input(prompt=None, default=None, allow=None, caption_bg=None):
    modal True
    tag menu
    window style "gm_root":
        background "#0008" # необязательное затемнение экрана
        key "dismiss" action []
        key "input_enter" action Return()
        key "K_ESCAPE" action [SetVariable("current_input_text", None), Return()]
        frame:
            style_group "yesno"
            align (.5, .5)
            vbox align (.5, .5):
                spacing config.screen_width / 60
                if prompt:
                    frame:
                        if caption_bg:
                            background caption_bg
                        align (.5, .0) xminimum config.screen_width / 4
                        label prompt style "pref_label" xalign .5
                input id "input" style "input_text" changed input_changed default default allow allow
                hbox xalign .5:
                    textbutton _("OK") xalign .5 action Return()
                    textbutton _("Отмена") xalign .5 action [SetVariable("current_input_text", None), Return()]

# экран сообщения с кнопкой ок
screen my_message(message_text=" ", **args):
    modal True
    tag menu
    window style "gm_root":
        key "dismiss" action []
        key "input_enter" action Return()
        key "K_ESCAPE" action Return()
        frame:
            style_group "yesno"
            align (.5, .5)
            vbox align (.5, .5):
                spacing config.screen_width / 60
                xminimum config.screen_width / 4
                text " "
                label message_text style "pref_label" xalign .5
                textbutton _("OK") xalign .5 action Return()
                text " "

# экран для неубирающейся рамки
screen forever_screen (forever_frame, _layer="foreverlayer"):
    # выводится, если это игра, но не экран настроек
    if not ("preferences" in renpy.current_screen().screen_name):
        add forever_frame

# стандартное автообъявление картинок, но с webp
# выполняется после всего остального
init 1900 python hide:
    def create_automatic_images():
        seps = config.automatic_images
        if seps is True:
            seps = [ ' ', '/', '_' ]
        for dir, fn in renpy.loader.listdirfiles():
            if fn.startswith("_"):
                continue
            # Only .png and .jpg and .webp
            if not fn.lower().endswith(".png") and not fn.lower().endswith(".jpg") and not fn.lower().endswith(".webp"):
                continue
            # Strip the extension, replace slashes.
            shortfn = fn[:-4]
            if fn.lower().endswith(".webp"):
                shortfn = fn[:-5]
            shortfn = shortfn.replace("\\", "/")
            # Determine the name.
            name = ( shortfn, )
            for sep in seps:
                name = tuple(j for i in name for j in i.split(sep))
            # Strip name components.
            while name:
                for i in config.automatic_images_strip:
                    if name[0] == i:
                        name = name[1:]
                        break
                else:
                    break
            # Only names of 2 components or more by default.
            if len(name) < config.automatic_images_minimum_components:
                continue
            # Reject if it already exists.
            if name in renpy.display.image.images:
                continue
            renpy.image(name, fn)
    if config.automatic_images:
        create_automatic_images()

Источник: Renpy для чайников: Много полезного в одном модуле


На главную страницу Книга рецептов Энциклопедии Ren'Py Renpy для чайников Вернуться к началу статьи