diff --git a/game/scripts/wardrobe/color_picker.rpy b/game/scripts/wardrobe/color_picker.rpy index ee277012..bb0a0fbd 100644 --- a/game/scripts/wardrobe/color_picker.rpy +++ b/game/scripts/wardrobe/color_picker.rpy @@ -1,4 +1,5 @@ -init python: +init python in colorpicker: + import pygame renpy.register_shader("color_picker.gradient", variables=""" @@ -83,7 +84,7 @@ init python: ) class ColorPickerBase(renpy.Displayable): - canvas = Solid("#ffffff") + canvas = renpy.store.Solid("#ffffff") def __init__(self, controller, **kwargs): super(ColorPickerBase, self).__init__(**kwargs) @@ -143,8 +144,8 @@ init python: self.update() self.unfocus() self.apply() - renpy.restart_interaction() - return ["released", self.controller.live_color] + set_color(None, None, self.controller.live_color) + return if ev.type == pygame.MOUSEMOTION and ev.buttons[0]: # Dragged @@ -249,7 +250,7 @@ init python: # Live colour - live_color = Solid(self.controller.live_color) + live_color = renpy.store.Solid(self.controller.live_color) lcr = renpy.render(live_color, width, height, st, at) # # Start colour @@ -322,9 +323,9 @@ init python: return rv - class ColorPicker(NoRollback): + class ColorPicker(renpy.store.NoRollback): - def __init__(self, start_color=Color("#fff"), default_color=Color("#fff")): + def __init__(self, start_color=renpy.store.Color("#fff"), default_color=renpy.store.Color("#fff")): self.live_color = start_color self.start_color = start_color self.default_color = default_color @@ -346,7 +347,7 @@ init python: def update(self): hsv = (self.hue, self.saturation, self.value) - col = Color(hsv=hsv, alpha=self.alpha) + col = renpy.store.Color(hsv=hsv, alpha=self.alpha) self.live_color = col self.redraw() @@ -382,150 +383,217 @@ init python: @staticmethod def add_history(col): - colorpicker.history.append(col) + renpy.store.colorpicker.history.append(col) - if len(colorpicker.history) > 10: - del colorpicker.history[0] + if len(renpy.store.colorpicker.history) > 10: + del renpy.store.colorpicker.history[0] @staticmethod def add_favorite(index, col): - colorpicker.favorites[index] = col + renpy.store.colorpicker.favorites[index] = col + + def set_layer(item, layer): + # Update scope + scope = renpy.get_screen("wardrobe").scope + scope["selected_item"] = item + scope["selected_layer"] = layer + + # Update colorpicker + col = item.color[layer] + dcol = item.color_default[layer] + + cp.live_replace(col) + cp.start_replace(col) + cp.default_replace(dcol) + + renpy.restart_interaction() + + def set_color(item, layer, value): + # Acquire params from scope if necessary + scope = renpy.get_screen("wardrobe").scope + if not item: + item = scope["selected_item"] + if not layer: + layer = scope["selected_layer"] + + # Update item + item.color[layer] = value + item.is_stale() + + renpy.restart_interaction() cp = ColorPicker() default colorpicker.history = [] default colorpicker.favorites = [Color((167, 77, 42)), Color((237, 179, 14)), Color((89, 116, 194)), Color((216, 163, 10)), Color((58, 115, 75)), Color((205, 205, 206)), Color((251, 198, 10)), Color((51, 43, 54))] + ([Color((255, 255, 255))] * 22) -screen colorpickerscreen(item=None): - zorder 30 - modal True +# screen colorpickerscreen(item=None): +# zorder 30 +# modal True - if item: - default is_cheating = config.developer or cheat_wardrobe_alpha - default is_blacklisted = item.type.startswith(tuple(item.blacklist_unequip)) - default is_allowed = item.type.startswith(("makeup", "tattoo")) - default transparency = item and not is_blacklisted and (is_allowed or is_cheating) +# if item: +# default is_cheating = config.developer or cheat_wardrobe_alpha +# default is_blacklisted = item.type.startswith(tuple(item.blacklist_unequip)) +# default is_allowed = item.type.startswith(("makeup", "tattoo")) +# default transparency = item and not is_blacklisted and (is_allowed or is_cheating) - frame: - style_prefix "colorpicker" - background "cp_frame" - align (0.2, 0.5) - padding (18, 18) +# frame: +# style_prefix "colorpicker" +# background "cp_frame" +# align (0.2, 0.5) +# padding (18, 18) - has vbox +# has vbox - if item: - $ layers = item.color +# if item: +# $ layers = item.color - label "Layers" xalign 0.0 +# label "Layers" xalign 0.0 - hbox: - spacing 4 - for i, col in enumerate(layers): +# hbox: +# spacing 4 +# for i, col in enumerate(layers): +# button: +# xysize (32, 32) +# background col +# foreground "cp_borders" +# action Return(["layer", i]) +# alternate Return(["replace", col]) +# text str(i+1) style "colorpicker_innertext" + +# hbox: +# vbox: +# label "Colour Picker" + +# frame: +# add cp.cpsv xysize (255, 255) + +# if transparency: +# label "Transparency" + +# frame: +# add cp.cpa xysize (255, 30) + +# vbox: +# label "Hue" + +# frame: +# add cp.cph xysize (30, 255) + +# vbox: + +# label "Previews" + +# hbox: +# spacing 4 +# frame: +# add cp.cpp xysize (32, 32) +# frame: +# button: +# xysize (32, 32) +# background cp.start_color +# action Return(["replace", cp.start_color]) +# text "Old" style "colorpicker_innertext" size 8 +# frame: +# button: +# xysize (32, 32) +# background cp.default_color +# action Return(["replace", cp.default_color]) +# text "Org" style "colorpicker_innertext" size 8 + +# label "Swatches" + +# grid 5 6: +# xalign 0.5 +# spacing 4 + +# for i, col in enumerate(colorpicker.favorites): +# frame: +# button: +# xysize (12, 12) +# background col +# action Return(["replace", col]) +# alternate Function(cp.add_favorite, i, cp.live_color) + +# label "History" + +# grid 5 2: +# xalign 0.5 +# spacing 4 + +# for col in colorpicker.history: +# frame: +# button: +# xysize (12, 12) +# background col +# action Return(["replace", col]) + +# hbox: +# align (1.0, 1.0) + +# if item: +# textbutton "Reset": +# action [Function(item.reset_color), Function(cp.live_replace, cp.default_color)] + +# textbutton "Finish": +# action Return(["finish", cp.live_color]) +# keysym ["K_ESCAPE", "K_RETURN"] + +# if config.developer: +# vbox: +# pos (15, 15) +# spacing 0 +# style_prefix "colorpickerdev" + +# text "Hue:[cp.hue]" +# text "Sat:[cp.saturation]" +# text "Val:[cp.value]" +# text "Alpha:[cp.alpha]" + +# if item: +# $ colorcode = [i.hexcode for i in item.color] +# textbutton "Colour code: [colorcode]": +# action [Function(set_clipboard, json.dumps(colorcode)), Notify("Colorcode copied to clipboard.")] +# #alternate [Function(item.set_color, evaluate(str(get_clipboard())))] +# keysym ["ctrl_K_c"] +# #alternate_keysym ["ctrl_K_v"] + +screen colorpicker(character): + default selected_layer = 0 + default selected_item = None + + hbox: + # Item list + vpgrid: + cols 1 + ysize 450 + yspacing 5 + scrollbars "vertical" + mousewheel True + for state in character.states.values(): + $ item = state[0] + + if item and item.color: button: - xysize (32, 32) - background col - foreground "cp_borders" - action Return(["layer", i]) - alternate Return(["replace", col]) - text str(i+1) style "colorpicker_innertext" - - hbox: + add AlphaMask(Transform(item.icon, xysize=(48, 48)), Transform("wheelmenu_button_opaque", xysize=(48, 48))) + action Function(wardrobe.change_item, item) selected (selected_item == item) + if selected_item: vbox: - label "Colour Picker" - - frame: - add cp.cpsv xysize (255, 255) - - if transparency: - label "Transparency" - - frame: - add cp.cpa xysize (255, 30) - - vbox: - label "Hue" - - frame: - add cp.cph xysize (30, 255) - - vbox: - - label "Previews" + label _("Layers") xalign 0.0 hbox: spacing 4 - frame: - add cp.cpp xysize (32, 32) - frame: + for n, col in enumerate(selected_item.color): button: xysize (32, 32) - background cp.start_color - action Return(["replace", cp.start_color]) - text "Old" style "colorpicker_innertext" size 8 - frame: - button: - xysize (32, 32) - background cp.default_color - action Return(["replace", cp.default_color]) - text "Org" style "colorpicker_innertext" size 8 + background col + selected_foreground "#ffffff80" + action Function(colorpicker.set_layer, item, n) + selected (n == selected_layer) + # alternate Return(["replace", col]) + text str(n+1) - label "Swatches" - - grid 5 6: - xalign 0.5 - spacing 4 - - for i, col in enumerate(colorpicker.favorites): - frame: - button: - xysize (12, 12) - background col - action Return(["replace", col]) - alternate Function(cp.add_favorite, i, cp.live_color) - - label "History" - - grid 5 2: - xalign 0.5 - spacing 4 - - for col in colorpicker.history: - frame: - button: - xysize (12, 12) - background col - action Return(["replace", col]) - - hbox: - align (1.0, 1.0) - - if item: - textbutton "Reset": - action [Function(item.reset_color), Function(cp.live_replace, cp.default_color)] - - textbutton "Finish": - action Return(["finish", cp.live_color]) - keysym ["K_ESCAPE", "K_RETURN"] - - if config.developer: - vbox: - pos (15, 15) - spacing 0 - style_prefix "colorpickerdev" - - text "Hue:[cp.hue]" - text "Sat:[cp.saturation]" - text "Val:[cp.value]" - text "Alpha:[cp.alpha]" - - if item: - $ colorcode = [i.hexcode for i in item.color] - textbutton "Colour code: [colorcode]": - action [Function(set_clipboard, json.dumps(colorcode)), Notify("Colorcode copied to clipboard.")] - #alternate [Function(item.set_color, evaluate(str(get_clipboard())))] - keysym ["ctrl_K_c"] - #alternate_keysym ["ctrl_K_v"] + add colorpicker.cp.cpsv xysize (255, 255) style colorpickerdev_text: size 12 diff --git a/game/scripts/wardrobe/wardrobe.rpy b/game/scripts/wardrobe/wardrobe.rpy index d0dc620f..18d225f3 100644 --- a/game/scripts/wardrobe/wardrobe.rpy +++ b/game/scripts/wardrobe/wardrobe.rpy @@ -11,17 +11,20 @@ define wardrobe.subcategories = { } # Settings -default wardrobe.music = False +default wardrobe.music = True default wardrobe.chitchats = True default wardrobe.autosave = False default wardrobe.suppress_warnings = False default wardrobe.randomize_color = False default wardrobe.global_color = False +default wardrobe.allow_opacity = False # Functions init python in wardrobe: from collections import OrderedDict + _last_track = None + def get_subcategories(d): return OrderedDict( sorted( @@ -40,35 +43,91 @@ init python in wardrobe: return renpy.store.Image(fp, oversample=4) return renpy.store.Image("gui/creamy_pumpkin_pie/icons/noicon.png", oversample=4) + def change_section(section): + scope = renpy.get_screen("wardrobe").scope + if scope["selected_section"] == section: + return + scope["selected_section"] = section + scope["selected_category"] = None + scope["selected_subcategory"] = None + + def change_category(category): + scope = renpy.get_screen("wardrobe").scope + if scope["selected_category"] == category: + return + scope["selected_category"] = category + scope["selected_subcategory"] = None + + def change_subcategory(subcategory): + scope = renpy.get_screen("wardrobe").scope + if scope["selected_subcategory"] == subcategory: + return + scope["selected_subcategory"] = subcategory + + def change_item(item): + scope = renpy.get_screen("wardrobe").scope + scope["selected_layer"] = 0 + scope["layers"] = item.color + scope["selected_item"] = item + + renpy.store.colorpicker.set_layer(item, 0) + + renpy.restart_interaction() + + def toggle_setting(setting): + if setting == "music": + if renpy.store.wardrobe.music == False: + renpy.store.wardrobe.music = True + renpy.music.play("music/Spring_In_My_Step.ogg") + else: + renpy.store.wardrobe.music = False + renpy.music.play(_last_track, fadein=1) + else: + # StoreModule is a bit of a hack, but it's the only way to do this. + renpy.store.wardrobe.__dict__[setting] = not renpy.store.wardrobe.__dict__[setting] + renpy.restart_interaction() + def equip(item): scope = renpy.get_screen("wardrobe").scope character = scope["character"] + # Check if the item is hair and already equipped if item.type == "hair" and character.is_equipped_item(item): + # If so, play a sound and display a notification to indicate that hair cannot be removed renpy.play("sounds/fail.ogg") renpy.notify("Hair cannot be removed.") else: - + # Check if the item is already equipped if character.is_equipped_item(item): + # If so, check if it's possible to unequip the item if wardrobe_check_unequip(item): + # If so, play a reaction and then remove the item from the character's equipment wardrobe_react("unequip", item) character.unequip(item) else: + # Otherwise, play a failed unequip reaction wardrobe_react("unequip_fail", item) else: + # If the item is not already equipped, check if it's possible to equip the item if wardrobe_check_equip(item): + # If so, play a reaction and then add the item to the character's equipment wardrobe_react("equip", item) + # Check if the item is on the blacklist if not wardrobe_check_blacklist(item): + # If so, play a blacklist reaction wardrobe_react("blacklist", item) + # Mark the item as seen and equip it to the character item.mark_as_seen() character.equip(item) + # Check if a fallback response is required for the item if wardrobe_fallback_required(item): - # Has to be called regardless of player preference. + # If so, call the fallback response function renpy.call(get_character_response(states.active_girl, "fallback"), item) else: + # Otherwise, play a failed equip reaction wardrobe_react("equip_fail", item) renpy.restart_interaction() @@ -106,8 +165,12 @@ init python in wardrobe: character.wear("all") renpy.restart_interaction() +# Context label wardrobe(inter_pause=True): $ disable_game_menu() + $ wardrobe._last_track = renpy.music.get_playing() + if wardrobe.music: + play music "music/Spring_In_My_Step.ogg" if inter_pause: # Ensures all irrelevant screens are hidden before capturing the surface tree with Pause(0.2) @@ -115,6 +178,7 @@ label wardrobe(inter_pause=True): $ enable_game_menu() jump main_room_menu +# Interface screen wardrobe(): layer "interface" zorder 0 @@ -126,10 +190,11 @@ screen wardrobe(): default navigation_exit = False default character = get_character_object(states.active_girl) + default selected_section = None default selected_category = None default selected_subcategory = None - # default menu_items = inventory.get_instances_of_type(category) - # default selected_item = None + default selected_item = None + default selected_layer = 0 add last_frame at navigation_last_frame_atl @@ -142,46 +207,122 @@ screen wardrobe(): at navigation_atl vbox: + # Sections hbox: spacing 0 - for category in character.wardrobe: - if category == "hidden": - continue - button: - add wardrobe.get_icon(category) xysize (64, 64) - tooltip category - action [SetScreenVariable("selected_category", category), SetScreenVariable("selected_subcategory", None)] + button: + add wardrobe.get_icon("outfits") xysize (64, 64) + tooltip "Outfits" + action Function(wardrobe.change_section, "outfits") selected (selected_section == "outfits") + button: + add wardrobe.get_icon("color_picker") xysize (64, 64) + tooltip "Colour Picker" + action Function(wardrobe.change_section, "color_picker") selected (selected_section == "color_picker") + button: + add wardrobe.get_icon("outfits") xysize (64, 64) + tooltip "Settings" + action Function(wardrobe.change_section, "settings") selected (selected_section == "settings") - null height 5 + null height 3 add "frame_spacer" xsize 500 xalign 0.5 - null height 5 + null height 3 - if selected_category: - viewport: - ysize 32 - edgescroll (60, 50) - mousewheel "horizontal" - hbox: - for subcategory in character.wardrobe[selected_category]: - button: - label subcategory - action SetScreenVariable("selected_subcategory", subcategory) + if selected_section == "outfits": + # Categories + hbox: + spacing 0 + for category in character.wardrobe: + if category == "hidden": + continue - null height 5 + button: + add wardrobe.get_icon(category) xysize (64, 64) + tooltip category + action Function(wardrobe.change_category, category) selected (selected_category == category) + + null height 3 add "frame_spacer" xsize 500 xalign 0.5 - null height 5 + null height 3 + + # Subcategories + if selected_category: + viewport: + ysize 28 + edgescroll (60, 50) + mousewheel "horizontal" + hbox: + for subcategory in character.wardrobe[selected_category]: + button: + label subcategory + action Function(wardrobe.change_subcategory, subcategory) selected (selected_subcategory == subcategory) + + add "frame_spacer" xsize 500 xalign 0.5 + null height 5 + + # Items + if selected_subcategory: + vpgrid: + cols 5 + ysize 399 + xspacing 5 + yspacing 5 + mousewheel True + scrollbars "vertical" + for item in character.wardrobe[selected_category][selected_subcategory]: + add item.button + elif selected_section == "color_picker": + # Included in a single screen because local screen scopes don't work as they should with functions. + hbox: + # Item list + vpgrid: + cols 1 + ysize 520 + yspacing 4 + scrollbars "vertical" + mousewheel True + for state in character.states.values(): + $ item = state[0] + + if item and item.color: + button: + add AlphaMask(Transform(item.icon, xysize=(48, 48)), Transform("wheelmenu_button_opaque", xysize=(48, 48))) + action Function(wardrobe.change_item, item) selected (selected_item == item) + if selected_item: + $ is_blacklisted = selected_item.type.startswith(tuple(selected_item.blacklist_unequip)) + $ is_allowed = selected_item.type.startswith(("makeup", "tattoo")) + + vbox: + label _("Layers") xalign 0.0 + + hbox: + spacing 4 + for n, col in enumerate(selected_item.color): + button: + xysize (32, 32) + background col + selected_foreground "#ffffff80" + action Function(colorpicker.set_layer, selected_item, n) + selected (n == selected_layer) + # alternate Return(["replace", col]) + text str(n+1) + + hbox: + add colorpicker.cp.cpsv xysize (255, 255) + add colorpicker.cp.cph xysize (30, 255) + + if not is_blacklisted and (is_allowed or wardrobe.allow_opacity): + add colorpicker.cp.cpa xysize (255, 30) + + elif selected_section == "settings": + textbutton _("Special Music") action Function(wardrobe.toggle_setting, "music") selected wardrobe.music style "wardrobe_checkbox_button" + textbutton _("Chitchats") action Function(wardrobe.toggle_setting, "chitchats") selected wardrobe.chitchats style "wardrobe_checkbox_button" + textbutton _("Autosave") action Function(wardrobe.toggle_setting, "autosave") selected wardrobe.autosave style "wardrobe_checkbox_button" + textbutton _("Suppress Warnings") action Function(wardrobe.toggle_setting, "suppress_warnings") selected wardrobe.suppress_warnings style "wardrobe_checkbox_button" + textbutton _("Randomize Colours") action Function(wardrobe.toggle_setting, "randomize_color") selected wardrobe.randomize_color style "wardrobe_checkbox_button" + textbutton _("Global Colours") action Function(wardrobe.toggle_setting, "global_color") selected wardrobe.global_color style "wardrobe_checkbox_button" + textbutton _("Allow Opacity Slider") action Function(wardrobe.toggle_setting, "allow_opacity") selected wardrobe.allow_opacity style "wardrobe_checkbox_button" - if selected_subcategory: - vpgrid: - cols 5 - ysize 399 - xspacing 5 - yspacing 5 - mousewheel True - scrollbars "vertical" - for item in character.wardrobe[selected_category][selected_subcategory]: - add item.button add character.image align (1.0, 1.0) zoom 0.6 vbox: @@ -192,7 +333,7 @@ screen wardrobe(): style wardrobe_item_button is empty: background Transform("wheelmenu_button", xysize=(96,96)) hover_background At(Transform("wheelmenu_button_opaque", xysize=(96,96)), wheelmenu_hover_anim) - selected_foreground Transform("#ffffff", alpha=0.5) + selected_foreground Transform("interface/topbar/icon_check.webp", align=(1.0, 1.0), size=(24, 24)) hover_sound "sounds/qubodup-hover1.ogg" activate_sound "sounds/qubodup-click2.ogg" # anchor (0.5, 0.5) @@ -216,8 +357,18 @@ style wardrobe_button_text is frame_button_text: size 18 style wardrobe_label: xpadding 5 - ypadding 5 + ypadding 2 style wardrobe_label_text is wardrobe_button_text style wardrobe_viewport: fit_first True xsize 500 + +style wardrobe_checkbox_button: + padding (6, 4) + hover_background Frame(Image("gui/creamy_pumpkin_pie/book/book_select.png", oversample=4), 20, 0, 20, 0, tile=False) + foreground Transform(Image("gui/creamy_pumpkin_pie/book/book_button_check_empty.png", oversample=4), xpos=6, yalign=0.5) + selected_foreground Transform(Image("gui/creamy_pumpkin_pie/book/book_button_check_checked.png", oversample=4), xpos=6, yalign=0.5) + insensitive_foreground Transform(Image("gui/creamy_pumpkin_pie/book/book_button_check_empty.png", oversample=4), alpha=0.5, xpos=6, yalign=0.5) + +style wardrobe_checkbox_button_text is wardrobe_button_text: + first_indent 24