2022-05-16 23:48:22 +00:00
default wardrobe_music = False
default wardrobe_chitchats = True
default wardrobe_autosave = False
default wardrobe_suppress_warnings = False
default wardrobe_randomise_color = False
default wardrobe_global_color = False
# Used as custom order for the sorting
define wardrobe_subcategories_sorted = {
"hair": 5, "shirts": 5, "skirts": 5, "pantyhose": 5, "slot1": 5, "panties": 5, "save": 5,
"earrings": 4, "sweaters": 4, "trousers": 4, "stockings": 4, "bikini panties": 4, "load": 4,
"neckwear": 3, "dresses": 3, "shorts": 3, "socks": 3, "schedule": 3,
"one-piece suits": 2, "import": 2,
"robes": 1, "export": 1,
"gloves": 0, "pubes": 0, "delete": 0,
"other": -1,
}
define wardrobe_categories = ("head", "piercings & tattoos", "upper body", "upper undergarment", "lower body", "lower undergarment", "legwear", "misc")
define wardrobe_outfit_schedule = ("day", "night", "cloudy", "rainy", "snowy")
2023-11-18 23:23:33 +00:00
default __lock = False
default __predicted = None
2022-05-16 23:48:22 +00:00
2023-03-24 18:04:49 +00:00
init python:
2023-11-18 23:23:33 +00:00
def preload_wardrobe_assets(c):
global __lock, __predicted
2023-07-11 21:57:49 +00:00
2023-11-18 23:23:33 +00:00
if renpy.version_tuple < (8, 2):
renpy.start_predict_screen("wardrobe")
else:
# use the new renpy.invoke_in_main_thread
renpy.invoke_in_main_thread(renpy.start_predict_screen, "wardrobe")
2023-07-11 21:57:49 +00:00
2023-11-18 23:23:33 +00:00
# this is not thread-safe, but there's no better way : it's the slow part
2023-03-24 18:04:49 +00:00
d = [v[0] for i in c.wardrobe_list for v in i.get_layers(i._hash).values()]
2023-11-18 23:23:33 +00:00
if renpy.version_tuple < (8, 2):
renpy.start_predict(*d, "interface/wardrobe/*.webp")
else:
renpy.invoke_in_main_thread(renpy.start_predict, *d, "interface/wardrobe/*.webp")
__predicted = d
__lock = False
2023-03-24 18:04:49 +00:00
2023-07-11 21:57:49 +00:00
def rebuild_wardrobe_icons(items, subcat):
2023-07-14 22:52:27 +00:00
if not settings.get("multithreading"):
return
if subcat == "import":
return
2023-07-12 22:25:53 +00:00
for i in items.get(subcat, []):
2023-07-11 21:57:49 +00:00
i.build_button(subcat)
def lock_wardrobe_icon(icon):
2023-07-14 22:52:27 +00:00
if not settings.get("multithreading"):
return icon
2023-07-11 21:57:49 +00:00
lock = bool(DollThread._count)
return gray_tint(icon) if lock else icon
def randomise_wardrobe_color(cloth):
def _func(cloth):
if not cloth is None:
if wardrobe_randomise_color and cloth.color:
col_len = len(cloth.color)
col = []
for i in range(col_len):
if col_len == 1:
col.append(tetriadic_colors[0])
elif col_len == 2:
col.append(double_colors[i-1])
elif col_len == 3:
col.append(triadic_colors[i-1])
else:
try:
col.append(tetriadic_colors[i-1])
except:
col.append(col[-1].rotate_hue(0.33))
cloth.set_color(col)
if wardrobe_global_color:
for outfit in char_active.outfits:
rebuild = False
for i in outfit.group:
if not (i.id, i.type) == (cloth.id, cloth.type):
continue
if len(cloth.color) != len(i.color):
print(f"Mismatched color lens:\n{cloth}\n{i}")
renpy.notify("Error!")
continue
i.set_color(cloth.color)
i.is_stale()
rebuild = True
if rebuild:
outfit.is_stale()
rebuild_wardrobe_icons(category_items, current_subcategory)
2023-03-24 18:04:49 +00:00
2023-07-14 01:33:58 +00:00
if settings.get("multithreading"):
thread = DollThread(target=_func, args=(cloth,), interval=0.05)
thread.start()
else:
_func(cloth)
renpy.restart_interaction()
2023-07-09 00:18:45 +00:00
2023-07-14 01:33:58 +00:00
# @functools.cache # Cache resets on wardrobe exit
2023-07-13 23:59:26 +00:00
def set_wardrobe_categories(current_category):
category_items = OrderedDict(
sorted(
[
(subcat, [item for item in items if item.unlocked])
for subcat, items in wardrobe_subcategories.get(current_category, {}).items()
],
key=lambda x: wardrobe_subcategories_sorted.get(x[0], 0),
reverse=True
)
)
return category_items
2023-03-24 18:04:49 +00:00
style loading_text:
color "#ffffff"
size 64
style loading_trivia_text:
color "#ffffff"
size 24
layeredimage loading:
always "gui_fade"
2023-11-15 03:45:11 +00:00
always Text("Loading", style="loading_text"):
2023-11-18 23:58:33 +00:00
align (0.5, 0.35)
2023-03-24 18:04:49 +00:00
always "loading_spinner"
image loading_spinner:
align (0.5, 0.5)
2023-11-18 23:58:33 +00:00
Text("{unicode}╞╪═════════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═╪════════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞══╪═══════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═══╪══════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞════╪═════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═════╪════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞══════╪═══╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═══════╪══╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞════════╪═╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═════════╪╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞════════╪═╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═══════╪══╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞══════╪═══╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═════╪════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞════╪═════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═══╪══════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞══╪═══════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
2023-11-18 23:58:33 +00:00
Text("{unicode}╞═╪════════╡{/unicode}", style="loading_text")
2023-03-24 18:04:49 +00:00
pause 0.1
repeat
2022-05-16 23:48:22 +00:00
label wardrobe:
2023-07-11 21:57:49 +00:00
$ renpy.call_in_new_context("_wardrobe")
return
label _wardrobe:
2023-03-24 18:04:49 +00:00
$ renpy.config.skipping = None
$ _game_menu_screen = None
$ _skipping = False
$ renpy.suspend_rollback(True)
show loading zorder 1000
# Ensure there's no thread in use before assigning a new one.
2023-11-18 23:23:33 +00:00
while __lock:
2023-03-24 18:04:49 +00:00
$ renpy.pause(0.5, hard=True)
2023-11-18 23:23:33 +00:00
$ __lock = True
$ renpy.invoke_in_thread(preload_wardrobe_assets, get_character_object(states.active_girl))
2023-03-24 18:04:49 +00:00
# Await thread return
# Note: renpy.pause must be called from within the main thread
2023-11-18 23:23:33 +00:00
while __lock:
2023-03-24 18:04:49 +00:00
$ renpy.pause(0.5, predict=True)
hide loading
# $ renpy.scene("screens")
# show expression screenshot.image
call wardrobe_menu
show screen main_room
show screen ui_top_bar
2023-11-18 23:23:33 +00:00
$ _game_menu_screen = "save" # documented
$ _skipping = True # documented
$ renpy.stop_predict(__predicted)
$ __predicted = None
2023-03-24 18:04:49 +00:00
$ renpy.suspend_rollback(False)
$ renpy.block_rollback()
2022-05-16 23:48:22 +00:00
return
screen wardrobe(xx, yy):
tag wardrobe
zorder 24
add "gui_fade"
if renpy.mobile:
use close_button_background
use close_button
fixed:
use wardrobe_menu(xx, yy)
if current_category == "outfits":
use wardrobe_outfit_menuitem(20, 50)
2023-11-16 16:53:29 +00:00
elif current_subcategory is not None:
2022-05-16 23:48:22 +00:00
use wardrobe_menuitem(20, 50)
label wardrobe_menu():
2023-11-19 00:10:50 +00:00
$ renpy.dynamic(
char_active = get_character_object(states.active_girl),
2024-03-26 18:53:28 +00:00
char_outfit = get_character_outfit(states.active_girl, typ="last"),
2023-11-19 00:10:50 +00:00
)
$ char_outfit.save()
$ renpy.dynamic(
wardrobe_subcategories = char_active.wardrobe,
2023-11-19 20:56:01 +00:00
current_category = "head",
2023-11-19 00:10:50 +00:00
)
2022-05-16 23:48:22 +00:00
python:
if renpy.android:
2023-11-19 00:10:50 +00:00
wardrobe_subcategories.update(outfits=dict.fromkeys(("load", "save", "delete", "schedule"), char_active.outfits))
2022-05-16 23:48:22 +00:00
else:
2023-11-19 00:10:50 +00:00
wardrobe_subcategories.update(outfits=dict.fromkeys(("load", "save", "delete", "schedule", "import", "export"), char_active.outfits))
2022-05-16 23:48:22 +00:00
2023-11-19 00:10:50 +00:00
$ renpy.dynamic(
category_items = set_wardrobe_categories(current_category),
)
$ renpy.dynamic(
current_subcategory = next(iter(category_items), ""),
)
$ renpy.dynamic(
current_item = char_active.get_equipped_wardrobe_item(category_items, current_subcategory),
last_track = renpy.music.get_playing(),
)
$ rebuild_wardrobe_icons(category_items, current_subcategory)
2022-05-16 23:48:22 +00:00
if wardrobe_music:
2023-03-16 22:55:14 +00:00
play music "music/Spring_In_My_Step.ogg" fadein 1 if_changed
2022-05-16 23:48:22 +00:00
2023-11-19 00:10:50 +00:00
show screen wardrobe(662, 50)
2022-05-16 23:48:22 +00:00
label .after_init:
2023-03-31 22:41:48 +00:00
$ renpy.hide(get_character_tag(states.active_girl))
2023-03-24 18:04:49 +00:00
$ renpy.config.skipping = None
$ _game_menu_screen = None
$ _skipping = False
$ renpy.suspend_rollback(True)
$ renpy.block_rollback()
# Note to self: Do not use a python: block, because
2022-11-04 21:17:41 +00:00
# renpy cannot return to the middle of a python block
# while mixing python and renpy scope
# https://github.com/renpy/renpy/issues/959
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
$ renpy.dynamic(__choice = ui.interact())
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
if __choice[0] == "category":
if not current_category == __choice[1]:
if wardrobe_check_category(__choice[1]):
$ current_category = __choice[1]
2022-05-16 23:48:22 +00:00
2023-07-13 23:59:26 +00:00
$ category_items = set_wardrobe_categories(current_category)
2022-11-04 21:17:41 +00:00
$ current_subcategory = list(category_items.keys())[0] if category_items else ""
2022-05-16 23:48:22 +00:00
2022-11-04 21:17:41 +00:00
if current_category == "outfits":
2023-07-11 21:57:49 +00:00
$ char_active.clear_outfit_button_cache()
$ current_item = char_active.get_equipped_wardrobe_item(category_items, current_subcategory)
2022-05-16 23:48:22 +00:00
2022-11-04 21:17:41 +00:00
$ char_active.wear("all")
if current_category in ("lower undergarment", "upper undergarment"):
$ char_active.strip("top", "bottom", "robe", "accessory")
elif current_category == "piercings & tattoos":
$ char_active.strip("top", "bottom", "robe", "accessory", "bra", "panties", "stockings", "gloves")
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("category_fail", __choice[1])
2022-05-16 23:48:22 +00:00
2023-07-11 21:57:49 +00:00
$ rebuild_wardrobe_icons(category_items, current_subcategory)
2023-11-14 22:16:26 +00:00
elif __choice[0] == "subcategory":
if not current_subcategory == __choice[1]:
$ current_subcategory = __choice[1]
2022-09-21 20:57:04 +00:00
2022-11-04 21:17:41 +00:00
if current_category == "outfits":
2023-07-11 21:57:49 +00:00
$ char_active.clear_outfit_button_cache()
2023-03-24 18:04:49 +00:00
2023-07-11 21:57:49 +00:00
$ current_item = char_active.get_equipped_wardrobe_item(category_items, current_subcategory)
$ rebuild_wardrobe_icons(category_items, current_subcategory)
2022-11-04 21:17:41 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "equip":
2022-11-04 21:17:41 +00:00
### CLOTHING ###
2023-11-14 22:16:26 +00:00
if isinstance(__choice[1], DollCloth):
if __choice[1].type == "hair" and char_active.is_equipped_item(__choice[1]):
2023-03-11 22:01:39 +00:00
play sound "sounds/fail.ogg"
2022-11-04 21:17:41 +00:00
$ renpy.notify("Hair cannot be removed.")
else:
2023-07-11 21:57:49 +00:00
2023-11-14 22:16:26 +00:00
if char_active.is_equipped_item(__choice[1]):
2022-11-04 21:17:41 +00:00
# UNEQUIP
2023-11-14 22:16:26 +00:00
if wardrobe_check_unequip(__choice[1]):
$ wardrobe_react("unequip", __choice[1])
$ char_active.unequip(__choice[1])
2023-07-11 21:57:49 +00:00
if current_item:
$ current_item.clear_button_cache()
$ current_item.build_button()
2022-11-04 21:17:41 +00:00
$ current_item = None
2022-09-21 20:57:04 +00:00
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("unequip_fail", __choice[1])
2022-11-04 21:17:41 +00:00
else:
# EQUIP
2023-11-14 22:16:26 +00:00
if wardrobe_check_equip(__choice[1]):
$ wardrobe_react("equip", __choice[1])
2022-05-16 23:48:22 +00:00
2022-11-04 21:17:41 +00:00
# Blacklist handling
2023-11-14 22:16:26 +00:00
if not wardrobe_check_blacklist(__choice[1]):
$ wardrobe_react("blacklist", __choice[1])
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
$ __choice[1].mark_as_seen()
$ char_active.equip(__choice[1])
2023-07-11 21:57:49 +00:00
if current_item:
$ current_item.clear_button_cache()
$ current_item.build_button()
2023-11-14 22:16:26 +00:00
$ current_item = __choice[1]
2023-07-11 21:57:49 +00:00
$ current_item.clear_button_cache()
$ current_item.build_button()
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
if wardrobe_fallback_required(__choice[1]):
2022-11-04 21:17:41 +00:00
# Has to be called regardless of player preference.
2023-11-14 22:16:26 +00:00
$ renpy.call(get_character_response(states.active_girl, "fallback"), __choice[1])
2022-11-04 21:17:41 +00:00
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("equip_fail", __choice[1])
2022-05-16 23:48:22 +00:00
### OUTFIT ###
2023-11-14 22:16:26 +00:00
elif isinstance(__choice[1], DollOutfit):
2022-11-04 21:17:41 +00:00
$ _outfit = char_active.create_outfit(temp=True)
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
if _outfit == __choice[1]:
2022-11-04 21:17:41 +00:00
$ renpy.notify("Load failed: Outfit already equipped.")
2022-05-16 23:48:22 +00:00
else:
2023-11-14 22:16:26 +00:00
if wardrobe_check_equip_outfit(__choice[1]):
2022-05-16 23:48:22 +00:00
if not _outfit.exists():
2022-11-04 21:17:41 +00:00
$ _confirmed = wardrobe_suppress_warnings or renpy.call_screen("confirm", "Discard unsaved changes and load this outfit?")
2022-05-16 23:48:22 +00:00
if _confirmed:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("equip_outfit", __choice[1])
$ char_active.equip(__choice[1])
$ current_item = __choice[1]
2022-05-16 23:48:22 +00:00
else:
2022-11-04 21:17:41 +00:00
$ renpy.notify("Load failed: Cancelled by user.")
2022-05-16 23:48:22 +00:00
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("equip_outfit", __choice[1])
$ char_active.equip(__choice[1])
$ current_item = __choice[1]
2022-05-16 23:48:22 +00:00
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("equip_outfit_fail", __choice[1])
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "setcolor":
2022-11-04 21:17:41 +00:00
python:
2023-11-14 22:16:26 +00:00
current_item.set_color(__choice[1])
2023-07-11 21:57:49 +00:00
current_item.clear_button_cache()
current_item.build_button()
2022-05-16 23:48:22 +00:00
if wardrobe_global_color:
for outfit in char_active.outfits:
rebuild = False
for i in outfit.group:
if not i.id == current_item.id:
continue
i.set_color(current_item.color)
2023-01-18 20:22:59 +00:00
i.is_stale()
2022-05-16 23:48:22 +00:00
rebuild = True
if rebuild:
2023-01-18 20:22:59 +00:00
outfit.is_stale()
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "touch":
if wardrobe_check_touch(__choice[1]):
$ wardrobe_react("touch", __choice[1])
2022-11-04 21:17:41 +00:00
else:
2023-11-14 22:16:26 +00:00
$ wardrobe_react("touch_fail", __choice[1])
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "addoutfit":
2022-11-04 21:17:41 +00:00
python:
2022-09-21 20:57:04 +00:00
_outfit = char_active.create_outfit(temp=True)
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if _outfit.exists():
renpy.notify("Save failed: Outfit already exists.")
else:
2023-11-14 22:16:26 +00:00
if __choice[1]:
_index = char_active.outfits.index(__choice[1])
2022-09-21 20:57:04 +00:00
_confirmed = wardrobe_suppress_warnings or renpy.call_screen("confirm", "Overwrite this outfit?")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if _confirmed:
_old_outfit = char_active.outfits[_index]
_old_schedule = _old_outfit.schedule.copy()
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
_outfit = char_active.create_outfit()
_outfit.delete() # Removes it from list only
_outfit.schedule = _old_schedule
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
char_active.outfits[_index] = _outfit
2023-07-16 15:57:53 +00:00
_outfit.build_button(current_subcategory)
2022-09-21 20:57:04 +00:00
renpy.notify("Overwritten.")
else:
renpy.notify("Save failed: Cancelled by user.")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
else:
2023-07-11 21:57:49 +00:00
_outfit = char_active.create_outfit()
_outfit.build_button(current_subcategory)
2022-09-21 20:57:04 +00:00
renpy.notify("Outfit Saved.")
2022-05-16 23:48:22 +00:00
2023-07-11 21:57:49 +00:00
current_item = char_active.get_equipped_wardrobe_item(category_items, current_subcategory)
2022-05-16 23:48:22 +00:00
2023-07-14 01:33:58 +00:00
category_items = set_wardrobe_categories(current_category)
2023-11-14 22:16:26 +00:00
elif __choice[0] == "deloutfit":
2022-11-04 21:17:41 +00:00
python:
2022-09-21 20:57:04 +00:00
_confirmed = wardrobe_suppress_warnings or renpy.call_screen("confirm", "Delete this outfit?")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if _confirmed:
2023-11-14 22:16:26 +00:00
__choice[1].delete()
2023-07-18 15:30:15 +00:00
category_items = set_wardrobe_categories(current_category)
2022-09-21 20:57:04 +00:00
renpy.notify("Outfit Deleted.")
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "export":
2022-11-04 21:17:41 +00:00
python:
2023-02-10 23:12:16 +00:00
filename = renpy.input("Save as:", datetime.datetime.now().strftime("%d %b %Y-%H%M%S"))
if not filename.endswith(".png"):
filename += ".png"
2023-11-14 22:16:26 +00:00
__choice[1].export_data(filename)
2022-09-21 20:57:04 +00:00
achievements.unlock("export")
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "import":
$ _outfit = char_active.import_outfit(__choice[1])
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice[0] == "schedule":
$ renpy.call_screen("wardrobe_schedule_menuitem", __choice[1])
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice == "music":
2022-11-04 21:17:41 +00:00
python:
2022-09-21 20:57:04 +00:00
if wardrobe_music:
wardrobe_music = False
2023-03-11 22:01:39 +00:00
renpy.music.play(last_track)
2022-09-21 20:57:04 +00:00
else:
wardrobe_music = True
2023-03-11 22:01:39 +00:00
renpy.music.play("music/Spring_In_My_Step.ogg", fadein=1)
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
elif __choice == "randomise":
2022-11-04 21:17:41 +00:00
python:
2022-09-21 20:57:04 +00:00
_confirmed = False
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
_outfit = char_active.create_outfit(temp=True)
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if not _outfit.exists():
_confirmed = wardrobe_suppress_warnings or renpy.call_screen("confirm", "Randomise Outfit?\n{size=-6}Unsaved changes will be lost.{/size}")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if not _confirmed:
renpy.notify("Advice: If you want to keep an outfit, save it.")
renpy.jump("wardrobe_menu.after_init")
2022-05-16 23:48:22 +00:00
2023-03-31 22:41:48 +00:00
progress = get_character_progression(states.active_girl)
2022-05-16 23:48:22 +00:00
2023-02-15 23:20:00 +00:00
if wardrobe_randomise_color:
2023-07-11 21:57:49 +00:00
# Set once per interaction
2023-02-15 23:20:00 +00:00
tetriadic_colors = [Color("%06x" % random.randint(0, 0xFFFFFF))]
triadic_colors = [tetriadic_colors[0].rotate_hue(0.25)]
double_colors = [tetriadic_colors[0], tetriadic_colors[0].rotate_hue(0.5)]
for i in range(1, 3):
col = tetriadic_colors[0].rotate_hue((i * 90.0) / 360.0)
tetriadic_colors.append(col)
col = triadic_colors[i-1].rotate_hue((i * 75.0) / 360.0)
triadic_colors.append(col)
2023-02-07 19:22:05 +00:00
for k in dict(char_active.states).keys():
valid_choices = [x for x in char_active.wardrobe_list if (istype(x, (DollCloth, DollClothDynamic, DollMakeup)) and x.type == k and x.unlocked and progress >= x.level)]
2022-05-16 23:48:22 +00:00
if k == "panties":
2023-03-31 22:41:48 +00:00
if not progress >= get_character_requirement(states.active_girl, "category lower undergarment"):
2022-05-16 23:48:22 +00:00
continue
2023-03-31 22:41:48 +00:00
if progress >= get_character_requirement(states.active_girl, "unequip panties"):
2022-05-16 23:48:22 +00:00
valid_choices += [None]
elif k == "bra":
2023-03-31 22:41:48 +00:00
if not progress >= get_character_requirement(states.active_girl, "category upper undergarment"):
2022-05-16 23:48:22 +00:00
continue
2023-03-31 22:41:48 +00:00
if progress >= get_character_requirement(states.active_girl, "unequip bra"):
2022-05-16 23:48:22 +00:00
valid_choices += [None]
elif k == "top":
2023-03-31 22:41:48 +00:00
if progress >= get_character_requirement(states.active_girl, "unequip top"):
2022-05-16 23:48:22 +00:00
valid_choices += [None]
elif k == "bottom":
2023-03-31 22:41:48 +00:00
if progress >= get_character_requirement(states.active_girl, "unequip bottom"):
2022-05-16 23:48:22 +00:00
valid_choices += [None]
elif any(k.startswith(type) for type in ("piercing", "tattoo")):
2023-03-31 22:41:48 +00:00
if not progress >= get_character_requirement(states.active_girl, "category piercings & tattoos"):
2022-05-16 23:48:22 +00:00
continue
valid_choices += [None]
elif k == "hair":
2023-03-14 23:25:54 +00:00
pass
elif k in char_active.body_layers:
2022-05-16 23:48:22 +00:00
pass
else:
valid_choices += [None]
if valid_choices:
cloth = random.choice(valid_choices)
2023-07-11 21:57:49 +00:00
if cloth:
randomise_wardrobe_color(cloth)
2022-05-16 23:48:22 +00:00
char_active.equip(cloth)
else:
char_active.unequip(k)
2023-07-11 21:57:49 +00:00
if current_item:
current_item.clear_button_cache()
current_item.build_button(current_subcategory)
current_item = char_active.get_equipped_wardrobe_item(category_items, current_subcategory)
if current_item:
current_item.clear_button_cache()
current_item.build_button(current_subcategory)
2022-05-16 23:48:22 +00:00
2023-11-14 22:16:26 +00:00
else: #__choice == "Close":
2022-11-04 21:17:41 +00:00
python:
2022-09-21 20:57:04 +00:00
_confirmed = False
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if wardrobe_autosave:
_outfit = char_active.create_outfit()
else:
_outfit = char_active.create_outfit(temp=True)
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if not _outfit.exists():
renpy.notify("Advice: If you want to keep an outfit, save it.")
_confirmed = wardrobe_suppress_warnings or renpy.call_screen("confirm", "Exit without saving?\n{size=-6}Unsaved changes will be lost.{/size}")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
if not _confirmed:
renpy.jump("wardrobe_menu.after_init")
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
char_active.equip(char_outfit)
2022-05-16 23:48:22 +00:00
if wardrobe_global_color:
for cloth in char_outfit.group:
for outfit in char_active.outfits:
rebuild = False
for i in outfit.group:
2023-01-18 20:22:59 +00:00
if not (i.id, i.type) == (cloth.id, cloth.type):
2022-05-16 23:48:22 +00:00
continue
i.set_color(cloth.color)
2023-01-18 20:22:59 +00:00
i.is_stale()
2022-05-16 23:48:22 +00:00
rebuild = True
if rebuild:
2023-01-18 20:22:59 +00:00
outfit.is_stale()
2022-05-16 23:48:22 +00:00
2022-09-21 20:57:04 +00:00
renpy.hide_screen("wardrobe")
char_active.wear("all")
renpy.play('sounds/door2.ogg')
2023-07-11 21:57:49 +00:00
2022-09-21 20:57:04 +00:00
if wardrobe_music:
2023-03-11 22:01:39 +00:00
renpy.music.play(last_track)
2023-07-11 21:57:49 +00:00
DollThread.stop_all()
2022-09-21 20:57:04 +00:00
enable_game_menu()
renpy.return_statement()
2022-05-16 23:48:22 +00:00
jump .after_init
screen wardrobe_menu(xx, yy):
tag wardrobe
zorder 24
style_prefix "wardrobe"
default icon_bg = Frame(gui.format("interface/frames/{}/iconmed.webp"), 6, 6)
default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
default panel = gui.format("interface/frames/{}/wardrobe.webp")
window:
pos (xx, yy)
xysize (344, 507)
#background panel
use invisible_button()
# Main Categories
grid 2 4:
ypos 108
xoffset -36
xspacing 200 + 72
yspacing 18
for i, category in enumerate(wardrobe_categories):
if wardrobe_check_category(category):
2023-03-31 22:41:48 +00:00
$ icon = Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/{}/{}.webp".format(states.active_girl, category), zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5)), icon_frame)
2022-05-16 23:48:22 +00:00
else:
2023-03-31 22:41:48 +00:00
$ icon = Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/{}/{}.webp".format(states.active_girl, category), zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5), matrixcolor=SaturationMatrix(0.0)), icon_frame)
2022-05-16 23:48:22 +00:00
$ icon_xoffset = -18 if (i % 2) == 0 else 18
button:
focus_mask None
xysize (72, 72)
2023-07-14 22:52:27 +00:00
background lock_wardrobe_icon(icon)
2022-05-16 23:48:22 +00:00
activate_sound "sounds/scroll.ogg"
tooltip category
2023-07-14 22:52:27 +00:00
sensitive (not bool(DollThread._count))
2022-05-16 23:48:22 +00:00
action Return(["category", category])
if current_category == category:
xoffset icon_xoffset
# Outfits and Studio
hbox:
$ icon_yoffset = -18
pos (92, 18)
spacing 18
# Outfits Manager
button:
focus_mask None
xysize (72, 72)
2023-07-14 22:52:27 +00:00
background lock_wardrobe_icon(Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/outfits.webp", zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5)), icon_frame))
2022-05-16 23:48:22 +00:00
tooltip "Outfits Manager"
2023-07-14 22:52:27 +00:00
sensitive (not bool(DollThread._count))
2022-05-16 23:48:22 +00:00
action Return(["category", "outfits"])
if current_category == "outfits":
yoffset icon_yoffset
# Studio
if not renpy.android:
button:
focus_mask None
xysize (72, 72)
background Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/studio.webp", zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5)), icon_frame)
tooltip "Photo Studio"
2023-03-31 22:41:48 +00:00
action Function(renpy.call_in_new_context, "studio", states.active_girl)
2022-05-16 23:48:22 +00:00
add panel
# Character image cut to the size of the wardrobe
IO Overhaul, Refactoring, and more
* Refactored DollFace
* Refactored DollBody
* Refactored DollCum
* Refactored DollCloth
* Refactored Doll
* Refactored clothing item zorders
* Refactored implementation of body, face, cum, clothing layers
* Refactored function calls
* Removed DollLipstick
* Added DollMakeup class, allowing adding dynamic clothes tracking face states
* Added DollClothDynamic, allowing dynamic clothes tracking other cloth states with bangs support
* Added cache to frequently called functions, drastically reducing the overhead
* Added hash system, reducing clone redundancy
* Added layer modifiers support for all types (face, body, cum, clothes etc.)
* Added support for an arbitrary number of equipped multislot clothing items (makeup, tattoos, piercings, etc.)
* Simplified initialization for clothing items and dolls
* Simplified class function calls
* Reduced the number of image creation calls
* Added hue support for additional skin layers
* Added displayable support to image cropping function
* Replaced store cache with built-in functools cache for _list_files function
* Refactored all character files
* and more...
2023-01-14 23:04:54 +00:00
add char_active.image:
2022-05-16 23:48:22 +00:00
yoffset -6
corner1 (184, 218)
corner2 (924, 1200)
zoom 0.45
align (0.5, 1.0)
# Easter Egg (Headpats, boobs, pussy)
button style "empty" xysize (120, 80) xalign 0.525 ypos 60 action Return(["touch", "head"])
button style "empty" xysize (120, 60) xalign 0.525 ypos 238 action Return(["touch", "breasts"])
button style "empty" xysize (120, 60) xalign 0.525 ypos 360 action Return(["touch", "vagina"])
button:
focus_mask None
xysize (72, 72)
align (0.0, 1.0)
offset (10, -10)
2023-07-11 21:57:49 +00:00
background lock_wardrobe_icon(Transform("interface/wardrobe/icons/random.webp", size=(72,72)))
2022-05-16 23:48:22 +00:00
tooltip "Randomise Outfit"
2023-07-11 21:57:49 +00:00
sensitive (not DollThread._count)
2022-05-16 23:48:22 +00:00
action Return("randomise")
use dropdown_menu(name="Options", pos=(12, 56)):
textbutton "Music":
style gui.theme("dropdown")
tooltip "My immortal."
selected wardrobe_music
action Return("music")
textbutton "Chit-chats":
style gui.theme("dropdown")
2023-03-31 22:41:48 +00:00
tooltip "{color=#35aae2}[states.active_girl]{/color} will make comments regarding your poor fashion tastes."
2022-05-16 23:48:22 +00:00
action ToggleVariable("wardrobe_chitchats", True, False)
textbutton "Outfits Scheduling":
style gui.theme("dropdown")
2023-03-31 22:41:48 +00:00
tooltip "{color=#35aae2}[states.active_girl]{/color} will automatically wear outfits\nbased on set schedule, time of day and weather."
action [ToggleVariable(f"states.{states.active_girl[:3]}.wardrobe_scheduling", True, False), If((current_category == "outfits" and current_subcategory == "schedule"), Return(["subcategory", "save"]))]
2022-05-16 23:48:22 +00:00
textbutton "Outfits Autosave":
style gui.theme("dropdown")
tooltip "Outfits will be automatically saved upon exit."
action ToggleVariable("wardrobe_autosave", True, False)
textbutton "Colour Synchronisation":
style gui.theme("dropdown")
tooltip "When changing colours of an item, apply it to all outfits with the same item."
action ToggleVariable("wardrobe_global_color", True, False)
textbutton "Colour Randomisation":
style gui.theme("dropdown")
tooltip "When randomising outfits, randomise colours as well."
action ToggleVariable("wardrobe_randomise_color", True, False)
2023-05-30 15:55:26 +00:00
textbutton "Prompts Suppression":
2022-05-16 23:48:22 +00:00
style gui.theme("dropdown")
tooltip "Disables warnings and prompts asking you to confirm certain actions. (Not recommended)"
action ToggleVariable("wardrobe_suppress_warnings", True, False)
screen wardrobe_menuitem(xx, yy):
tag wardrobe_menuitem
zorder 24
style_prefix "wardrobe"
default icon_size = (96, 96)
default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
default icon_transparent = Frame("interface/color_picker/checker.webp", tile=True)
default panel = gui.format("interface/frames/{}/panel.webp")
window:
pos (xx, yy)
xysize (560, 454)
background panel
use invisible_button()
text "[current_category]" size 22 xalign 0.5 ypos 65
# Colours
IO Overhaul, Refactoring, and more
* Refactored DollFace
* Refactored DollBody
* Refactored DollCum
* Refactored DollCloth
* Refactored Doll
* Refactored clothing item zorders
* Refactored implementation of body, face, cum, clothing layers
* Refactored function calls
* Removed DollLipstick
* Added DollMakeup class, allowing adding dynamic clothes tracking face states
* Added DollClothDynamic, allowing dynamic clothes tracking other cloth states with bangs support
* Added cache to frequently called functions, drastically reducing the overhead
* Added hash system, reducing clone redundancy
* Added layer modifiers support for all types (face, body, cum, clothes etc.)
* Added support for an arbitrary number of equipped multislot clothing items (makeup, tattoos, piercings, etc.)
* Simplified initialization for clothing items and dolls
* Simplified class function calls
* Reduced the number of image creation calls
* Added hue support for additional skin layers
* Added displayable support to image cropping function
* Replaced store cache with built-in functools cache for _list_files function
* Refactored all character files
* and more...
2023-01-14 23:04:54 +00:00
if current_item and current_item.color:
2022-05-16 23:48:22 +00:00
hbox:
spacing 2
xanchor 1.0
pos (552, 61)
2022-07-15 21:48:34 +00:00
# Colour picker
2022-05-16 23:48:22 +00:00
button:
xysize (32, 32)
2022-07-15 21:48:34 +00:00
tooltip "Dye clothing"
action Return(["setcolor", 0])
add "interface/wardrobe/icons/brush.webp":
xysize (32, 32)
2022-05-16 23:48:22 +00:00
# Subcategory icons
hbox:
spacing 5
pos (12, 108)
for subcategory in category_items.keys():
2023-07-14 22:52:27 +00:00
$ icon = lock_wardrobe_icon("interface/wardrobe/icons/{}.webp".format(subcategory))
2022-05-16 23:48:22 +00:00
button:
focus_mask None
xysize (72, 72)
background Transform(icon, size=(72, 72), fit="contain", alpha=0.65)
selected_background Transform(icon, size=(72, 72), fit="contain", )
selected (subcategory == current_subcategory)
tooltip subcategory
2023-07-14 22:52:27 +00:00
sensitive (not bool(DollThread._count))
2022-05-16 23:48:22 +00:00
action Return(["subcategory", subcategory])
2023-07-11 21:57:49 +00:00
# # Item icons
# if not menu_items:
# text "Nothing here yet" size 24 align (0.5, 0.6)
# else:
vpgrid:
cols 5
spacing 5
pos (28, 192)
xysize (507, 308)
mousewheel True
scrollbars "vertical"
style_prefix gui.theme("wardrobe")
for item in category_items.get(current_subcategory, []):
add item.button
2022-05-16 23:48:22 +00:00
screen wardrobe_outfit_menuitem(xx, yy):
tag wardrobe_menuitem
zorder 24
style_prefix "wardrobe"
default icon_size = (96, 168)
default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
default panel = gui.format("interface/frames/{}/panel.webp")
window:
pos (xx, yy)
xysize (560, 454)
background panel
use invisible_button()
text "[current_category]" size 22 xalign 0.5 ypos 65
# Subcategory icons
hbox:
spacing 5
pos (8, 108)
for subcategory in category_items.keys():
2023-07-14 22:52:27 +00:00
$ icon = lock_wardrobe_icon("interface/wardrobe/icons/{}.webp".format(subcategory))
2022-05-16 23:48:22 +00:00
$ action = Return(["subcategory", subcategory])
2023-03-31 22:41:48 +00:00
if subcategory == "schedule" and not get_character_scheduling(states.active_girl):
2022-05-16 23:48:22 +00:00
$ icon = gray_tint(icon)
2023-03-31 22:41:48 +00:00
$ action = Confirm("Outfit scheduling is currently disabled,\nwould you like to turn it on?", [SetVariable(f"states.{states.active_girl[:3]}.wardrobe_scheduling", True), Return(["subcategory", subcategory])])
2022-05-16 23:48:22 +00:00
button:
focus_mask None
xysize (72, 72)
background Transform(icon, alpha=0.65, xsize=72, fit="contain")
selected_background Transform(icon, xsize=72, fit="contain")
selected (subcategory == current_subcategory)
2023-07-14 22:52:27 +00:00
sensitive (not bool(DollThread._count))
2022-05-16 23:48:22 +00:00
tooltip subcategory
action action
# Outfit icons
2023-03-24 18:04:49 +00:00
vpgrid:
cols 5
spacing 5
pos (28, 192)
xysize (507, 308)
# if renpy.android:
# mousewheel "horizontal"
# scrollbars "horizontal"
# else:
mousewheel True
scrollbars "vertical"
2023-03-28 21:06:48 +00:00
style_prefix gui.theme("wardrobe")
2023-03-24 18:04:49 +00:00
# Add empty slot
if current_subcategory == "save":
textbutton "Save":
focus_mask None
xysize icon_size
2023-07-14 22:52:27 +00:00
insensitive_background "#0000001A"
2023-03-24 18:04:49 +00:00
idle_background "#00000033"
text_align (0.5, 0.5)
2023-07-14 22:52:27 +00:00
sensitive (not bool(DollThread._count))
2023-03-24 18:04:49 +00:00
action Return(["addoutfit", None])
2023-07-11 21:57:49 +00:00
if current_subcategory == "import":
for item in list_outfit_files():
add item
else:
2022-05-16 23:48:22 +00:00
2023-07-11 21:57:49 +00:00
for item in reversed(category_items.get(current_subcategory, [])):
add item.button
2022-05-16 23:48:22 +00:00
screen wardrobe_schedule_menuitem(item):
tag dropdown
zorder 24
default mpos = renpy.get_mouse_pos()
use invisible_button(action=Return(), alternate=Show("wardrobe_schedule_menuitem", item=item))
window:
style "empty"
pos mpos
#use invisible_button(action=NullAction(), alternate=Return())
frame:
style "empty"
background "#00000080"
padding (5, 5, 5, 5)
vbox:
spacing 0
for i in wardrobe_outfit_schedule:
$ boolean = "" if item.schedule[i] else "Not "
$ caption = "{}worn during the {}".format(boolean, i) if i in ("day", "night") else "{}worn in {} weather".format(boolean, i)
textbutton i:
style gui.theme("dropdown")
tooltip caption
2023-07-11 21:57:49 +00:00
action [ToggleDict(item.schedule, i, True, False), item.clear_button_cache, Function(item.build_button, current_subcategory)]
2022-05-16 23:48:22 +00:00
style wardrobe_window is empty
style wardrobe_button is empty:
foreground None
hover_foreground "#ffffff80"
activate_sound "sounds/click.ogg"
style wardrobe_button_text:
color "#fff"
2023-07-14 22:52:27 +00:00
insensitive_color "#808080"
2022-05-16 23:48:22 +00:00
size 20
2023-07-11 21:57:49 +00:00
outlines [ (2, "#000", 0, 0) ]
2022-05-16 23:48:22 +00:00
style wardrobe_item_caption:
color "#fff"
size 14
outlines [ (1, "#000", 0, 0) ]
2023-03-28 21:06:48 +00:00
style dark_wardrobe_window is wardrobe_window
style dark_wardrobe_button is wardrobe_button
style darK_wardrobe_button_text is wardrobe_button_text
style dark_wardrobe_item_caption is wardrobe_item_caption
style dark_wardrobe_vscrollbar is dark_vscrollbar
style light_wardrobe_window is wardrobe_window
style light_wardrobe_button is wardrobe_button
style light_wardrobe_button_text is wardrobe_button_text
style light_wardrobe_item_caption is wardrobe_item_caption
style light_wardrobe_vscrollbar is light_vscrollbar