WTS/game/scripts/interface/book.rpy

273 lines
8.9 KiB
Plaintext

init python:
class book_readable_class(object):
def __init__(self, title, contents=(), **kwargs):
self.title = title
self.page = 0
self.overflow=None
self.title = title
self.contents = list(contents) # list of (title, text) pairs
self.__dict__.update(**kwargs)
self.npages = len(self.contents)
@property
def maxpage(self):
# maximum value for the `page` attribute
if self.npages %2:
return self.npages-1
return self.npages-2
def open(self, page=0):
self.page = max(0, min(page, self.maxpage))
self.refresh()
return
def close(self):
self.page = 0
renpy.hide_screen("book_menu")
return
def next(self):
self.page = min(self.page+2, self.maxpage)
self.refresh()
return
def prev(self):
self.page = max(self.page-2, 0)
self.refresh()
return
def refresh(self):
page_title, page_text = self.contents[self.page]
page_text = page_text[:880]
if self.npages > self.page+1:
next_page_title, next_page_text = self.contents[self.page-1]
next_page_text = next_page_text[:880]
else:
next_page_title, next_page_text = None, None
renpy.show_screen("book_menu",
page=self.page, npages=self.npages, title=self.title,
page_title=page_title, page_text=page_text,
next_page_title=next_page_title, next_page_text=next_page_text,
page_overflow=self.overflow,
)
return
def append(self, page_title, page_text):
self.contents.append((page_title, page_text))
self.npages = len(self.contents)
return
class diary_class(book_readable_class):
def __init__(self, *args, dictionary, **kwargs):
"""
`dictionary` is a dict containing two types of entries:
- for normal text pages, id: (title, text).
`text` may contain interpolation fields, such as {code}.
When that's the case, there must be an 2nd-type entry for "code" in this dict.
`title` may be None.
- for interpolation codes, code: text.
`text` is the text to be used for the interpolation.
Alternatively, `dictionary` may be the name of a store variable containing the actual dictionary
(that's better when not in a testing phase, for pickling/saving/updating reasons)
"""
super().__init__(*args, **kwargs)
self.dictionary_ = dictionary # str id : either (title, text) or text
self.entry_ids = set() # str id
@property
def dictionary(self):
rv = self.dictionary_
if isinstance(rv, str):
rv = getattr(renpy.store, rv)
return rv
# append still exists, so that you can manually add pages without going through the dictionary
def diary_append(self, id, day=None, **branches):
"""
Adds a page to the diary.
`id` is the key of the event that just happened, in the dictionary.
`day` sets the day number for the entry, defaulting to the current day.
`branches` is a dict of {sub-event id : code} for every happened sub-event specializing event `id`.
the specified codes will be looked for in the dictionary, and the original entry of id `id`
will be formatted by associating {sub-event id} with dictionary[code].
If `code` is not a valid entry in the dict, the `code` value itself will be interpolated instead,
or nothing if v is a false value (like None).
If the page for the key `id` contains interpolation fields,
it is a mistake to not specify all interpolation fields in `branches`.
It is benign to specify keys which are not interpolation fields.
"""
if id in self.entry_ids:
return
dictionary = self.dictionary
page_title, page_text = dictionary[id]
if branches:
branches = {k : dictionary.get(v, v or "") for k, v in branches.items()}
page_text = page_text.format(**branches)
if day is None:
day = game.day
if page_title:
page_title = "Day {}\n{}".format(day, page_title)
else:
page_title = "Day {}".format(day)
self.append(page_title, page_text)
self.entry_ids.add(id)
label book_handle(book=None):
$ book.open()
play sound "sounds/bookopen.ogg"
show screen book_animator("book_page_next", 0.5) # use an ATL sort-of-Fade instead, and With
label .after_init:
$ renpy.dynamic(__choice = ui.interact())
if __choice == "next":
$ book.next()
play sound "sounds/pageflip.ogg"
show screen book_animator("book_page_next", 0.5)
with d1
elif __choice == "prev":
$ book.prev()
play sound "sounds/pageflip.ogg"
show screen book_animator("book_page_prev", 0.5)
with d1
elif __choice == "back":
$ book.open()
play sound "sounds/pageflipback.ogg"
show screen book_animator("book_page_start", 0.5)
with d1
elif __choice == "Close":
$ book.close()
play sound "sounds/bookclose.ogg"
return
jump .after_init
screen book_menu(page, npages, title, page_title, page_text, next_page_title, next_page_text, page_overflow):
# page is 0-based
# npages is the number of pages, so max(page) is npages-1
tag book_menu
zorder 30
button style "empty" action NullAction()
add Color("#000", alpha=0.5)
add "interface/book/book_open.webp"
frame:
style "empty"
pos (280, 130)
xsize 250
ysize 300
text page_title ypos -20 size 16 xalign 0.5 textalign .5
text page_text size 12 ypos 40
text str(page+1) bold True xalign 0.5 ypos 350 size 11
frame:
style "empty"
xpos 600 ypos 130
xsize 250
ysize 300
if next_page_title is not None:
text next_page_title ypos -20 size 16 xalign 0.5 textalign .5
if next_page_text is not None:
text next_page_text size 12 ypos 40
text str(page+2) bold True xalign 0.5 ypos 350 size 11
if page+2 < npages:
# Next
imagebutton:
pos (721, 100)
idle Transform("interface/book/hover.webp", alpha=0)
hover "interface/book/hover.webp"
action Return("next")
elif page > 0:
# Fast Back to start
imagebutton:
pos (721, 100)
idle "interface/book/back.webp"
hover "interface/book/back.webp"
action Return("back")
# Previous
imagebutton:
pos (242, 100)
idle Transform("interface/book/hover.webp", xzoom=-1.0, alpha=0)
hover Transform("interface/book/hover.webp", xzoom=-1.0, alpha=1)
action Return("prev")
use close_button
screen book_animator(img, timer):
tag animator
zorder 31
add img
button style "empty" action [Hide("book_animator"), With(Dissolve(0.05))]
timer timer action [Hide("book_animator"), With(Dissolve(0.1))]
image book_page_next:
contains:
"interface/book/book_open.webp"
contains:
#"interface/book_of_secrets/book_anim_01.webp"
#pause.1
"interface/book/page_02.webp"
pause.08
"interface/book/page_03.webp"
pause.08
"interface/book/page_04.webp"
pause.08
"interface/book/page_05.webp"
pause.08
"interface/book/page_06.webp"
pause.08
"interface/book/page_07.webp"
pause.08
"blank"
image book_page_prev:
contains:
"interface/book/book_open.webp"
contains:
xoffset 40
#"interface/book_of_secrets/book_anim_01.webp"
#pause.1
Transform("interface/book/page_02.webp", xzoom=-1.0)
pause.08
Transform("interface/book/page_03.webp", xzoom=-1.0)
pause.08
Transform("interface/book/page_04.webp", xzoom=-1.0)
pause.08
Transform("interface/book/page_05.webp", xzoom=-1.0)
pause.08
Transform("interface/book/page_06.webp", xzoom=-1.0)
pause.08
Transform("interface/book/page_07.webp", xzoom=-1.0)
pause.08
"blank"
image book_page_start:
contains:
"interface/book/book_open.webp"
contains:
"interface/book/reverse_01.webp"
pause.07
"interface/book/reverse_02.webp"
pause.07
"blank"
repeat 3 #book_page_max was too slow