sleeping_root/game/7dots.rpy

951 lines
39 KiB
Plaintext
Raw Normal View History

# чтобы str() не вылетала на линуксе
define mystr = eval("lambda i: '%s' % i")
init -2000 python:
# деление с переводом в целочисленное для нового ренпая
def d2(x, d=2):
return int(x / d)
# префиксы спрайтов, теги в которых нужно делить не пробелами, а "_"
layered_prefixes = []
init:
# масштабирование
transform zoom(zoom=1):
zoom zoom
transform xzoom(zoom=1):
xzoom zoom
transform yzoom(zoom=1):
yzoom zoom
# прозрачность
transform alpha(alpha=1.):
alpha alpha
# размытость
transform blur(blur=4):
blur blur
# яркость
transform brightness(brightness=.25):
matrixcolor BrightnessMatrix(brightness)
# контраст
transform contrast(contrast=1.25):
matrixcolor ContrastMatrix(contrast)
# насыщенность
transform saturation(saturation=1.):
matrixcolor SaturationMatrix(saturation)
# подкрашивание картинок
transform color(color="#000"):
matrixcolor TintMatrix(color)
# спрайт цвета color1 переливается в color2
transform color2(color1="#fff", color2="#def", t=2):
matrixcolor TintMatrix(color1)
ease_quad t*.5 matrixcolor TintMatrix(color2)
ease_quad t*.5 matrixcolor TintMatrix(color1)
repeat
# силуэт цвета color
transform paint(color="#fff"):
matrixcolor TintMatrix(color) * InvertMatrix(1.) * TintMatrix("#000")
# силуэт цвета color1 переливается в color2
transform paint2(color1="#fff", color2="#def", t=2):
matrixcolor TintMatrix(color1) * InvertMatrix(1.) * TintMatrix("#000")
ease_quad t*.5 matrixcolor TintMatrix(color2) * InvertMatrix(1.) * TintMatrix("#000")
ease_quad t*.5 matrixcolor TintMatrix(color1) * InvertMatrix(1.) * TintMatrix("#000")
repeat
# относительное положение
transform xalign(xalign=.5):
xalign xalign
transform yalign(yalign=1.):
yalign yalign
transform align(xalign=.5, yalign=1.):
align (xalign, yalign)
# положение
transform xpos(xpos=.5):
xpos xpos
transform ypos(ypos=.0):
ypos ypos
transform pos(xpos=.5, ypos=.0):
pos (xpos, ypos)
# якорь
transform xanchor(xanchor=.5):
xanchor xanchor
transform yanchor(yanchor=1.):
yanchor yanchor
transform anchor(xanchor=.5, yanchor=1.):
anchor (xanchor, yanchor)
# отзеркаливание
transform hflip(xz=-1.):
xzoom xz
transform vflip(yz=-1.):
yzoom yz
# поворот против часовой
transform rotate(a=45, rotate_pad=True):
rotate_pad rotate_pad
rotate a
# повороты с перспективой
## вверх-вниз
transform turnx(x=45):
perspective True
matrixtransform RotateMatrix(x, 0, 0)
## влево-вправо
transform turny(y=45):
perspective True
matrixtransform RotateMatrix(0, y, 0)
## против часовой-по часовой
transform turnz(z=45):
perspective True
matrixtransform RotateMatrix(0, 0, z)
## по всем направлениям
transform turn(x=0, y=45, z=0):
perspective True
matrixtransform RotateMatrix(x, y, z)
# вырезание
transform crop(x=0, y=0, w=1., h=1.):
crop(x, y, w, h)
# подпрыгивание персонажа
transform leap(dt=.4, dyz=0.01, dxz=0.005):
yzoom 1.
easein dt*0.35 yzoom 1.+dyz xzoom 1.-dxz
easeout dt*0.35 yzoom 1. xzoom 1.
easein dt*0.15 yzoom 1.-dyz xzoom 1.+dxz
easeout dt*0.15 yzoom 1. xzoom 1.
# слева, но не у самого края
transform left2(xa=.35):
anchor (.5, 1.)
align(xa, 1.)
# справа, но не у самого края
transform right2(xa=.65):
anchor (.5, 1.)
align(xa, 1.)
# слева, за краем
transform left0():
anchor (1., 1.)
pos (.0, 1.)
# справа, за краем
transform right0():
anchor (1., 1.)
pos (1., 1.)
# сиськотряс
transform boobs(t=2):
yanchor 0 yzoom 1
easeout (t*.075) yzoom 1.05
easein (t*.1) yzoom .95
easeout (t*.125) yzoom 1.025
easein (t*.125) yzoom .975
easeout (t*.125) yzoom 1.01
easein (t*.15) yzoom .99
easeout (t*.15) yzoom 1.005
easein (t*.15) yzoom 1.
init -2 python:
# единоразовый dismiss
def skip_once():
renpy.end_interaction(True)
SkipOnce = renpy.curry(skip_once)
# остановить перемотку
def skip_stop():
renpy.config.skipping = None
SkipStop = renpy.curry(skip_stop)
# нужно, чтобы включить/отключить dismiss
can_dismiss = True
def dismiss_block():
global can_dismiss
return can_dismiss
# включить dismiss
def dismiss_on():
store.can_dismiss = True
DismissOn = renpy.curry(dismiss_on)
# отключить dismiss
def dismiss_off():
if config.say_allow_dismiss is None:
config.say_allow_dismiss = dismiss_block
store.can_dismiss = False
DismissOff = renpy.curry(dismiss_off)
# для отладки
def log(*args):
for i in args:
print(str(i))
Log = renpy.curry(log)
# эффект вспышки нужного цвета для смены фонов
def flash(color="#fff"):
return Fade(.25, 0, .75, color=color)
# показан ли экран (или один из экранов)
def has_screen(*args):
args = make_list(args)
for i in args:
if renpy.get_screen(i):
return True
return False
# директории для хранение звуков и музыки
audio_dir = config.play_channel
music_dir = "music"
# жёсткая пауза
def pause(t=1, hard=True):
renpy.pause(t, hard=hard)
# получить скриншот заданного размера, по умолчанию весь экран
def shot(w=config.screen_width, h=config.screen_height):
renpy.take_screenshot((w, h))
return FileCurrentScreenshot()
# сканируем папку музыки, на выходе - список мелодий без указанного расширения и папки
def get_music_list(folder=music_dir, 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
# окно игры в центре экрана (вызывается из init)
def window_center():
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
# автоматическое объявление изображений (вызывается из init)
def images_auto(folders=["images"]):
config.automatic_images_minimum_components = 1
config.automatic_images = [' ', '_', '/']
config.automatic_images_strip = folders
# остановить перемотку
def stop_skip():
renpy.config.skipping = None
# строку в displayable
def img2disp(displayable):
if isinstance(displayable, (str, unicode)):
return renpy.displayable(displayable)
return displayable
# узнать текущие размеры изображения типа displayable
# например, после масштабирования и других операций
# не работает в разделе init
def get_size(displayable, w=config.screen_width, h=config.screen_height, st=0, at=0):
w, h = renpy.render(img2disp(displayable), w, h, st, at).get_size()
return int(w), int(h)
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
# автоматическое объявление анимации
# описание функции 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=Dissolve(.1, alpha=True), 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. / 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 = img2disp(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 = img2disp(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)
# показать фон с именем bg указанного цвета color
def bg(color="#000", bg="bg"):
renpy.scene()
renpy.show(bg, what=img2disp(color))
# меняем стандартное время всех или некоторых эффектов для появления/исчезновения спрайтов
def move_time(delay=.5, effects=["move", "ease"]):
effects = make_list(effects)
for i in effects:
define.move_transitions(i, delay)
import datetime
# для цифровых часиков (не менять, не вызывать)
clock_properties = None
def show_digital_clock(st, at):
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, *arg, **kwarg):
renpy.show_screen(screen, _layer="master", *arg, **kwarg)
# убрать экран со слоя "мастер"
def hide_s(screen, **kwarg):
renpy.hide_screen(screen, layer="master", **kwarg)
# добавляем неубирающийся по hide_interface слой
if not "forever" in config.layers:
config.layers.insert(config.layers.index("screens"), "forever")
# показать неубирающийся по нажатию "h" экран
def show_forever(screen):
renpy.show_screen(screen, _layer="forever")
# спрятать неубирающийся по нажатию "h" экран
def hide_forever(screen):
renpy.hide_screen(screen, layer="forever")
# получить английское название времени суток
# если не указывать время в часах,
# то будет взято системное время
# можно задать начало утра, дня, вечера и ночи в часах от 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)]
# удалить все сохранения
def delete_saves_now():
all = renpy.list_saved_games(fast=True)
for i in all:
renpy.unlink_save(i)
renpy.restart_interaction()
DeleteSavesNow = renpy.curry(delete_saves_now)
# удаление всех сохранений с запросом подтверждения
def delete_saves(confirm=True):
if confirm:
layout.yesno_screen(message=_("Удалить все сохранения?"), yes=DeleteSavesNow(), no=NullAction())
else:
delete_saves_now()
DeleteSaves = renpy.curry(delete_saves)
# очистить постоянные данные и сохранения
def delete_data_now():
# удаление сохранений
delete_saves(False)
# удаление ачивок
# achievement.clear_all()
# achievement.sync()
# удаление постоянных данных
persistent._clear(progress=True)
# выход из игры
Quit(confirm=False)()
DeleteDataNow = renpy.curry(delete_data_now)
# удаление всех данных и сохранений с запросом подтверждения
def delete_data(confirm=True):
if confirm:
layout.yesno_screen(message="Удалить все данные?\nИгра будет закрыта.", yes=DeleteDataNow(), no=NullAction())
DeleteData = renpy.curry(delete_data)
# действие - продолжить игру оттуда, где закончили
# если загружать пока нечего, то кнопка неактивна
# 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_images(*args):
res = True
for i in args:
# вместо какой-то картинки может быть список или кортеж
if isinstance(i, (list, dict)):
res = res & has_images(i)
else:
res = res & has_image(i)
return res
# задан ли курсор с таким именем
def has_mouse(mouse):
if config.mouse:
if mouse in config.mouse.keys():
return True
return False
# рандомный элемент из параметров на входе
# просто сокращаем писанину
def rnds(*args):
return renpy.random.choice(args)
# рандомное целое число в заданных пределах
# второй предел НЕ включительно, как в питоне
# (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 - 1))
# рандомное дробное число в заданных пределах
# (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=1, fadeout=1, ext="ogg"):
if name:
renpy.music.play(audio_dir + "/" + name + "." + ext, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)
# костыли для звуков и музыки - сокращают писанину
# можно запускать музыку или звуки, не указывая папки и расширения
# по умолчанию для музыки music/*.ogg
# по умолчанию для звуков audio/*.ogg
# запустить музыку или плейлист
def mplay(mname, fadein=1, fadeout=1, loop=True, channel="music", ext="ogg"):
list = []
mname = make_list(mname)
for i in mname:
list.append(music_dir + "/" + i + "." + ext)
renpy.music.play(list, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)
# запустить музыку или случайно перемешанный плейлист
def rndplay(mname, fadein=1, fadeout=1, loop=True, channel="music", ext="ogg"):
list = make_list(mname)
if len(list) > 1:
renpy.random.shuffle(list)
mplay(list, fadein, fadeout, loop, channel, ext)
# перезапустить музыку, даже если уже играет она же
def mreplay(mname, fadein=1, fadeout=1, loop=True, channel="music", ext="ogg"):
new_fn = music_dir + "/" + mname + "." + ext
renpy.music.play(new_fn, channel=channel, loop=loop, fadein=fadein, fadeout=fadeout)
# запустить музыку для имени файла и пути
def fnplay(new_fn, fadein=1, fadeout=1, channel="music"):
old_fn = renpy.music.get_playing()
if old_fn != new_fn and new_fn:
renpy.music.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, fadeout=1, channel="music"):
if last_music_fn:
fnplay(last_music_fn, fadein=fadein, fadeout=fadeout, channel=channel)
# воспроизвести звук для канала audio, который поддерживает многопоточность
def splay(mname, fadein=0, fadeout=0, channel=config.play_channel, ext="ogg"):
if mname:
mname = make_list(mname)
lst = []
for i in mname:
lst.append(audio_dir + "/" + i + "." + ext)
renpy.play(lst, channel=channel, fadein=fadein, fadeout=fadeout)
# воспроизвести звук
def sndplay(mname, fadein=0, fadeout=0, channel="sound", ext="ogg"):
if mname:
mname = make_list(mname)
lst = []
for i in mname:
lst.append(audio_dir + "/" + i + "." + ext)
renpy.play(lst, 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, channel='music'):
renpy.music.stop(channel=channel, fadeout=fadeout)
# остановить зацикленный эффект
def sfxstop(fadeout=1, channel='effect'):
renpy.music.stop(channel=channel, fadeout=fadeout)
# превращаем функции в action для экранов screen
SPlay = renpy.curry(splay)
SFXPlay = renpy.curry(sfxplay)
SFXStop = renpy.curry(sfxstop)
MPlay = renpy.curry(mplay)
FNPlay = renpy.curry(fnplay)
VPlay = renpy.curry(vplay)
SStop = renpy.curry(sstop)
MStop = renpy.curry(mstop)
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='#'):
if txt:
return re.sub(r'{' + prefix + '([^}]+)}', '', txt)
else:
return txt
# получить тэги и вернуть их в виде списка строк
def get_tags_str(text, prefix='#'):
# выуживаем все теги ремарок
return re.findall('{' + prefix + '([^}]+)}', text)
# разделить строку на две части - до и после знака равно
# (или другого разделителя) и убрать пробелы вокруг этих частей
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()
# нужно включить автоматические сохранения, чтобы работала Continue
config.has_autosave = True
# список спрайтов на экране (не только тегов)
def get_showing_sprites(layer='master'):
images = []
tags = renpy.get_showing_tags(layer)
for i in tags:
tag = i
atrs = renpy.get_attributes(i, layer)
for a in atrs:
tag += " " + a
images.append(tag)
return images
# найти на экране спрайт, содержащий тег
def get_sprite_by_tag(tag, layer='master'):
if tag:
# если среди всех спрайтов на экране
images = get_showing_sprites(layer)
for i in images:
# есть тот, что содержит нужный тэг
if str(tag) in str(i):
return str(i)
# если на экране нет говорящего персонажа
return None
# получить параметры спрайта
def get_sprite_bounds(tag, layer='master'):
# если не нашли спрайт
x, y, w, h = -1, -1, -1, -1
# ищем спрайт на экране
i = get_sprite_by_tag(tag, layer)
# если спрайт на экране
if i:
x, y, w, h = renpy.get_image_bounds(i, layer=layer)
return int(x), int(y), int(w), int(h)
# полное копирование
import copy as dcopy
def copy(*args):
return dcopy.deepcopy(*args)
# БЛОК ДЛЯ РАБОТЫ С ВРЕМЕНАМИ СУТОК
# как пользоваться:
# 1) если есть нужные рисунки, то назвать файлы по временам суток:
# bg_street_night, bg_street_morning и т.д. по списку
# в противном случае будет перекрашиваться основная картинка
# например, "bg street day" или скопированная в неё "bg street"
# первый суффикс в списке времён суток можно и не указывать: bg street
# 2) воспользоваться автоматическим объявлением спрайтов в блоке init:
# $ images_auto()
# 3) указать перфиксы спрайтов, которые будут зависеть от времени суток
# например, чтобы все фоны и все спрайты eileen и pytom зависели от времени суток:
# daytime_prefix = ["bg", "eileen", "pytom"]
# 4) при необходимости задать список времён суток, по умолчанию он:
# alldaytime = ["day", "night"]
# 5) в скрипте просто задавать время суток $ setdaytime("night")
# или переключение на следующее по списку (зациклено): $ setdaytime()
# спрайты на экране сразу поменяются
init:
# настройки нового освещения, на входе сразу матрица
transform daytime_light(matrix):
matrixcolor matrix
transform daytime_empty():
pass
init -99 python:
# список допустимых времён суток
# "night" - обязательно!
alldaytime = ["day", "night"]
# список префиксов-меток для динамических спрайтов,
# освещение которых будет зависеть от времени суток в curdaytime
# например, все фоны и пара героев:
# daytime_prefix = ["bg", "eileen", "pytom"]
# к таким именам будет добавлен суффикс из daytime_suffix
# а потом они будут превращены в динамические уже со своими именами без суффикса
daytime_prefix = []
# настройки каждого времени суток для перекрашивания фонов и спрайтов
# (color, brightness, saturation, contrast)
day_bg_attrs = ("#000", 0, 1, 1)
day_attrs = ("#000", 0, 1, 1)
evening_bg_attrs = ("#9af", -.2, .8, 1)
evening_attrs = ("#9af", 0, .9, 1)
night_bg_attrs = ("#9af", -.475, .375, .575)
night_attrs = ("#9af", -.1, .375, 1)
morning_bg_attrs = ("#fca", .1, 1, 1)
morning_attrs = ("#fca", .1, 1, 1)
# по умолчанию первое в списке время суток
curdaytime = alldaytime[0]
# суффикс для динамических спрайтов - первое в списке время суток
daytime_suffix = alldaytime[0]
# здесь будут храниться имена изменённых спрайтов, зависимых от curdaytime
daytime_suffixed = []
# префикс-метка для фонов
bg_prefix = "bg"
# переключение времени суток на новое или на следующее, если не указывать, на какое
def setdaytime(newdaytime=None, effect=dissolve):
if newdaytime is None:
# если новое время суток == None,
# то переключаемся на следующее в списке (по кругу)
i = alldaytime.index(curdaytime) + 1
if i >= len(alldaytime):
i = 0
newdaytime = alldaytime[i]
if effect:
renpy.show("black", tag="daytimeblack")
renpy.with_statement(effect)
store.curdaytime = newdaytime
if effect:
renpy.hide("daytimeblack")
renpy.with_statement(effect)
# получить трансформ с матрицей для ночного освещения
# по умолчанию для спрайта, True - для фона
def atdaytime(bg=False):
if bg:
key = "_" + bg_prefix + "_"
else:
key = "_"
key = curdaytime + key + "attrs"
attrs = ("#000", 0, 1, 0)
if key in globals().keys():
color, brightness, saturation, contrast = globals()[key]
matrix = BrightnessMatrix(brightness) * ContrastMatrix(contrast) * TintMatrix(color) * SaturationMatrix(saturation)
return daytime_light(matrix)
return daytime_empty()
# БЛОК ДЛЯ ДОПОЛНЕННОГО АВТООБЪЯВЛЕНИЯ СПРАЙТОВ
# стандартное автообъявление картинок, но с webp
# плюс не разбиваются на теги имена, предназначенные для LayerdImage
# вместо этого объединяются через нижний минус "_"
# префиксы, по которым определяются такие имена берутся из layered_prefixes
# выполняется после всего остального
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
# только .png и .jpg и .jpeg и .webp
if not (fn.lower().endswith(".png") or fn.lower().endswith(".jpg") or fn.lower().endswith(".jpeg") or fn.lower().endswith(".webp")):
continue
# убираем расширения и заменяем слеши.
if fn.lower().endswith(".jpeg") or fn.lower().endswith(".webp"):
shortfn = fn[:-5].replace("\\", "/")
else:
shortfn = fn[:-4].replace("\\", "/")
# делим строку на части
name = ( shortfn, )
for sep in seps:
name = tuple(j for i in name for j in i.split(sep))
# выбрасываем имя папок из тегов
while name:
for i in config.automatic_images_strip:
if name[0] == i:
name = name[1:]
break
else:
break
# для проверки префиксов и суффиксов после
# возможной склейки тегов
prefix = name[0]
suffix = name[len(name) - 1]
# убираем суффикс, если это первое время суток
if suffix == daytime_suffix:
name = name[:-1]
# имя без суффикса
name0 = name
# теги одной строкой
sname = " ".join(name)
# не делим на части имена, которые начинаются с префиксов для LayeredImage
layered = False
if prefix in layered_prefixes:
name = "_".join(name)
sname = name
layered = True
# добавляем суффикс по умолчанию, если начинается
# с префикса из списка меток для динамических спрайтов,
# которые будут менять освещение в зависимости от времени суток
if prefix in daytime_prefix:
# нельзя автоматизировать файлы с суффиксами времён суток,
# потому что они станут частью автоматизированного спрайта
if not suffix in alldaytime[1:]:
if not sname in daytime_suffixed:
# запоминаем имя изменённого спрайта
store.daytime_suffixed.append(sname)
# добавляем суффикс
if layered:
name = name + " " + daytime_suffix
else:
name = (*name, daytime_suffix)
# игнорируем, если уже создана одноимённая копия с суффиксом
if name0 in daytime_suffixed:
continue
# игнорируем, если не набирается указанное в переменной количество тегов
if len(name) < config.automatic_images_minimum_components:
continue
# игнорируем, если такой спрайт уже есть
if name in renpy.display.image.images:
continue
# объявляем спрайт
renpy.image(name, fn)
# если заданы параметры, то объявляем спрайты автоматом
if config.automatic_images:
create_automatic_images()
# функция для динамического освещения спрайтов и фонов
def def_daytime(st, at, img):
# ищем картинку для текущего времени суток
new = img + " " + curdaytime
if has_image(new):
return new, None
# если не нашли, то берем основную
new = img + " " + daytime_suffix
# и перекрашиваем в соответствии с настройками
if img.startswith(bg_prefix):
return At(new, atdaytime(True)), None
return At(new, atdaytime()), None
# если заданы параметры, то создаём динамически освещённые спрайты
if len(daytime_suffixed) > 0:
# перебираем все спрайты, для которых нужна реакция на освещение
for i in daytime_suffixed:
# создаём такие спрайты
renpy.image(i, DynamicDisplayable(def_daytime, i))