Gouvernathor
f0c9aaa153
a lot of work, but entirely backwards-compatible ! no visible change (no intended ones at least) except maybe performance
471 lines
20 KiB
Plaintext
471 lines
20 KiB
Plaintext
init python:
|
|
from collections import namedtuple
|
|
AchievementKind = namedtuple("AchievementKind", ("category", "name", "description", "icon", "secret"))
|
|
AchievementKind.title = AchievementKind.name
|
|
|
|
define achievements_db = {
|
|
# id : (categoryname, title, description, icon, secret)
|
|
"unlockher": AchievementKind("Characters", "Granger Danger", "Awarded for unlocking Hermione Granger.", "interface/icons/head/hermione.webp", False),
|
|
"unlockcho": AchievementKind("Characters", "Chang Dynasty", "Awarded for unlocking Cho Chang.", "interface/icons/head/cho.webp", False),
|
|
"unlocklun": AchievementKind("Characters", "Looney Tunes", "Awarded for unlocking Luna Lovegood.", "interface/icons/head/luna.webp", False),
|
|
"unlockast": AchievementKind("Characters", "Green Peas", "Awarded for unlocking Astoria Greengrass.", "interface/icons/head/astoria.webp", False),
|
|
"unlockton": AchievementKind("Characters", "Nymphadoreador", "Awarded for unlocking Nymphadora Tonks.", "interface/icons/head/tonks.webp", False),
|
|
"overwhored": AchievementKind("Characters", "Overwhored", "Awarded for fully corrupting Hermione.", "interface/icons/head/hermione.webp", False),
|
|
"unlocksus": AchievementKind("Characters", "Boner", "Awarded for unlocking Susan Bones.", "interface/icons/head/susan.webp", False),
|
|
"unlocksna": AchievementKind("Characters", "Strictly colleagues", "Awarded for unlocking Severus Snape.", "interface/icons/head/snape.webp", False),
|
|
"mirror": AchievementKind("Mirror", "Mirror, mirror on the wall..", "Awarded for unlocking the Room of Requirement.", "images/rooms/room_of_requirement/mirror_hover.webp", False),
|
|
"gold": AchievementKind("General", "Gold Digger", "Awarded for having 10,000 gold in total.", "interface/icons/gold.webp", False),
|
|
"drunkard": AchievementKind("General", "Drunken Master", "Awarded for collecting 25 bottles of wine.", "interface/icons/wine.webp", True),
|
|
"workaholic": AchievementKind("General", "Workaholic", "Awarded for completing five full reports.", "interface/icons/generic_scroll.webp", False),
|
|
"fireplace": AchievementKind("General", "Feel the Heat", "Awarded for lighting the fireplace 5 times or more.", "images/rooms/main_room/fireplace/fireplace_idle.webp", True),
|
|
"peta": AchievementKind("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}", "images/rooms/main_room/phoenix/phoenix_01.webp", True),
|
|
"petpal": AchievementKind("General", "Regular stroking", "Awarded for petting the bird 25 times.", "images/rooms/main_room/phoenix/phoenix_01.webp", False),
|
|
"postman": AchievementKind("Cardgame", "Poster Boy", "Awarded for buying all posters from the token shop.", "interface/icons/agrabah_poster.webp", False),
|
|
"hats": AchievementKind("Cardgame", "Mad Hatter", "Awarded for buying all hat decorations from the token shop.", "interface/icons/icon_gambler_hat.webp", False),
|
|
"daddy": AchievementKind("Characters", "Who's your daddy?", "Awarded for letting Hermione call you a {size=-5}(sugar){/size} daddy.", "interface/icons/head/hermione.webp", True),
|
|
"pantiesfap": AchievementKind("Characters", "I sneezed on them...", "Awarded for rubbing one out on Hermione's panties.", "characters/genie/chibis/jerk_off/02.webp", False),
|
|
"pantiesfapcho": AchievementKind("Characters", "Exercise is important", "Awarded for rubbing one out on Cho's panties.", "characters/genie/chibis/jerk_off/02.webp", False),
|
|
"bros": AchievementKind("Characters", "Bros before hoes", "Awarded for becoming best pals with Snape.", "interface/icons/head/snape.webp", False),
|
|
"knock": AchievementKind("Characters", "*Knock* *knock*", "Awarded for telling Hermione to go away during her introductory events.", "images/rooms/main_room/door/door_idle.webp", True),
|
|
"decorator": AchievementKind("Cardgame", "Decorator", "Awarded for decorating the office for the first time.", "interface/icons/stag_trophy.webp", False),
|
|
"flashback": AchievementKind("Cardgame", "Flashback", "Awarded for retelling what actually happened...", "interface/icons/cards.webp", True),
|
|
"start": AchievementKind("General", "Welcome to Hogwarts!", "Awarded for finishing the intro.", "interface/icon.webp", False),
|
|
"export": AchievementKind("General", "Sharing is caring", "Awarded for exporting an outfit through the wardrobe menu.", "interface/wardrobe/icons/load.webp", False),
|
|
"Credits": AchievementKind("General", "New game, who this?", "Awarded for checking out the Credits Menu.", "interface/icons/silver_scroll.webp", False),
|
|
"Cardwin": AchievementKind("Cardgame", "Time to duel", "Awarded for winning your first Card game duel.", "interface/icons/cards.webp", False),
|
|
"puzzle": AchievementKind("General", "Down the hatch!", "Awarded for wasting a bottle of unbelievably rare phoenix tears by drinking it.", "interface/icons/item_potion.webp", True),
|
|
"ending": AchievementKind("General", "Bittersweet Farewell", "Awarded for reaching the original ending.", "interface/icons/silver.webp", True),
|
|
#1.37 HG achievements
|
|
"busted": AchievementKind("Characters", "BUSTED!", "Awarded for getting busted by Hermione when busting a nut.", "interface/icons/head/hermione.webp", False),
|
|
"herstrip": AchievementKind("Characters", "Dance lessons", "Awarded for having Hermione dance naked in front of you... and Snape.", "interface/icons/head/hermione.webp", False),
|
|
"herkiss": AchievementKind("Characters", "First Kiss", "Awarded for having Hermione make out with you-- r... cock...", "interface/icons/head/hermione.webp", False),
|
|
"hertits": AchievementKind("Characters", "Boobs Lover", "Awarded for sticking it between Hermione's fun bags.", "interface/icons/head/hermione.webp", False),
|
|
"headlib": AchievementKind("Characters", "Head Librarian", "Awarded for releasing your seed in Hermione's mouth.", "interface/icons/head/hermione.webp", False),
|
|
"nerdgasm": AchievementKind("Characters", "Nerdgasm", "Awarded for doing the deed with Hermione.", "interface/icons/head/hermione.webp", False)
|
|
}
|
|
|
|
init python hide:
|
|
for name in achievements_db:
|
|
achievement.register(name)
|
|
|
|
# keep the achievements from earlier versions
|
|
if isinstance(persistent.achievements, dict):
|
|
# id : [categoryname, title, description, unlocked, icon, secret]
|
|
for k, v in persistent.achievements.items():
|
|
if v[3]:
|
|
achievement.grant(k)
|
|
del persistent.achievements
|
|
|
|
init python:
|
|
|
|
class Achievements(object):
|
|
"""
|
|
Useless class, to be rolled out.
|
|
"""
|
|
|
|
@staticmethod
|
|
def validate():
|
|
"""Check if icons are loadable at init"""
|
|
for i in achievements_db.values():
|
|
if not renpy.loadable(i.icon):
|
|
raise IOError(repr(i.icon))
|
|
|
|
@staticmethod
|
|
def status(id):
|
|
return achievement.has(id)
|
|
|
|
@staticmethod
|
|
def unlock(id, silent=False):
|
|
if _in_replay:
|
|
return
|
|
|
|
if not achievement.has(id):
|
|
achievement.grant(id)
|
|
|
|
if not silent:
|
|
renpy.play('sounds/achievement.ogg')
|
|
renpy.show_screen("achievement_window", msg=achievements_db[id].title, title="Achievement unlocked!", icon=achievements_db[id].icon)
|
|
|
|
@staticmethod
|
|
def lock(self, id):
|
|
achievement.clear(id)
|
|
|
|
def achievement_sortfilter(lst, sortby="A-z", filtering=None):
|
|
"""
|
|
Takes a list/iterable of achievement ids, returns a list of achievement ids
|
|
"""
|
|
|
|
if filtering == "Locked":
|
|
lst = (x for x in lst if not achievement.has(x))
|
|
elif filtering == "Unlocked":
|
|
lst = filter(achievement.has, lst)
|
|
elif filtering == "Secret":
|
|
lst = (x for x in lst if achievements_db[x].secret is True)
|
|
|
|
# Always sort alphabetically first.
|
|
lst = sorted(lst, key=lambda x: natsort_key(achievements_db[x].title))
|
|
|
|
if sortby == "z-A":
|
|
lst.sort(key=lambda x: natsort_key(achievements_db[x].title), reverse=True)
|
|
elif sortby == "Unlocked":
|
|
lst.sort(key=lambda x: not achievement.has(x))
|
|
elif sortby == "Locked":
|
|
lst.sort(key=achievement.has)
|
|
|
|
return lst
|
|
|
|
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(t=7):
|
|
on show, appear, start:
|
|
subpixel True
|
|
rotate 0
|
|
linear t rotate 360
|
|
repeat
|
|
|
|
####################################
|
|
############# Menu #################
|
|
####################################
|
|
|
|
define achievement_categories_sorted = ("All", "General", "Characters", "Cardgame", "Mirror")
|
|
define items_shown = 36
|
|
|
|
init python:
|
|
class __SetCategory(Action):
|
|
def __init__(self, category):
|
|
self.category = category
|
|
|
|
def __call__(self):
|
|
global current_category
|
|
global number_unlocked
|
|
|
|
current_category = self.category
|
|
if current_category == "All":
|
|
category_items = achievements_db
|
|
else:
|
|
category_items = filter((lambda x: current_category==achievements_db[x].category), achievements_db)
|
|
__regen(category_items)
|
|
number_unlocked = len(tuple(filter(achievement.has, menu_items)))
|
|
|
|
class __Filter(Action):
|
|
# TODO: in 8.2, replace with CycleVariable("current_filter", (None, "Locked", "Unlocked", "Secret"))
|
|
def __call__(self):
|
|
global current_filter
|
|
global number_unlocked
|
|
|
|
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
|
|
__regen()
|
|
number_unlocked = len(tuple(filter(achievement.has, menu_items)))
|
|
|
|
class __Sort(Action):
|
|
# TODO: in 8.2, replace with CycleVariable("current_sorting", ("A-z", "z-A", "Unlocked", "Locked"))
|
|
def __call__(self):
|
|
global current_sorting
|
|
|
|
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"
|
|
__regen()
|
|
|
|
def __regen(category_items=achievements_db):
|
|
global menu_items
|
|
global menu_items_length
|
|
global current_page
|
|
global current_item
|
|
|
|
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)
|
|
renpy.restart_interaction()
|
|
|
|
label achievement:
|
|
$ gui.in_context("achievement_menu")
|
|
jump main_room_menu
|
|
|
|
label achievement_menu(xx=150, yy=90):
|
|
|
|
$ renpy.dynamic(
|
|
current_page = 0,
|
|
current_category = achievement_categories_sorted[0],
|
|
current_filter = None,
|
|
current_sorting = "Unlocked",
|
|
menu_items = achievement_sortfilter(achievements_db, "Unlocked", None),
|
|
number_unlocked = len(tuple(filter(achievement.has, achievements_db)))
|
|
)
|
|
$ renpy.dynamic(
|
|
menu_items_length = len(menu_items),
|
|
current_item = next(iter(menu_items), None),
|
|
)
|
|
|
|
call screen achievements(xx, yy)
|
|
|
|
return
|
|
|
|
screen achievements(xx, yy):
|
|
tag achievements
|
|
zorder 15
|
|
modal True
|
|
|
|
add "gui_fade"
|
|
|
|
if renpy.mobile:
|
|
use close_button_background
|
|
|
|
use close_button
|
|
|
|
fixed:
|
|
pos (xx, yy)
|
|
if settings.get("animations"):
|
|
at gui_animation
|
|
use achievement_menu()
|
|
use achievement_menuitem()
|
|
|
|
screen achievement_menu():
|
|
window:
|
|
style "empty"
|
|
style_prefix gui.theme('achievements')
|
|
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 __SetCategory(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 __Filter()
|
|
else:
|
|
textbutton "Show: [current_filter]" action __Filter()
|
|
textbutton "Sort by: [current_sorting]" action __Sort()
|
|
|
|
screen achievement_menuitem():
|
|
window:
|
|
style "empty"
|
|
pos (217, -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: [number_unlocked]/[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 SetVariable("current_page", current_page-1)
|
|
# TODO: in 8.2, replace with IncrementVariable("current_page", -1)
|
|
|
|
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 SetVariable("current_page", current_page+1)
|
|
# TODO: in 8.2, replace with IncrementVariable("current_page")
|
|
|
|
# Add items
|
|
grid 9 4:
|
|
style "empty"
|
|
pos (24, 113)
|
|
spacing 10
|
|
|
|
for it_item in menu_items[current_page*items_shown:(current_page+1)*items_shown]:
|
|
$ it_item_data = achievements_db[it_item]
|
|
$ it_item_unlocked = achievement.has(it_item)
|
|
frame:
|
|
style "empty"
|
|
xsize 48
|
|
ysize 48
|
|
add gui.format("interface/achievements/{}/iconbox.webp")
|
|
|
|
if current_item and current_item == it_item:
|
|
add "interface/achievements/glow.webp" align (0.5, 0.5) zoom 0.105 alpha 0.7 at rotate_circular
|
|
|
|
if it_item_unlocked or not it_item_data.secret:
|
|
$ image_zoom = crop_image_zoom(it_item_data.icon, 42, 42, not it_item_unlocked)
|
|
else:
|
|
$ image_zoom = crop_image_zoom("interface/achievements/secret.webp", 35, 35, True)
|
|
|
|
add image_zoom:
|
|
xalign .5
|
|
if it_item_data.category == "Characters" and (it_item_unlocked or not it_item_data.secret):
|
|
yalign 1.
|
|
yoffset -3
|
|
else:
|
|
yalign .5
|
|
|
|
button:
|
|
style gui.theme("overlay_button")
|
|
background "interface/achievements/glass_iconbox.webp"
|
|
xsize 48 ysize 48
|
|
action SetVariable("current_item", it_item)
|
|
if it_item_data.secret and not it_item_unlocked:
|
|
tooltip "???"
|
|
else:
|
|
tooltip it_item_data.name
|
|
|
|
if current_item:
|
|
$ current_item_data = achievements_db[current_item]
|
|
$ current_item_unlocked = achievement.has(current_item)
|
|
frame:
|
|
style "empty"
|
|
xsize 96
|
|
ysize 96
|
|
pos (24, 375)
|
|
add gui.format("interface/achievements/{}/icon_selected.webp")
|
|
|
|
if current_item_unlocked or not current_item_data.secret:
|
|
$ image_zoom = crop_image_zoom(current_item_data.icon, 84, 84, not current_item_unlocked)
|
|
else:
|
|
$ image_zoom = crop_image_zoom("interface/achievements/secret.webp", 70, 70, True)
|
|
|
|
add image_zoom:
|
|
xalign .5
|
|
if current_item_data.category == "Characters" and (current_item_unlocked or not current_item_data.secret):
|
|
yalign 1.
|
|
yoffset -7
|
|
else:
|
|
yalign .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_data.name ypos 380 size 16 xoffset 45
|
|
if current_item_unlocked:
|
|
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_unlocked or not current_item_data.secret:
|
|
text current_item_data.description size 12
|
|
else:
|
|
text "???" 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 [] |