2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# init python:
# def shop_dress_sortfilter(item, sortby="Price (Asc)", filtering=None):
# # Always sort alphabetically first.
# item = sorted(item, key=lambda x: natsort_key(x.name))
# if sortby == "Price (Asc)":
# item.sort(key=lambda x: x.price, reverse=False)
# elif current_sorting == "Price (Desc)":
# item.sort(key=lambda x: x.price, reverse=True)
# if sortby == "Lewdness (Asc)":
# item.sort(key=get_outfit_score, reverse=False)
# elif current_sorting == "Lewdness (Desc)":
# item.sort(key=get_outfit_score, reverse=True)
# return item
# label shop_dress:
# $ gui.in_context("shop_dress_menu")
# return
# label shop_dress_menu:
# python:
# current_sorting = "Price (Asc)"
# category_items = {"hermione": hermione.outfits, "tonks": tonks.outfits, "cho": cho.outfits, "luna": luna.outfits, "astoria": astoria.outfits, "susan": susan.outfits}
# current_category = "hermione"
# store_cart = set()
# menu_items = shop_dress_sortfilter((x for x in category_items.get(current_category, []) if (x.unlocked == False and x.price > 0 and x not in store_cart)), current_sorting)
# current_item = next(iter(menu_items), None)
# parcel_callbacks = []
# show screen shop_dress()
# label .after_init:
# $ renpy.dynamic(__choice = ui.interact())
# if __choice[0] == "category":
# $ current_category = __choice[1]
# $ menu_items = shop_dress_sortfilter((x for x in category_items.get(current_category, []) if (x.unlocked == False and x.price > 0 and x not in store_cart)), current_sorting)
# $ current_item = next(iter(menu_items), None)
# elif __choice[0] == "buy":
# show screen blktone
# with d3
# if states.env.gold < __choice[1].price:
# gen "(I don't have enough gold.)" ("base", xpos="far_left", ypos="head")
# else:
# if len(store_cart) < 5:
# $ renpy.call("purchase_outfit", __choice[1])
# play sound "sounds/money.ogg"
# $ states.env.gold -= __choice[1].price
# $ store_cart.add(__choice[1])
# $ menu_items = shop_dress_sortfilter((x for x in category_items.get(current_category, []) if (x.unlocked == False and x.price > 0 and x not in store_cart)), current_sorting)
# $ current_item = next(iter(menu_items), None)
# if len(store_cart) < 5:
# maf "Anything else?"
# else:
# maf "That was your fifth order, sir, I'm afraid it will have to be your last one."
# else:
# maf "I'm sorry luv but that's as much as you can order for now."
# hide screen blktone
# with d3
# elif __choice == "sort":
# if current_sorting == "Price (Asc)":
# $ current_sorting = "Price (Desc)"
# elif current_sorting == "Price (Desc)":
# $ current_sorting = "Lewdness (Asc)"
# elif current_sorting == "Lewdness (Asc)":
# $ current_sorting = "Lewdness (Desc)"
# elif current_sorting == "Lewdness (Desc)":
# $ current_sorting = "Price (Asc)"
# $ menu_items = shop_dress_sortfilter([x for x in category_items.get(current_category, []) if bool(x.unlocked == False and x.price > 0 and not x in store_cart)], current_sorting)
# else: # Close
# if len(store_cart) < 5:
# show screen blktone
# with d3
# menu:
# maf "Are you finished shopping, dearie?"
# "-Yes, I'm done-":
# pass
# "-Not yet-":
# hide screen blktone
# with d3
# jump .after_init
# if store_cart:
# $ transit_time = len(store_cart)+1
# $ packaging_fee = 45 + ( (len(store_cart)-1) * 20 )
# menu:
# maf "If you pay extra, I could hire a bunch of elves to speed things up..."
# "\"Fine. ([packaging_fee] gold)\"" if states.env.gold >= packaging_fee:
# $ states.env.gold -= packaging_fee
# $ transit_time = int(transit_time/2)
# "\"Fine. ([packaging_fee] gold)\"" (style="disabled") if states.env.gold < packaging_fee:
# maf "Sorry luv, but it appears you have no gold left."
# "-No thanks-":
# pass
# hide screen shop_dress
# hide screen blktone
# $ _tmp = "tomorrow" if transit_time == 1 else f"in about {transit_time} days"
# maf "You can expect a parcel [_tmp]."
# # Executes callbacks upon receival of the parcel.
# $ curry = renpy.curry(execute_callbacks)(parcel_callbacks) if parcel_callbacks else None
# $ parcel_callbacks = []
# $ Parcel(contents=[(k, 1) for k in store_cart], wait=transit_time, func=curry).send()
# return
# else:
# gen "Nothing has caught my eye I'm afraid." ("base", xpos="far_left", ypos="head")
# maf "Maybe next time."
# return
# jump .after_init
# screen shop_dress():
# tag shop_dress
# zorder 15
# modal True
# add "gui_fade"
# if renpy.mobile:
# use close_button_background
# use close_button
# fixed:
# if settings.get("animations"):
# at gui_animation
# use shop_dress_menu()
# use shop_dress_menuitem()
# screen shop_dress_menu():
# tag shop_menu
# zorder 15
# style_prefix "shop"
# default icon_bg = gui.format("interface/achievements/{}/iconbox.webp")
# default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
# default panel = gui.format("interface/frames/{}/panel_left.webp")
# default highlight = gui.format("interface/achievements/{}/highlight_left_b.webp")
# window:
# pos (150, 90)
# xysize (207, 454)
# background panel
# use invisible_button()
# vbox:
# pos (6, 6)
# for category in category_items.keys():
# if get_character_unlock(category):
# $ icon = Fixed(icon_bg, Frame( Transform(f"interface/icons/head/{category}.webp", fit="contain"), xysize=(42, 42), offset=(3, 3)), "interface/achievements/glass_iconbox.webp")
# vbox:
# textbutton category:
# style "empty"
# xysize (195, 48)
# text_align (0.6, 0.5)
# text_xanchor 0.5
# text_size 20
# foreground icon
# hover_background highlight
# selected_background highlight
# selected (current_category == category)
# action Return(["category", category])
# add gui.format("interface/frames/{}/spacer_left.webp")
# vbox:
# style_prefix gui.theme('achievements_filters')
# pos (6, 384)
# button action None
# textbutton "Sort by: [current_sorting]" action Return("sort")
# screen shop_dress_menuitem():
# tag shop_menuitem
# zorder 16
# style_prefix "shop"
# default icon_size = (144, 288)
# default icon_frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
# default panel = gui.format("interface/frames/{}/panel.webp")
# window:
# pos (367, 37)
# xysize (560, 501)
# background panel
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# use invisible_button()
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# text "Shop" size 22 xalign 0.5 ypos 65
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# if current_item:
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# frame:
# xalign 0.5
# ypos 412
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# vbox:
# xalign 0.5
# add gui.format("interface/achievements/{}/highlight.webp")# pos (112, 375)
# add gui.format("interface/achievements/{}/spacer.webp")# pos (120, 398)
# text "[current_item.desc]" size 12 yoffset 6
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# text "[current_item.name]" xalign 0.5 ypos 3 size 16
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# $ frame = Frame(gui.format("interface/frames/{}/iconframe.webp"), 6, 6)
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# textbutton "Buy":
# style "inventory_button"
# background frame
# xalign 0.95
# action Return(["buy", current_item])
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# vpgrid:
# rows 1
# xspacing 5
# yspacing 2
# draggable True
# mousewheel "horizontal"
# scrollbars "horizontal"
# xmaximum 512
# ypos 106
# xalign 0.5
# at transform:
# mesh True
# for item in menu_items:
# $ icon = Transform(item.image, crop=(215, 0, 680, 1200), mesh=True, gl_pixel_perfect=True)
# $ is_modded = item.is_modded()
# $ is_affordable = bool(states.env.gold >= item.price)
# button:
# style "shop_outfit_button"
# xysize icon_size
# background Transform(icon, xsize=144, ysize=288, fit="contain", anchor=(0.5, 1.0), align=(0.5, 1.0), yoffset=-6)
# selected (current_item == item)
# action SetVariable("current_item", item)
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# add icon_frame
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# if is_affordable:
# text "{color=#daa520}G{/color} [item.price]" xalign 0.5 ypos 10 color "#ffffff" outlines [ (1, "#000", 0, 0) ] style "shop_outfit_text"
# else:
# text "{color=#daa520}G{/color} {color=#ff0000}[item.price]{/color}" xalign 0.5 ypos 10 color "#ffffff" outlines [ (1, "#000", 0, 0) ] style "shop_outfit_text"
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# if config.developer:
# $ outfit_score = get_outfit_score(item)
# text "{color=#fff}score{/color} [outfit_score]" align (0.1, 0.98) color "#ffffff" outlines [ (1, "#000", 0, 0) ] size 8
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# hbox:
# offset (5, -5)
# align (0.0, 1.0)
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# if is_modded:
# text "M" color "#00b200"
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# style shop_window is empty
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# style shop_outfit_button is empty:
# foreground None
# hover_foreground "#ffffff80"
# selected_foreground "#ffffff40"
# activate_sound "sounds/click.ogg"
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# style shop_outfit_button_text is default:
# size 14
2022-05-16 23:48:22 +00:00
2024-11-11 19:06:18 +00:00
# style shop_outfit_text:
# size 20
2024-11-10 15:23:13 +00:00
# Functions (Initialised after wardrobe)
init 5 python in clothing_store:
get_icon = renpy.store.wardrobe.get_icon # Simple Proxy since both interfaces share the same code
def buy():
renpy.play("sounds/money.ogg")
pass
def change_section(section):
scope = renpy.get_screen("clothing_store_interface").scope
2024-11-11 19:06:18 +00:00
scope["character"] = renpy.store.get_character_object(section)
2024-11-10 15:23:13 +00:00
scope["selected_section"] = section
2024-11-11 19:06:18 +00:00
scope["selected_item"] = next(outfits(section), None)
2024-11-10 15:23:13 +00:00
def add_remove_outfit(outfit):
scope = renpy.get_screen("clothing_store_interface").scope
cart = scope["cart"]
if outfit in cart:
# Remove the outfit from the cart if it's already there and there are more than one item
cart ^= {outfit}
elif len(cart) < 5:
# Add the outfit to the cart if it's not already there and there are less than five items
cart |= {outfit}
else:
renpy.notify("You can only have five items in your cart.")
renpy.sound.play("sounds/fail.ogg")
2024-11-11 19:06:18 +00:00
def select_outfit(outfit):
2024-11-10 15:23:13 +00:00
scope = renpy.get_screen("clothing_store_interface").scope
scope["selected_item"] = outfit
renpy.restart_interaction()
def exit():
scope = renpy.get_screen("clothing_store_interface").scope
renpy.play("sounds/curtain_close.ogg")
# Handle exit animation
scope["navigation_last_frame_atl"] = renpy.store.navigation_last_frame_hide
scope["navigation_atl"] = renpy.store.wardrobe_hide
scope["character_atl"] = renpy.store.wardrobe_character_hide
scope["navigation_exit"] = True
# Reset states
renpy.restart_interaction()
2024-11-11 19:06:18 +00:00
def outfits(section):
scope = renpy.get_screen("clothing_store_interface").scope
character = scope["character"]
# Sort the outfits by price in ascending order
sorted_outfits = sorted((x for x in reversed(character.outfits) if not x.unlocked and x.price > 0), key=lambda outfit: outfit.price)
return iter(sorted_outfits)
def discuss(outfit):
renpy.store._skipping = True
renpy.suspend_rollback(False)
renpy.block_rollback()
renpy.call_in_new_context("discuss_outfit", outfit)
renpy.store._skipping = False
def wheelmenu(outfit):
scope = renpy.get_screen("clothing_store_interface").scope
character = scope["character"]
cart = scope["cart"]
exit_action = renpy.store.Function(renpy.hide_screen, "wheelmenu")
select_action = renpy.store.Function(select_outfit, outfit)
add_remove_action = renpy.store.Function(add_remove_outfit, outfit)
d = {
_("select"): (renpy.store.Text("✅", align=(0.5, 0.5)), [exit_action, select_action])
}
if outfit in cart:
d[_("Remove from cart")] = (renpy.store.Text("🛒", align=(0.5, 0.5)), [exit_action, add_remove_action])
else:
d[_("Add to cart")] = (renpy.store.Text("🛒", align=(0.5, 0.5)), [exit_action, add_remove_action])
btns = renpy.store.create_wheelmenu(d)
renpy.play("sounds/qubodup-click1.ogg")
renpy.show_screen("wheelmenu", btns, pos=None, close_action=exit_action)
2024-11-10 15:23:13 +00:00
# Context
label clothing_store_interface(inter_pause=True):
$ disable_game_menu()
play sound "sounds/curtain_open.ogg"
if inter_pause:
# Ensures all irrelevant screens are hidden before capturing the surface tree
with Pause(0.2)
call screen clothing_store_interface
$ enable_game_menu()
# jump expression f"{states.active_girl}_requests"
jump main_room_menu
# Interface
screen clothing_store_interface():
layer "interface"
zorder 0
2024-11-11 19:06:18 +00:00
style_prefix "store"
2024-11-10 15:23:13 +00:00
default navigation_atl = wardrobe_show
default character_atl = wardrobe_character_show
default last_frame = (screenshot.capture() or screenshot.image)
default navigation_last_frame_atl = navigation_last_frame_show
default navigation_exit = False
default character = get_character_object("tonks")
default selected_section = "tonks"
2024-11-11 19:06:18 +00:00
default selected_item = next(clothing_store.outfits(selected_section), None)
2024-11-10 15:23:13 +00:00
default cart = set()
2024-11-11 19:06:18 +00:00
$ total_price = sum([item.price for item in cart])
$ total_gold = states.env.gold-total_price
2024-11-10 15:23:13 +00:00
add last_frame at navigation_last_frame_atl
add "gui_fade_both" at gui_fade
if navigation_exit:
timer 0.4 action Return()
if selected_item:
add selected_item.image align (1.0, 1.0) zoom 0.6 at character_atl
frame:
style "empty"
at navigation_atl
vbox:
style_prefix "navigation_tabs"
2024-11-11 19:06:18 +00:00
pos (540, 428)
2024-11-10 15:23:13 +00:00
at navigation_tabs_show
2024-11-11 19:06:18 +00:00
textbutton _("Discuss") action Function(clothing_store.discuss, selected_item) style "navigation_tabs_button_special" at navigation_tabs
textbutton (_("Remove from cart") if selected_item in cart else _("Add to cart")) action Function(clothing_store.add_remove_outfit, selected_item) selected (selected_item in cart) style "store_tabs_button_add_remove" at navigation_tabs
textbutton _("Checkout") action clothing_store.buy sensitive (states.env.gold >= total_price and cart) at navigation_tabs
2024-11-10 15:23:13 +00:00
null height 35
textbutton _("Exit") action clothing_store.exit keysym "K_ESCAPE" at navigation_tabs
2024-11-11 19:06:18 +00:00
if selected_item:
vbox:
at character_atl
pos (972, 468)
vbox:
xoffset -36
text _("[states.env.gold]G") xalign 1.0
text _("-[total_price]G") xalign 1.0
add "frame_spacer" xsize 100
if total_gold >= 0:
text _("[total_gold]G") xalign 1.0
else:
text _("[total_gold]G") color "#ad0000" xalign 1.0
label _("G") + str(selected_item.price) xoffset -50
2024-11-10 15:23:13 +00:00
frame:
at navigation_atl
vbox:
# Sections
hbox:
spacing 0
2024-11-11 19:06:18 +00:00
for i in states.dolls:
button:
add clothing_store.get_icon(i) xysize (64, 64)
tooltip i
action Function(clothing_store.change_section, i) selected (selected_section == i)
2024-11-10 15:23:13 +00:00
null height 3
add "frame_spacer" xsize 500 xalign 0.5
null height 3
# Outfit List
vpgrid:
cols 5
spacing 4
mousewheel True
scrollbars "vertical"
2024-11-11 19:06:18 +00:00
for outfit in clothing_store.outfits(selected_section):
2024-11-10 15:23:13 +00:00
button:
2024-11-11 19:06:18 +00:00
style "store_rectangular_button"
2024-11-10 15:23:13 +00:00
add outfit.button.child
2024-11-11 19:06:18 +00:00
label "G[outfit.price]" style "store_label_small"
2024-11-10 15:23:13 +00:00
if outfit in cart:
add Transform(Text("🛒"), align=(1.0, 1.0), size=(24, 24))
2024-11-11 19:06:18 +00:00
if renpy.android:
action Function(clothing_store.wheelmenu, outfit)
else:
action Function(clothing_store.select_outfit, outfit)
alternate Function(clothing_store.wheelmenu, outfit)
2024-11-10 15:23:13 +00:00
selected (selected_item == outfit)
2024-11-11 19:06:18 +00:00
style store_rectangular_button is wardrobe_item_button:
xysize (96, 168)
2024-11-10 15:23:13 +00:00
background Transform("wheelmenu_frame_vertical", xysize=(96,168))
hover_background At(Transform("wheelmenu_frame_opaque_vertical", xysize=(96,168)), wheelmenu_hover_anim)
selected_background Fixed(Transform("wheelmenu_frame_vertical", xysize=(96,168)), At(Transform("interface/achievements/glow.webp", align=(0.5, 0.5), size=(96, 96), alpha=0.5), rotate_circular))
selected_hover_background Fixed(At(Transform("wheelmenu_frame_vertical", xysize=(96,168)), wheelmenu_hover_anim), At(Transform("interface/achievements/glow.webp", align=(0.5, 0.5), size=(96, 96), alpha=0.5), rotate_circular))
2024-11-11 19:06:18 +00:00
selected_foreground None
style store_frame is wardrobe_frame
style store_button is wardrobe_button
style store_text is wardrobe_text:
color "#FFFFFF"
style store_label:
background Image("gui/creamy_pumpkin_pie/store/price_tag.png", oversample=3)
style store_label_text:
anchor (1.0, 0.5)
text_align 1.0
pos (110, 30)
color "#000000"
outlines [(2, "#8BA5D9", 1, 1)]
hinting "bytecode"
size 24
style store_label_small:
align (0.0, 1.0)
xysize (68, 28)
background Frame(Image("gui/creamy_pumpkin_pie/store/price_tag.png", oversample=6), 20, 10, tile=False, fit="contain")
style store_label_small_text:
anchor (1.0, 0.5)
text_align 1.0
pos (50, 16)
color "#000000"
outlines [(1, "#8BA5D9", 1, 1)]
hinting "bytecode"
size 14
style store_tabs_button_add_remove is navigation_tabs_button:
ysize 35
left_padding 15
right_padding 30
selected_right_padding 30
background Frame(Transform(Image("gui/creamy_pumpkin_pie/book/book_tab.png", oversample=4), matrixcolor=HueMatrix(180.0)), 0, 0, 80, 0, tile=False)
selected_background Frame(Transform(Image("gui/creamy_pumpkin_pie/book/book_tab.png", oversample=4), matrixcolor=HueMatrix(275.0)), 0, 0, 80, 0, tile=False)
insensitive_background Frame(Transform(Image("gui/creamy_pumpkin_pie/book/book_tab.png", oversample=4), matrixcolor=SaturationMatrix(0.0)), 0, 0, 80, 0, tile=False)
activate_sound "sounds/woosh2.ogg"
selected_activate_sound "sounds/woosh.ogg"
style store_tabs_button_add_remove_text is navigation_tabs_button_text:
selected_xoffset 0