CampBuddy/Camp.Buddy v2.2.1/Camp_Buddy-2.2.1-pc/renpy/common/00gallery.rpy
2025-03-03 23:00:33 +01:00

623 lines
18 KiB
Text

# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
init -1500 python:
class __GalleryAllPriorCondition(object):
def check(self, all_prior):
return all_prior
class __GalleryArbitraryCondition(object):
def __init__(self, condition):
self.condition = condition
def check(self, all_prior):
return eval(self.condition)
class __GalleryUnlockCondition(object):
def __init__(self, images):
self.images = images
def check(self, all_prior):
for i in self.images:
print(i, renpy.seen_image(i))
if not renpy.seen_image(i):
return False
return True
class __GalleryImage(object):
def __init__(self, gallery, displayables):
# The gallery object we belong to.
self.gallery = gallery
# A list of conditions for this image to be displayed.
self.conditions = [ ]
# A list of displayables to show.
self.displayables = displayables
# A list of transforms to apply to those displayables, or None
# to not apply a transform.
self.transforms = [ None ] * len(displayables)
def check_unlock(self, all_prior):
"""
Returns True if the image is unlocked.
"""
for i in self.conditions:
if not i.check(all_prior):
return False
return True
def show(self, locked, index, count):
"""
Shows this image when it's unlocked.
"""
renpy.transition(self.gallery.transition)
ui.saybehavior()
displayables = [ ]
for d, transform in zip(self.displayables, self.transforms):
if transform is not None:
d = transform(d)
else:
d = config.default_transform(d)
d = renpy.display.layout.AdjustTimes(d, None, None)
displayables.append(d)
renpy.show_screen("_gallery", locked=locked, index=index + 1, count=count, displayables=displayables, gallery=self.gallery)
return ui.interact()
class __GalleryButton(object):
def __init__(self, gallery, index):
self.gallery = gallery
self.images = [ ]
self.conditions = [ ]
self.index = index
def check_unlock(self):
for i in self.conditions:
if not i.check(True):
return False
for i in self.images:
if i.check_unlock(False):
return True
return False
@renpy.pure
class __GalleryToggleSlideshow(Action, FieldEquality):
identity_fields = [ "gallery" ]
def __init__(self, gallery):
self.gallery = gallery
def __call__(self):
self.gallery.slideshow = not self.gallery.slideshow
renpy.restart_interaction()
def get_selected(self):
return self.gallery.slideshow
@renpy.pure
class __GalleryAction(Action, FieldEquality):
identity_fields = [ "gallery" ]
equality_fields = [ "index" ]
def __init__(self, gallery, index):
self.gallery = gallery
self.index = index
def __call__(self):
renpy.invoke_in_new_context(self.gallery.show, self.index)
class Gallery(object):
"""
:doc: gallery class
This class supports the creation of an image gallery by handling the
locking of images, providing an action that can show one or more images,
and a providing method that creates buttons that use that action.
.. attribute:: transition
The transition that is used when changing images.
.. attribute:: locked_button
The default displayable used by make_button for a locked button.
.. attribute:: hover_border
The default hover border used by make_button.
.. attribute:: idle_border
The default idle border used by make_button.
.. attribute:: unlocked_advance
If true, the gallery will only advance through unlocked images.
.. attribute:: navigation
If true, the gallery will display navigation and slideshow
buttons on top of the images.
To customize the look of the navigation, you may override the
gallery_navigation screen. The default screen is defined in
common/00gallery.rpy
.. attribute:: span_buttons
If true, the gallery will advance between buttons.
.. attribute:: slideshow_delay
The time it will take for the gallery to advance between images
in slideshow mode.
"""
transition = None
hover_border = None
idle_border = None
locked_button = None
def __init__(self):
# A map from button name (or image) to __GalleryButton object.
self.buttons = { }
# A list of buttons.
self.button_list = [ ]
self.button_ = None
self.image_ = None
self.unlockable = None
self.unlocked_advance = False
self.navigation = False
self.span_buttons = False
self.slideshow_delay = 5
self.slideshow = False
def button(self, name):
"""
:doc: gallery method
Creates a new button, named `name`.
`name`
The name of the button being created.
"""
button = __GalleryButton(self, len(self.button_list))
self.unlockable = button
self.buttons[name] = button
self.button_list.append(button)
self.button_ = button
def image(self, *displayables):
"""
:doc: gallery method
Adds a new image to the current button, where an image consists
of one or more displayables.
"""
self.image_ = __GalleryImage(self, displayables)
self.button_.images.append(self.image_)
self.unlockable = self.image_
display = image
def transform(self, *transforms):
"""
:doc: gallery method
Applies transforms to the last image registered. This should be
called with the same number of transforms as the image has
displayables. The transforms are applied to the corresponding
displayables.
If a transform is None, the default transform is used.
"""
self.image_.transforms = transforms
def unlock(self, *images):
"""
:doc: gallery method
A condition that takes one or more image names as argument, and
is satisfied when all the named images have been seen by the
player. The image names should be given as strings.
"""
self.unlockable.conditions.append(__GalleryUnlockCondition(images))
def condition(self, expression):
"""
:doc: gallery method
A condition that is satisfied when an expression evaluates to true.
`expression`
A string giving a Python expression.
"""
if not isinstance(expression, basestring):
raise Exception("Gallery condition must be a string containing an expression.")
self.unlockable.conditions.append(__GalleryArbitraryCondition(expression))
def allprior(self):
"""
:doc: gallery method
A condition that is true if all prior images associated with the
current button have been unlocked.
"""
self.unlockable.conditions.append(__GalleryAllPriorCondition())
def unlock_image(self, *images):
"""
:doc: gallery method
A convenience method that is equivalent to calling image and unlock
with the same parameters. This will cause an image to be displayed
if it has been seen before.
The images should be specified as strings giving image names.
"""
self.image(*images)
self.unlock(*images)
def Action(self, name):
"""
:doc: gallery method
An action that displays the images associated with the given button
name.
"""
if name not in self.buttons:
raise Exception("{0!r} is not a button defined in this gallery.".format(name))
b = self.buttons[name]
if b.check_unlock():
return __GalleryAction(self, b.index)
else:
return None
def make_button(self, name, unlocked, locked=None, hover_border=None, idle_border=None, style=None, **properties):
"""
:doc: gallery method
This creates a button that displays the images associated with the given
button name.
`name`
The name of the button that will be created.
`unlocked`
A displayable that is displayed for this button when it is
unlocked.
`locked`
A displayable that is displayed for this button when it is
locked. If None, the locked_button field of the gallery
object is used instead.
`hover_border`
A displayable that is used to overlay this button when
it is unlocked and has focus. If None, the hover_border
field of the gallery object is used.
`idle_border`
A displayable that is used to overlay this button when
it is unlocked but unfocused. If None, the idle_border
field of the gallery object is used.
`style`
The style the button inherits from. When None, defaults
to the "empty" style, so as not to inherit borders and
so on.
Additional keyword arguments become style properties of the
created button object.
"""
action = self.Action(name)
if locked is None:
locked = self.locked_button
if hover_border is None:
hover_border = self.hover_border
if idle_border is None:
idle_border = self.idle_border
if style is None:
if (config.script_version is not None) and (config.script_version <= (7, 0, 0)):
style = "button"
else:
style = "empty"
return Button(action=action, child=unlocked, insensitive_child=locked, hover_foreground=hover_border, idle_foreground=idle_border, style=style, **properties)
def get_fraction(self, name, format="{seen}/{total}"):
"""
:doc: gallery method
Returns a text string giving the number of unlocked images and total number of images in the button
named `name`.
`format`
A Python format string that's used to format the numbers. This has three values that
can be substituted in:
{seen}
The number of images that have been seen.
{total}
The total number of images in the button.
{locked}
The number of images that are still locked.
"""
seen = 0
total = 0
all_prior = True
for i in self.buttons[name].images:
total += 1
if i.check_unlock(all_prior):
seen += 1
else:
all_prior = False
return format.format(seen=seen, total=total, locked=total - seen)
def show(self, button=0, image=0):
"""
Starts showing gallery images.
`button`
The index of the button to start showing.
"""
# A list of (button, image) index pairs for all of the images we know
# about.
all_images = [ ]
# A list of (button, image) index pairs for all of the unlocked
# images.
unlocked_images = [ ]
for bi, b in enumerate(self.button_list):
all_unlocked = True
for ii, i in enumerate(b.images):
all_images.append((bi, ii))
unlocked = i.check_unlock(all_unlocked)
if unlocked:
unlocked_images.append((bi, ii))
else:
all_unlocked = False
if self.unlocked_advance and (button == bi) and (image == ii):
image += 1
self.slideshow = False
# Loop, displaying the images.
while True:
if button >= len(self.button_list):
break
b = self.button_list[button]
if image >= len(b.images):
break
i = b.images[image]
result = i.show((button, image) not in unlocked_images, image, len(b.images))
# Default action for click.
if result is True:
result = "next"
if result == 'return':
break
# At this point, result is either 'next', "next_unlocked", "previous", or "previous_unlocked"
# Go through the common advance code.
if self.unlocked_advance:
images = unlocked_images
else:
images = all_images
if (button, image) in images:
index = images.index((button, image))
else:
index = -1
if result.startswith('previous'):
index -= 1
else:
index += 1
if index < 0 or index >= len(images):
break
new_button, new_image = images[index]
if not self.span_buttons:
if new_button != button:
break
button = new_button
image = new_image
renpy.transition(self.transition)
def Return(self):
"""
:doc: gallery method
Stops displaying gallery images.
"""
return ui.returns("return")
def Next(self, unlocked=False):
"""
:doc: gallery method
Advances to the next image in the gallery.
`unlocked`
If true, only considers unlocked images.
"""
if unlocked:
return ui.returns("next_unlocked")
else:
return ui.returns("next")
def Previous(self, unlocked=False):
"""
:doc: gallery method
Goes to the previous image in the gallery.
`unlocked`
If true, only considers unlocked images.
"""
if unlocked:
return ui.returns("previous_unlocked")
else:
return ui.returns("previous")
def ToggleSlideshow(self):
"""
:doc: gallery method
Toggles slideshow mode.
"""
return __GalleryToggleSlideshow(self)
init -1500:
# Displays a set of images in the gallery, or indicates that the images
# are locked. This is given the following arguments:
#
# locked
# True if the image is locked.
# displayables
# A list of transformed displayables that should be shown to the user.
# index
# A 1-based index of the image being shown.
# count
# The number of images attached to the current button.
# gallery
# The image gallery object.
screen _gallery:
if locked:
add "#000"
text _("Image [index] of [count] locked.") align (0.5, 0.5)
else:
for d in displayables:
add d
if gallery.slideshow:
timer gallery.slideshow_delay action Return("next") repeat True
key "game_menu" action gallery.Return()
if gallery.navigation:
use gallery_navigation
screen gallery_navigation:
hbox:
spacing 20
style_group "gallery"
align (.98, .98)
textbutton _("prev") action gallery.Previous(unlocked=gallery.unlocked_advance)
textbutton _("next") action gallery.Next(unlocked=gallery.unlocked_advance)
textbutton _("slideshow") action gallery.ToggleSlideshow()
textbutton _("return") action gallery.Return()
python:
style.gallery = Style(style.default)
style.gallery_button.background = None
style.gallery_button_text.color = "#666"
style.gallery_button_text.hover_color = "#fff"
style.gallery_button_text.selected_color = "#fff"
style.gallery_button_text.size = 16