diff --git a/game/scripts/doll/main.rpy b/game/scripts/doll/main.rpy index f6faf121..d447be50 100644 --- a/game/scripts/doll/main.rpy +++ b/game/scripts/doll/main.rpy @@ -613,7 +613,7 @@ init python: group.append(x[0]) if group: - renpy.notify("Import successful!") + # renpy.notify("Import successful!") return DollOutfit(group, True) renpy.notify("Import failed: Unknown error.") return None diff --git a/game/scripts/doll/outfits.rpy b/game/scripts/doll/outfits.rpy index 384d9724..b249e2d1 100644 --- a/game/scripts/doll/outfits.rpy +++ b/game/scripts/doll/outfits.rpy @@ -99,11 +99,11 @@ init python: def icon(self): return self.build_icon(self._hash) - def _build_button(self, _hash, subcat): - style = "wardrobe_button" + def _build_button(self, _hash): + style = "wardrobe_item_button" # is_equipped = self.char.is_equipped_item(self) is_modded = self.is_modded() - is_inadequate = subcat in ("save", "load", "schedule") and not wardrobe_check_equip_outfit(self) + # is_inadequate = wardrobe.wardrobe_check_equip_outfit(self) has_schedule = any(self.schedule.values()) child = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6) @@ -116,45 +116,40 @@ init python: warnings.append("Outfit contains items from these mods:\n{size=-4}{color=#35aae2}"+ "\n".join(self.get_modname()) + "{/color}{/size}") hbox.append(Text("M", color="#00b200", style="wardrobe_button_text")) - action = None + action = [Function(wardrobe.wheelmenu, self, "outfits"), self.build_button] alternate = None unhovered = None foreground = None hover_foreground = "#ffffff80" selected_foreground = None - if is_inadequate: - foreground = "#b2000040" - hover_foreground = "#CD5C5C40" - selected_foreground = "#CD5C5C40" + # if is_inadequate: + # foreground = "#b2000040" + # hover_foreground = "#CD5C5C40" + # selected_foreground = "#CD5C5C40" - ## MOVE ACTIONS OUT OF THE FUNCTION, THEY FUCK THINGS UP. - ## One can manipulate the button actions using Button.action - - if subcat == "delete": - action = Return(["deloutfit", self]) - elif subcat == "load": - action = Return(["equip", self]) - elif subcat == "save": - action = Return(["addoutfit", self]) - # elif subcat == "import": # Imports are taken care of outside the class. - # action = Return(["import", self]) - elif subcat == "export": - action = Return(["export", self]) - elif subcat == "schedule": - if not has_schedule and not is_inadequate: - action = Return(["schedule", self]) - alternate = Return(["schedule", self]) - foreground = "#00000040" - hover_foreground = "#80808040" - selected_foreground = "#80808040" - elif has_schedule: - action = Return(["schedule", self]) - alternate = Return(["schedule", self]) - # elif is_inadequate: - # foreground = "#b2000040" - # hover_foreground = "#CD5C5C40" - # selected_foreground = "#CD5C5C40" + # if subcat == "delete": + # action = Return(["deloutfit", self]) + # elif subcat == "load": + # action = Return(["equip", self]) + # elif subcat == "save": + # action = Return(["addoutfit", self]) + # elif subcat == "export": + # action = Return(["export", self]) + # elif subcat == "schedule": + # if not has_schedule and not is_inadequate: + # action = Return(["schedule", self]) + # alternate = Return(["schedule", self]) + # foreground = "#00000040" + # hover_foreground = "#80808040" + # selected_foreground = "#80808040" + # elif has_schedule: + # action = Return(["schedule", self]) + # alternate = Return(["schedule", self]) + # # elif is_inadequate: + # # foreground = "#b2000040" + # # hover_foreground = "#CD5C5C40" + # # selected_foreground = "#CD5C5C40" if has_schedule: for i in wardrobe.outfit_schedule: # Wardrobe store var @@ -173,13 +168,13 @@ init python: return Button(child=child, focus_mask=None, xysize=(96, 168), background=self.icon, action=action, alternate=alternate, tooltip=("\n".join(warnings)), foreground=foreground, hover_foreground=hover_foreground, selected_foreground=selected_foreground, unhovered=unhovered, style=style) @functools.cache - def build_button(self, subcat): + def build_button(self): - def _func(self, hash, subcat): - result = self._build_button(self._hash, subcat) + def _func(self, hash): + result = self._build_button(self._hash) self._button.put(result) - thread = DollThread(target=_func, args=(self, self._hash, subcat)) + thread = DollThread(target=_func, args=(self, self._hash)) thread.start() @property @@ -188,7 +183,7 @@ init python: return self._button.get_with_default(self._loading) else: global current_subcategory - return self._build_button(self._hash, current_subcategory) + return self._build_button(self._hash) def clear_button_cache(self): self.build_button.cache_clear() diff --git a/game/scripts/wardrobe/wardrobe.rpy b/game/scripts/wardrobe/wardrobe.rpy index ef1544b5..19e48305 100644 --- a/game/scripts/wardrobe/wardrobe.rpy +++ b/game/scripts/wardrobe/wardrobe.rpy @@ -22,6 +22,8 @@ default wardrobe.allow_opacity = False # Functions init python in wardrobe: import functools + import datetime + import os from collections import OrderedDict _last_track = None @@ -52,6 +54,9 @@ init python in wardrobe: scope["selected_section"] = section if section == "outfits": + scope["selected_item"] = None + import_outfits() + if section == "clothing": scope["selected_category"] = "head" scope["selected_subcategory"] = "hair" scope["selected_item"] = None @@ -81,7 +86,7 @@ init python in wardrobe: renpy.restart_interaction() - def jump_to_item(item, section="outfits"): + def jump_to_item(item, section="clothing"): scope = renpy.get_screen("wardrobe").scope cat, subcat = item.categories scope["selected_section"] = section @@ -111,45 +116,65 @@ init python in wardrobe: 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) + if isinstance(item, renpy.store.DollCloth): + # 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: - # 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): - # If so, call the fallback response function - renpy.call(get_character_response(states.active_girl, "fallback"), item) + # 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: - # Otherwise, play a failed equip reaction - wardrobe_react("equip_fail", item) - renpy.restart_interaction() + # 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): + # 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() + else: + outfit = character.create_outfit(temp=True) + + if outfit == item: + renpy.notify("Load failed: Outfit already equipped.") + else: + if wardrobe_check_equip_outfit(item): + + if not outfit.exists(): + # confirm = suppress_warnings or renpy.show_screen("confirm", "Discard unsaved changes and load this outfit?") + + wardrobe_react("equip_outfit", item) + character.equip(item) + else: + wardrobe_react("equip_outfit", item) + character.equip(item) + else: + wardrobe_react("equip_outfit_fail", item) + def strip(): scope = renpy.get_screen("wardrobe").scope @@ -168,6 +193,18 @@ init python in wardrobe: scope["__character_strip"] = 0 renpy.restart_interaction() + def save(): + scope = renpy.get_screen("wardrobe").scope + character = scope["character"] + outfit = character.create_outfit(temp=True) + + if outfit.exists(): + renpy.notify("Save failed: Outfit already exists.") + else: + outfit = character.create_outfit() + outfit.build_button() + renpy.notify("Outfit Saved.") + def toggle_item(slot): scope = renpy.get_screen("wardrobe").scope character = scope["character"] @@ -194,20 +231,57 @@ init python in wardrobe: character.wear("all") renpy.restart_interaction() - def wheelmenu(item, section="outfits"): + def wheelmenu(item, section="clothing"): scope = renpy.get_screen("wardrobe").scope character = scope["character"] + submenu_pos = renpy.get_mouse_pos() exit_action = renpy.store.Function(renpy.hide_screen, "wheelmenu") equip_action = renpy.store.Function(equip, item) color_action = renpy.store.Function(jump_to_item, item, "color_picker") if character.is_equipped_item(item) else [equip_action, renpy.store.Function(jump_to_item, item, "color_picker")] - hide_action = renpy.store.Function(toggle_item, item.type) select_action = renpy.store.Function(change_item, item) jump_action = renpy.store.Function(jump_to_item, item) + if isinstance(item, renpy.store.DollCloth): + hide_action = renpy.store.Function(toggle_item, item.type) + + def _overwrite_outfit(character, item): + selected_outfit_index = character.outfits.index(item) + selected_outfit_schedule = character.outfits[selected_outfit_index].schedule.copy() + + current_outfit = character.create_outfit() + current_outfit.delete() # Removes from list only + current_outfit.schedule = selected_outfit_schedule + + character.outfits[selected_outfit_index] = current_outfit + + def schedule_action(): + btns = renpy.store.create_wheelmenu({ + _("Day"): (renpy.store.Text("🌞", align=(0.5, 0.5)), renpy.store.Function(toggle_schedule_action, "day"), "True", str(not item.schedule["day"])), + _("Night"): (renpy.store.Text("🌙", align=(0.5, 0.5)), renpy.store.Function(toggle_schedule_action, "night"), "True", str(not item.schedule["night"])), + _("Rainy"): (renpy.store.Text("🌧️", align=(0.5, 0.5)), renpy.store.Function(toggle_schedule_action, "rainy"), "True", str(not item.schedule["rainy"])), + _("Snowy"): (renpy.store.Text("🌨️", align=(0.5, 0.5)), renpy.store.Function(toggle_schedule_action, "snowy"), "True", str(not item.schedule["snowy"])), + _("Cloudy"): (renpy.store.Text("☁️", align=(0.5, 0.5)), renpy.store.Function(toggle_schedule_action, "cloudy"), "True", str(not item.schedule["cloudy"])), + }) + + renpy.show_screen("wheelmenu", btns, pos=submenu_pos, close_action=exit_action) + + def toggle_schedule_action(schedule): + item.schedule[schedule] = not item.schedule[schedule] + schedule_action() + d = {} if section == "outfits": + delete_action = item.delete + export_action = renpy.store.Function(item.export_data, datetime.datetime.now().strftime("%d %b %Y-%H%M%S") + ".png") + overwrite_action = renpy.store.Function(_overwrite_outfit, character, item) + d[_("Equip")] = (renpy.store.Text("👗", align=(0.5, 0.5)), [exit_action, equip_action]) + d[_("Overwrite")] = (renpy.store.Text("💾", align=(0.5, 0.5)), [exit_action, overwrite_action]) + d[_("Delete")] = (renpy.store.Text("❌", align=(0.5, 0.5)), [exit_action, delete_action]) + d[_("Export")] = (renpy.store.Text("📤", align=(0.5, 0.5)), [exit_action, export_action]) + d[_("Schedule")] = (renpy.store.Text("🗓️", align=(0.5, 0.5)), [exit_action, schedule_action]) + elif section == "clothing": if not character.is_equipped_item(item): d[_("Equip")] = (renpy.store.Text("👗", align=(0.5, 0.5)), [exit_action, equip_action]) else: @@ -216,14 +290,13 @@ init python in wardrobe: if item.color: d[_("Colourize")] = (renpy.store.Text("🎨", align=(0.5, 0.5)), [exit_action, color_action]) elif section == "color_picker": - d[_("Select")] = (renpy.store.Text("✅", align=(0.5, 0.5)), [exit_action, select_action]) - if not character.is_worn(item.type): d[_("Show")] = (renpy.store.Text("👁️", align=(0.5, 0.5)), [exit_action, hide_action]) else: d[_("Hide")] = (renpy.store.Text("👁️", align=(0.5, 0.5)), [exit_action, hide_action]) - d[_("Jump to wardrobe")] = (renpy.store.Text("👗", align=(0.5, 0.5)), [exit_action, jump_action]) + d[_("Select")] = (renpy.store.Text("✅", align=(0.5, 0.5)), [exit_action, select_action]) + d[_("Jump to wardrobe")] = (renpy.store.Text("🚪", align=(0.5, 0.5)), [exit_action, jump_action]) btns = renpy.store.create_wheelmenu(d) @@ -285,6 +358,22 @@ init python in wardrobe: return [(head_btn, head_pos), (breasts_btn, breasts_pos), (vagina_btn, vagina_pos)] + def import_outfits(): + scope = renpy.get_screen("wardrobe").scope + character = scope["character"] + path = f"{renpy.config.gamedir}/outfits/" + + if not os.path.exists(path): + os.makedirs(path) + + files = [] + for f in os.listdir(path): + fp = os.path.join(path, f) + rp = os.path.relpath(fp, renpy.config.gamedir).replace("\\", "/") + + if os.path.isfile(os.path.join(path, f)) and f.endswith(".png"): + character.import_outfit(rp) + # Context label wardrobe(inter_pause=True): $ disable_game_menu() @@ -333,15 +422,19 @@ screen wardrobe(): button: add wardrobe.get_icon("outfits") xysize (64, 64) - tooltip "Outfits" + tooltip _("Outfits") action Function(wardrobe.change_section, "outfits") selected (selected_section == "outfits") + button: + add wardrobe.get_icon("clothing") xysize (64, 64) + tooltip _("Clothing") + action Function(wardrobe.change_section, "clothing") selected (selected_section == "clothing") button: add wardrobe.get_icon("color_picker") xysize (64, 64) - tooltip "Colour Picker" + 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" + add wardrobe.get_icon("clothing") xysize (64, 64) + tooltip _("Settings") action Function(wardrobe.change_section, "settings") selected (selected_section == "settings") null height 3 @@ -349,6 +442,26 @@ screen wardrobe(): null height 3 if selected_section == "outfits": + # Outfit List + vpgrid: + cols 5 + spacing 5 + mousewheel True + scrollbars "vertical" + + textbutton "Save": + focus_mask None + xysize (96, 168) + insensitive_background "#0000001A" + idle_background "#00000033" + text_align (0.5, 0.5) + sensitive (not bool(DollThread._count)) + action wardrobe.save + + for outfit in reversed(character.outfits): + add outfit.button + + elif selected_section == "clothing": # Categories hbox: spacing 0 @@ -596,5 +709,5 @@ style wardrobe_checkbox_button_text is wardrobe_button_text: # Debug only style wardrobe_secret: - #background "#ff000025" - background None + #background "#ff000025" + background None