From 3b5f35a732448ba8896c9f416f73ffc8872abc29 Mon Sep 17 00:00:00 2001 From: Gouvernathor <44340603+Gouvernathor@users.noreply.github.com> Date: Sat, 18 Nov 2023 03:54:37 +0100 Subject: [PATCH] Rebase the achievements system on the builtin feature a lot of work, but entirely backwards-compatible ! no visible change (no intended ones at least) except maybe performance --- game/scripts/interface/achievements.rpy | 409 ++++++++++++------------ 1 file changed, 211 insertions(+), 198 deletions(-) diff --git a/game/scripts/interface/achievements.rpy b/game/scripts/interface/achievements.rpy index c0f7a323..504b9886 100644 --- a/game/scripts/interface/achievements.rpy +++ b/game/scripts/interface/achievements.rpy @@ -1,123 +1,118 @@ -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], +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": ["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] + "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: - if persistent.achievements is None: - persistent.achievements = achievements_dict.copy() class Achievements(object): + """ + Useless class, to be rolled out. + """ - def __init__(self): - self.achievements = persistent.achievements - self.attempt_repair() - - if config.developer: - self.validate() - - def validate(self): + @staticmethod + def validate(): """Check if icons are loadable at init""" - for i in self.achievements.values(): - if not renpy.loadable(i[4]): - raise IOError(repr(i[4])) + for i in achievements_db.values(): + if not renpy.loadable(i.icon): + raise IOError(repr(i.icon)) - 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. + @staticmethod + def status(id): + return achievement.has(id) - 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): + @staticmethod + def unlock(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 achievement.has(id): + achievement.grant(id) 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]) + renpy.show_screen("achievement_window", msg=achievements_db[id].title, title="Achievement unlocked!", icon=achievements_db[id].icon) + @staticmethod def lock(self, id): - self.achievements[id][3] = False - persistent.achievements[id][3] = False + 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 + """ - def achievement_sortfilter(item, sortby="A-z", filtering=None): if filtering == "Locked": - item = [x for x in item if x[1][3] is False] + lst = (x for x in lst if not achievement.has(x)) elif filtering == "Unlocked": - item = [x for x in item if x[1][3] is True] + lst = filter(achievement.has, lst) elif filtering == "Secret": - item = [x for x in item if x[1][5] is True] + lst = (x for x in lst if achievements_db[x].secret is True) # Always sort alphabetically first. - item = sorted(item, key=lambda x: natsort_key(x[1][1])) + lst = sorted(lst, key=lambda x: natsort_key(achievements_db[x].title)) 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) + 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 item + return lst default achievements = Achievements() @@ -167,61 +162,43 @@ screen achievement_window(msg="", title="", icon=None, xpos=0, ypos=60): text msg size 14 xalign 0.5 xanchor 0.5 timer 6.0 action Hide("achievement_window") -transform rotate_circular(): +transform rotate_circular(t=7): on show, appear, start: subpixel True rotate 0 - linear 7.0 rotate 360 + linear t rotate 360 repeat #################################### ############# Menu ################# #################################### -label achievement: - $ gui.in_context("achievement_menu") - jump main_room_menu +define achievement_categories_sorted = ("All", "General", "Characters", "Cardgame", "Mirror") +define items_shown = 36 -label achievement_menu(xx=150, yy=90): +init python: + class __SetCategory(Action): + def __init__(self, category): + self.category = category - python: - achievement_categories_sorted = ["All", "General", "Characters", "Cardgame", "Mirror"] + def __call__(self): + global current_category + global number_unlocked - 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] + current_category = self.category if current_category == "All": - category_items = list(persistent.achievements.items()) + category_items = achievements_db 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": + 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": @@ -230,11 +207,14 @@ label achievement_menu(xx=150, yy=90): 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": + __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": @@ -243,15 +223,42 @@ label achievement_menu(xx=150, yy=90): 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() + __regen() - jump .after_init + 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 @@ -266,16 +273,16 @@ screen achievements(xx, yy): use close_button fixed: + pos (xx, yy) if settings.get("animations"): at gui_animation - use achievement_menu(xx, yy) - use achievement_menuitem(xx, yy) + use achievement_menu() + use achievement_menuitem() -screen achievement_menu(xx, yy): +screen achievement_menu(): window: style "empty" style_prefix gui.theme('achievements') - pos (xx, yy) xysize (207, 454) use invisible_button() @@ -289,22 +296,22 @@ screen achievement_menu(xx, yy): vbox: textbutton category: selected (current_category == category) - action Return(["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 Return("filter") + textbutton "Show: All" action __Filter() else: - textbutton "Show: [current_filter]" action Return("filter") - textbutton "Sort by: [current_sorting]" action Return("sort") + textbutton "Show: [current_filter]" action __Filter() + textbutton "Sort by: [current_sorting]" action __Sort() -screen achievement_menuitem(xx, yy): +screen achievement_menuitem(): window: style "empty" - pos (xx+217, yy-53) + pos (217, -53) xysize (560, 507) use invisible_button() @@ -314,7 +321,7 @@ screen achievement_menuitem(xx, yy): 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) + text "Unlocked: [number_unlocked]/[menu_items_length]" size 12 pos (24, 70) # Page counter if menu_items_length > items_shown: @@ -332,71 +339,80 @@ screen achievement_menuitem(xx, yy): 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") + 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 Return("inc") + action SetVariable("current_page", current_page+1) + # TODO: in 8.2, replace with IncrementVariable("current_page") # 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 + 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 - 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]: + 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 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 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) - 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 + 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: - add image_zoom align (0.5, 0.5) + yalign .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]: + action SetVariable("current_item", it_item) + if it_item_data.secret and not it_item_unlocked: tooltip "???" else: - tooltip str(menu_items[i][1][1]) + 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[1][4]: - if current_item[1][3]: - $ image_zoom = crop_image_zoom(current_item[1][4], 84, 84) + + 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: - 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) + yalign .5 + add "interface/achievements/glass_selected.webp" pos (6, 6) add gui.format("interface/achievements/{}/highlight.webp") pos (112, 375) @@ -404,21 +420,18 @@ screen achievement_menuitem(xx, yy): hbox: spacing 5 xalign 0.5 - text current_item[1][1] ypos 380 size 16 xoffset 45 - if current_item[1][3]: + 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[1][3]: - text current_item[1][2] size 12 + if current_item_unlocked or not current_item_data.secret: + text current_item_data.description size 12 else: - if current_item[1][5]: - text "???" size 12 - else: - text current_item[1][2] size 12 + text "???" size 12 # Category styles style achievements_categories_button is empty: