Gouvernathor
7d4aa5f8fd
it's weird to define a variable then openly mutate it (mutate the list values, that is) I wonder if it could have unforeseen consequences There may be when sharing saves : achievements unlocked in the system the save is created may get silently unlocked on the system the save gets loaded...
459 lines
21 KiB
Plaintext
459 lines
21 KiB
Plaintext
define achievements_dict = {
|
|
# id : (categoryname, title, description, unlocked, icon, secret)
|
|
"unlockher": ["Characters", "Granger Danger", "Awarded for unlocking Hermione Granger.", False, "interface/icons/head/hermione.webp", False],
|
|
"unlockcho": ["Characters", "Chang Dynasty", "Awarded for unlocking Cho Chang.", False, "interface/icons/head/cho.webp", False],
|
|
"unlocklun": ["Characters", "Looney Tunes", "Awarded for unlocking Luna Lovegood.", False, "interface/icons/head/luna.webp", False],
|
|
"unlockast": ["Characters", "Green Peas", "Awarded for unlocking Astoria Greengrass.", False, "interface/icons/head/astoria.webp", False],
|
|
"unlockton": ["Characters", "Nymphadoreador", "Awarded for unlocking Nymphadora Tonks.", False, "interface/icons/head/tonks.webp", False],
|
|
"overwhored": ["Characters", "Overwhored", "Awarded for fully corrupting Hermione.", False, "interface/icons/head/hermione.webp", False],
|
|
"unlocksus": ["Characters", "Boner", "Awarded for unlocking Susan Bones.", False, "interface/icons/head/susan.webp", False],
|
|
"unlocksna": ["Characters", "Strictly colleagues", "Awarded for unlocking Severus Snape.", False, "interface/icons/head/snape.webp", False],
|
|
"mirror": ["Mirror", "Mirror, mirror on the wall..", "Awarded for unlocking the Room of Requirement.", False, "images/rooms/room_of_requirement/mirror_hover.webp", False],
|
|
"gold": ["General", "Gold Digger", "Awarded for having 10,000 gold in total.", False, "interface/icons/gold.webp", False],
|
|
"drunkard": ["General", "Drunken Master", "Awarded for collecting 25 bottles of wine.", False, "interface/icons/wine.webp", True],
|
|
"workaholic": ["General", "Workaholic", "Awarded for completing five full reports.", False, "interface/icons/generic_scroll.webp", False],
|
|
"fireplace": ["General", "Feel the Heat", "Awarded for lighting the fireplace 5 times or more.", False, "images/rooms/main_room/fireplace/fireplace_idle.webp", True],
|
|
"peta": ["General", "I think I forgot something...", "Awarded for not feeding the bird for 50 days.... \nYou monster.\n{size=-4}Disclaimer: No real nor fictional animals were harmed in the process.{/size}", False, "images/rooms/main_room/phoenix/phoenix_01.webp", True],
|
|
"petpal": ["General", "Regular stroking", "Awarded for petting the bird 25 times.", False, "images/rooms/main_room/phoenix/phoenix_01.webp", False],
|
|
"postman": ["Cardgame", "Poster Boy", "Awarded for buying all posters from the token shop.", False, "interface/icons/agrabah_poster.webp", False],
|
|
"hats": ["Cardgame", "Mad Hatter", "Awarded for buying all hat decorations from the token shop.", False, "interface/icons/icon_gambler_hat.webp", False],
|
|
"daddy": ["Characters", "Who's your daddy?", "Awarded for letting Hermione call you a {size=-5}(sugar){/size} daddy.", False, "interface/icons/head/hermione.webp", True],
|
|
"pantiesfap": ["Characters", "I sneezed on them...", "Awarded for rubbing one out on Hermione's panties.", False, "characters/genie/chibis/jerk_off/02.webp", False],
|
|
"pantiesfapcho": ["Characters", "Exercise is important", "Awarded for rubbing one out on Cho's panties.", False, "characters/genie/chibis/jerk_off/02.webp", False],
|
|
"bros": ["Characters", "Bros before hoes", "Awarded for becoming best pals with Snape.", False, "interface/icons/head/snape.webp", False],
|
|
"knock": ["Characters", "*Knock* *knock*", "Awarded for telling Hermione to go away during her introductory events.", False, "images/rooms/main_room/door/door_idle.webp", True],
|
|
"decorator": ["Cardgame", "Decorator", "Awarded for decorating the office for the first time.", False, "interface/icons/stag_trophy.webp", False],
|
|
"flashback": ["Cardgame", "Flashback", "Awarded for retelling what actually happened...", False, "interface/icons/cards.webp", True],
|
|
"start": ["General", "Welcome to Hogwarts!", "Awarded for finishing the intro.", False, "interface/icon.webp", False],
|
|
"export": ["General", "Sharing is caring", "Awarded for exporting an outfit through the wardrobe menu.", False, "interface/wardrobe/icons/load.webp", False],
|
|
"Credits": ["General", "New game, who this?", "Awarded for checking out the Credits Menu.", False, "interface/icons/silver_scroll.webp", False],
|
|
"Cardwin": ["Cardgame", "Time to duel", "Awarded for winning your first Card game duel.", False, "interface/icons/cards.webp", False],
|
|
"puzzle": ["General", "Down the hatch!", "Awarded for wasting a bottle of unbelievably rare phoenix tears by drinking it.", False, "interface/icons/item_potion.webp", True],
|
|
"ending": ["General", "Bittersweet Farewell", "Awarded for reaching the original ending.", False, "interface/icons/silver.webp", True],
|
|
#1.37 HG achievements
|
|
"busted": ["Characters", "BUSTED!", "Awarded for getting busted by Hermione when busting a nut.", False, "interface/icons/head/hermione.webp", False],
|
|
"herstrip": ["Characters", "Dance lessons", "Awarded for having Hermione dance naked in front of you... and Snape.", False, "interface/icons/head/hermione.webp", False],
|
|
"herkiss": ["Characters", "First Kiss", "Awarded for having Hermione make out with you-- r... cock...", False, "interface/icons/head/hermione.webp", False],
|
|
"hertits": ["Characters", "Boobs Lover", "Awarded for sticking it between Hermione's fun bags.", False, "interface/icons/head/hermione.webp", False],
|
|
"headlib": ["Characters", "Head Librarian", "Awarded for releasing your seed in Hermione's mouth.", False, "interface/icons/head/hermione.webp", False],
|
|
"nerdgasm": ["Characters", "Nerdgasm", "Awarded for doing the deed with Hermione.", False, "interface/icons/head/hermione.webp", False]
|
|
}
|
|
|
|
init python:
|
|
if persistent.achievements is None:
|
|
persistent.achievements = achievements_dict.copy()
|
|
|
|
class Achievements(object):
|
|
|
|
def __init__(self):
|
|
self.achievements = persistent.achievements
|
|
self.attempt_repair()
|
|
|
|
if config.developer:
|
|
self.validate()
|
|
|
|
def validate(self):
|
|
"""Check if icons are loadable at init"""
|
|
for i in self.achievements.values():
|
|
if not renpy.loadable(i[4]):
|
|
raise IOError(repr(i[4]))
|
|
|
|
def attempt_repair(self):
|
|
"""Achievements are kept in a persistent state which is shared across versions,
|
|
because of that, they occassionally might need to be checked
|
|
if the set values are equal to the pre-defined values.
|
|
|
|
Attempted repair will try to fix the mismatched values without resetting the completion status."""
|
|
|
|
# Save unlock states
|
|
unlock_states = {k: v[3] for k, v in self.achievements.items()}
|
|
# Keys that should not exist in the persistent state anymore
|
|
orphans = self.achievements.keys() - achievements_dict.keys()
|
|
|
|
# Making some K-pop
|
|
for k in orphans:
|
|
self.achievements.pop(k, None)
|
|
|
|
self.achievements.update(achievements_dict)
|
|
|
|
# Reapply unlock states
|
|
for k, v in self.achievements.items():
|
|
v[3] = unlock_states.get(k, False)
|
|
|
|
def status(self, id):
|
|
return self.achievements.get(id)[3]
|
|
|
|
def unlock(self, id, silent=False):
|
|
if _in_replay:
|
|
return
|
|
|
|
if persistent.achievements[id][3] == False:
|
|
self.achievements[id][3] = True
|
|
persistent.achievements[id][3] = True
|
|
|
|
if not silent:
|
|
renpy.play('sounds/achievement.ogg')
|
|
renpy.show_screen("achievement_window", msg=persistent.achievements[id][1], title="Achievement unlocked!", icon=persistent.achievements[id][4])
|
|
|
|
def lock(self, id):
|
|
self.achievements[id][3] = False
|
|
persistent.achievements[id][3] = False
|
|
|
|
def achievement_sortfilter(item, sortby="A-z", filtering=None):
|
|
if filtering == "Locked":
|
|
item = [x for x in item if x[1][3] is False]
|
|
elif filtering == "Unlocked":
|
|
item = [x for x in item if x[1][3] is True]
|
|
elif filtering == "Secret":
|
|
item = [x for x in item if x[1][5] is True]
|
|
|
|
# Always sort alphabetically first.
|
|
item = sorted(item, key=lambda x: natsort_key(x[1][1]))
|
|
|
|
if sortby == "z-A":
|
|
item = sorted(item, key=lambda x: natsort_key(x[1][1]), reverse=True)
|
|
elif current_sorting == "Unlocked":
|
|
item = sorted(item, key=lambda x: x[1][3] is False)
|
|
elif current_sorting == "Locked":
|
|
item = sorted(item, key=lambda x: x[1][3] is True)
|
|
|
|
return item
|
|
|
|
default achievements = Achievements()
|
|
|
|
###
|
|
|
|
label popup(msg="", title="", icon=None, xpos=0, ypos=60, sound=True, soundfile='sounds/achievement.ogg'):
|
|
if sound:
|
|
play sound soundfile
|
|
hide screen achievement_window
|
|
show screen achievement_window(msg=msg, title=title, icon=icon, xpos=xpos, ypos=ypos)
|
|
return
|
|
|
|
screen achievement_window(msg="", title="", icon=None, xpos=0, ypos=60):
|
|
tag popup_window
|
|
layer "interface"
|
|
|
|
frame:
|
|
style "empty"
|
|
at popup_animation(time=5.0, xx=-410)
|
|
pos (xpos, ypos)
|
|
xsize 410
|
|
ysize 96
|
|
|
|
add gui.format("interface/achievements/{}/box.webp")
|
|
if icon:
|
|
frame:
|
|
style "empty"
|
|
pos (6, 6)
|
|
xsize 84
|
|
ysize 84
|
|
$ image_zoom = crop_image_zoom(icon, 84, 84)
|
|
if 'head' in icon:
|
|
add image_zoom align (0.5, 1.0) yoffset -1
|
|
else:
|
|
add image_zoom align (0.5, 0.5)
|
|
|
|
add "interface/achievements/glass.webp"
|
|
frame:
|
|
style "empty"
|
|
xpos 96
|
|
xsize 314
|
|
vbox:
|
|
ypos 12
|
|
spacing 10
|
|
xalign 0.5
|
|
text title size 18 xalign 0.5 xanchor 0.5
|
|
text msg size 14 xalign 0.5 xanchor 0.5
|
|
timer 6.0 action Hide("achievement_window")
|
|
|
|
transform rotate_circular():
|
|
on show, appear, start:
|
|
subpixel True
|
|
rotate 0
|
|
linear 7.0 rotate 360
|
|
repeat
|
|
|
|
####################################
|
|
############# Menu #################
|
|
####################################
|
|
|
|
label achievement:
|
|
$ gui.in_context("achievement_menu")
|
|
jump main_room_menu
|
|
|
|
label achievement_menu(xx=150, yy=90):
|
|
|
|
python:
|
|
achievement_categories_sorted = ["All", "General", "Characters", "Cardgame", "Mirror"]
|
|
|
|
items_shown = 36
|
|
current_page = 0
|
|
current_category = achievement_categories_sorted[0]
|
|
current_filter = None
|
|
current_sorting = "Unlocked"
|
|
|
|
category_items = list(persistent.achievements.items())
|
|
menu_items = achievement_sortfilter(category_items, current_sorting, current_filter)
|
|
menu_items_length = len(menu_items)
|
|
current_item = next(iter(menu_items), None)
|
|
|
|
renpy.show_screen("achievements", xx, yy)
|
|
|
|
label .after_init:
|
|
|
|
python:
|
|
renpy.dynamic(__choice = ui.interact())
|
|
|
|
if __choice[0] == "select":
|
|
current_item = __choice[1]
|
|
elif __choice[0] == "category":
|
|
current_category = __choice[1]
|
|
if current_category == "All":
|
|
category_items = list(persistent.achievements.items())
|
|
else:
|
|
category_items = [x for x in list(persistent.achievements.items()) if current_category in x[1][0]]
|
|
menu_items = achievement_sortfilter(category_items, current_sorting, current_filter)
|
|
menu_items_length = len(menu_items)
|
|
current_page = 0
|
|
current_item = next(iter(menu_items), None)
|
|
elif __choice == "inc":
|
|
current_page += 1
|
|
elif __choice == "dec":
|
|
current_page += -1
|
|
elif __choice == "filter":
|
|
if current_filter is None:
|
|
current_filter = "Locked"
|
|
elif current_filter == "Locked":
|
|
current_filter = "Unlocked"
|
|
elif current_filter == "Unlocked":
|
|
current_filter = "Secret"
|
|
else:
|
|
current_filter = None
|
|
menu_items = achievement_sortfilter(category_items, current_sorting, current_filter)
|
|
menu_items_length = len(menu_items)
|
|
current_page = 0
|
|
current_item = next(iter(menu_items), None)
|
|
elif __choice == "sort":
|
|
if current_sorting == "A-z":
|
|
current_sorting = "z-A"
|
|
elif current_sorting == "z-A":
|
|
current_sorting = "Unlocked"
|
|
elif current_sorting == "Unlocked":
|
|
current_sorting = "Locked"
|
|
else:
|
|
current_sorting = "A-z"
|
|
menu_items = achievement_sortfilter(category_items, current_sorting, current_filter)
|
|
menu_items_length = len(menu_items)
|
|
current_page = 0
|
|
current_item = next(iter(menu_items), None)
|
|
else:
|
|
renpy.hide_screen("achievements")
|
|
renpy.return_statement()
|
|
|
|
jump .after_init
|
|
|
|
screen achievements(xx, yy):
|
|
tag achievements
|
|
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 achievement_menu(xx, yy)
|
|
use achievement_menuitem(xx, yy)
|
|
|
|
screen achievement_menu(xx, yy):
|
|
window:
|
|
style "empty"
|
|
style_prefix gui.theme('achievements')
|
|
pos (xx, yy)
|
|
xysize (207, 454)
|
|
|
|
use invisible_button()
|
|
|
|
add gui.format("interface/achievements/{}/panel_left.webp")
|
|
|
|
vbox:
|
|
style_prefix gui.theme('achievements_categories')
|
|
pos (6, 41)
|
|
for category in achievement_categories_sorted:
|
|
vbox:
|
|
textbutton category:
|
|
selected (current_category == category)
|
|
action Return(["category", category])
|
|
|
|
add gui.format("interface/achievements/{}/spacer_left.webp")
|
|
vbox:
|
|
style_prefix gui.theme('achievements_filters')
|
|
pos (6, 384)
|
|
if current_filter is None:
|
|
textbutton "Show: All" action Return("filter")
|
|
else:
|
|
textbutton "Show: [current_filter]" action Return("filter")
|
|
textbutton "Sort by: [current_sorting]" action Return("sort")
|
|
|
|
screen achievement_menuitem(xx, yy):
|
|
window:
|
|
style "empty"
|
|
pos (xx+217, yy-53)
|
|
xysize (560, 507)
|
|
|
|
use invisible_button()
|
|
|
|
add "interface/achievements/star.webp"
|
|
add gui.format("interface/achievements/{}/panel.webp")
|
|
|
|
text "Achievements" size 22 xalign 0.5 ypos 65
|
|
|
|
text "Unlocked: "+str(len([x for x in menu_items if x[1][3] is True]))+"/[menu_items_length]" size 12 pos (24, 70)
|
|
|
|
# Page counter
|
|
if menu_items_length > items_shown:
|
|
hbox:
|
|
xanchor 1.0
|
|
pos (540, 24)
|
|
spacing 5
|
|
add "interface/page.webp" yanchor 0.5 ypos 53
|
|
text str(current_page+1)+"/"+str(int(math.ceil(menu_items_length/items_shown))) ypos 44 size 16
|
|
vbox:
|
|
pos (570, 186)
|
|
spacing 10
|
|
|
|
imagebutton:
|
|
idle gui.format("interface/frames/{}/arrow_up.webp")
|
|
if not current_page <= 0:
|
|
hover image_hover(gui.format("interface/frames/{}/arrow_up.webp"))
|
|
action Return("dec")
|
|
|
|
imagebutton:
|
|
idle Transform(gui.format("interface/frames/{}/arrow_up.webp"), yzoom = -1.0)
|
|
if current_page < math.ceil((menu_items_length-1)/items_shown)-1:
|
|
hover Transform(image_hover(gui.format("interface/frames/{}/arrow_up.webp")), yzoom = -1.0)
|
|
action Return("inc")
|
|
|
|
# Add items
|
|
for i in range(current_page*items_shown, (current_page*items_shown)+items_shown):
|
|
if i < menu_items_length:
|
|
$ row = (i // 9) % 4
|
|
$ col = i % 9
|
|
frame:
|
|
style "empty"
|
|
xsize 48
|
|
ysize 48
|
|
pos (24+58*(col), 113+58*(row))
|
|
add gui.format("interface/achievements/{}/iconbox.webp")
|
|
|
|
if current_item and current_item[0] == menu_items[i][0]:
|
|
add "interface/achievements/glow.webp" align (0.5, 0.5) zoom 0.105 alpha 0.7 at rotate_circular
|
|
|
|
if menu_items[i][1][4]:
|
|
if menu_items[i][1][3]:
|
|
$ image_zoom = crop_image_zoom(menu_items[i][1][4], 42, 42)
|
|
elif not menu_items[i][1][5]:
|
|
$ image_zoom = crop_image_zoom(menu_items[i][1][4], 42, 42, True)
|
|
else:
|
|
$ image_zoom = crop_image_zoom("interface/achievements/secret.webp", 35, 35, True)
|
|
|
|
if menu_items[i][1][0] == "Characters" and not (menu_items[i][1][5] is True and not menu_items[i][1][3] is True):
|
|
add image_zoom align (0.5, 1.0) yoffset -3
|
|
else:
|
|
add image_zoom align (0.5, 0.5)
|
|
|
|
button:
|
|
style gui.theme("overlay_button")
|
|
background "interface/achievements/glass_iconbox.webp"
|
|
xsize 48 ysize 48
|
|
action Return(["select", menu_items[i]])
|
|
if menu_items[i][1][5] and not menu_items[i][1][3]:
|
|
tooltip "???"
|
|
else:
|
|
tooltip str(menu_items[i][1][1])
|
|
|
|
if current_item:
|
|
frame:
|
|
style "empty"
|
|
xsize 96
|
|
ysize 96
|
|
pos (24, 375)
|
|
add gui.format("interface/achievements/{}/icon_selected.webp")
|
|
if current_item[1][4]:
|
|
if current_item[1][3]:
|
|
$ image_zoom = crop_image_zoom(current_item[1][4], 84, 84)
|
|
else:
|
|
if current_item[1][5]:
|
|
$ image_zoom = crop_image_zoom("interface/achievements/secret.webp", 70, 70, True)
|
|
else:
|
|
$ image_zoom = crop_image_zoom(current_item[1][4], 84, 84, True)
|
|
if current_item[1][0] == "Characters" and not (current_item[1][5] is True and not current_item[1][3] is True):
|
|
add image_zoom align (0.5, 1.0) yoffset -7
|
|
else:
|
|
add image_zoom align (0.5, 0.5)
|
|
add "interface/achievements/glass_selected.webp" pos (6, 6)
|
|
|
|
add gui.format("interface/achievements/{}/highlight.webp") pos (112, 375)
|
|
add gui.format("interface/achievements/{}/spacer.webp") pos (120, 398)
|
|
hbox:
|
|
spacing 5
|
|
xalign 0.5
|
|
text current_item[1][1] ypos 380 size 16 xoffset 45
|
|
if current_item[1][3]:
|
|
add "interface/unlocked_True.webp" xoffset 45 ypos 377
|
|
else:
|
|
add "interface/unlocked_False.webp" xoffset 45 ypos 377
|
|
hbox:
|
|
pos (132, 407)
|
|
xsize 410
|
|
if current_item[1][3]:
|
|
text current_item[1][2] size 12
|
|
else:
|
|
if current_item[1][5]:
|
|
text "???" size 12
|
|
else:
|
|
text current_item[1][2] size 12
|
|
|
|
# Category styles
|
|
style achievements_categories_button is empty:
|
|
xysize (195, 16)
|
|
|
|
style dark_achievements_categories_button:
|
|
hover_background "interface/achievements/gray/highlight_left.webp"
|
|
selected_background "interface/achievements/gray/highlight_left.webp"
|
|
|
|
style light_achievements_categories_button:
|
|
hover_background "interface/achievements/gold/highlight_left.webp"
|
|
selected_background "interface/achievements/gold/highlight_left.webp"
|
|
|
|
style achievements_categories_button_text is text:
|
|
xalign 0.5
|
|
outlines []
|
|
|
|
# style dark_achievements_categories_button_text:
|
|
# take dark_button_text
|
|
|
|
# style light_achievements_categories_button_text:
|
|
# take light_button_text
|
|
|
|
# Filter styles
|
|
style achievements_filters_button is empty:
|
|
xysize (195, 32)
|
|
|
|
style dark_achievements_filters_button:
|
|
hover_background "#7d75aa40"
|
|
|
|
style light_achievements_filters_button:
|
|
hover_background "#e3ba7140"
|
|
|
|
style achievements_filters_button_text is default:
|
|
align (0.5, 0.5)
|
|
size 12
|
|
outlines []
|