From 7c7fb38dd802a9d63227b3118fd624688f314f9f Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Mon, 3 Apr 2023 00:34:45 -0500 Subject: [PATCH] Merge milestones and achievements Yay for removing a whole redundant feature! --- src/data/common.tsx | 36 ++-- src/features/achievements/Achievement.vue | 82 +++++++- src/features/achievements/achievement.tsx | 141 ++++++++++++- src/features/milestones/Milestone.vue | 128 ------------ src/features/milestones/milestone.tsx | 235 ---------------------- 5 files changed, 226 insertions(+), 396 deletions(-) delete mode 100644 src/features/milestones/Milestone.vue delete mode 100644 src/features/milestones/milestone.tsx diff --git a/src/data/common.tsx b/src/data/common.tsx index befb408..d163f72 100644 --- a/src/data/common.tsx +++ b/src/data/common.tsx @@ -1,10 +1,10 @@ import Collapsible from "components/layout/Collapsible.vue"; +import { GenericAchievement } from "features/achievements/achievement"; import type { Clickable, ClickableOptions, GenericClickable } from "features/clickables/clickable"; import { createClickable } from "features/clickables/clickable"; import type { GenericConversion } from "features/conversion"; import type { CoercableComponent, JSXFunction, OptionsFunc, Replace } from "features/feature"; import { jsx, setDefault } from "features/feature"; -import { GenericMilestone } from "features/milestones/milestone"; import { displayResource, Resource } from "features/resources/resource"; import type { GenericTree, GenericTreeNode, TreeNode, TreeNodeOptions } from "features/trees/tree"; import { createTreeNode } from "features/trees/tree"; @@ -384,35 +384,35 @@ export function colorText(textToColor: string, color = "var(--accent2)"): JSX.El } /** - * Creates a collapsible display of a list of milestones - * @param milestones A dictionary of the milestones to display, inserted in the order from easiest to hardest + * Creates a collapsible display of a list of achievements + * @param achievements A dictionary of the achievements to display, inserted in the order from easiest to hardest */ -export function createCollapsibleMilestones(milestones: Record) { - // Milestones are typically defined from easiest to hardest, and we want to show hardest first - const orderedMilestones = Object.values(milestones).reverse(); - const collapseMilestones = persistent(true, false); - const lockedMilestones = computed(() => - orderedMilestones.filter(m => m.earned.value === false) +export function createCollapsibleAchievements(achievements: Record) { + // Achievements are typically defined from easiest to hardest, and we want to show hardest first + const orderedAchievements = Object.values(achievements).reverse(); + const collapseAchievements = persistent(true, false); + const lockedAchievements = computed(() => + orderedAchievements.filter(m => m.earned.value === false) ); const { firstFeature, collapsedContent, hasCollapsedContent } = getFirstFeature( - orderedMilestones, + orderedAchievements, m => m.earned.value ); const display = jsx(() => { - const milestonesToDisplay = [...lockedMilestones.value]; + const achievementsToDisplay = [...lockedAchievements.value]; if (firstFeature.value) { - milestonesToDisplay.push(firstFeature.value); + achievementsToDisplay.push(firstFeature.value); } return renderColJSX( - ...milestonesToDisplay, + ...achievementsToDisplay, jsx(() => ( @@ -420,7 +420,7 @@ export function createCollapsibleMilestones(milestones: Record - + - - - diff --git a/src/features/milestones/milestone.tsx b/src/features/milestones/milestone.tsx deleted file mode 100644 index 0a973db..0000000 --- a/src/features/milestones/milestone.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import Select from "components/fields/Select.vue"; -import type { - CoercableComponent, - GenericComponent, - OptionsFunc, - Replace, - StyleValue -} from "features/feature"; -import { - Component, - GatherProps, - getUniqueID, - isVisible, - jsx, - setDefault, - Visibility -} from "features/feature"; -import MilestoneComponent from "features/milestones/Milestone.vue"; -import { globalBus } from "game/events"; -import "game/notifications"; -import type { Persistent } from "game/persistence"; -import { persistent } from "game/persistence"; -import player from "game/player"; -import settings, { registerSettingField } from "game/settings"; -import { camelToTitle } from "util/common"; -import type { - Computable, - GetComputableType, - GetComputableTypeWithDefault, - ProcessedComputable -} from "util/computed"; -import { processComputable } from "util/computed"; -import { createLazyProxy } from "util/proxies"; -import { coerceComponent, isCoercableComponent } from "util/vue"; -import { computed, unref, watchEffect } from "vue"; -import { useToast } from "vue-toastification"; - -const toast = useToast(); - -export const MilestoneType = Symbol("Milestone"); - -export enum MilestoneDisplay { - All = "all", - //Last = "last", - Configurable = "configurable", - Incomplete = "incomplete", - None = "none" -} - -export interface MilestoneOptions { - visibility?: Computable; - shouldEarn?: () => boolean; - style?: Computable; - classes?: Computable>; - display?: Computable< - | CoercableComponent - | { - requirement: CoercableComponent; - effectDisplay?: CoercableComponent; - optionsDisplay?: CoercableComponent; - } - >; - showPopups?: Computable; - onComplete?: VoidFunction; -} - -export interface BaseMilestone { - id: string; - earned: Persistent; - complete: VoidFunction; - type: typeof MilestoneType; - [Component]: GenericComponent; - [GatherProps]: () => Record; -} - -export type Milestone = Replace< - T & BaseMilestone, - { - visibility: GetComputableTypeWithDefault; - style: GetComputableType; - classes: GetComputableType; - display: GetComputableType; - showPopups: GetComputableType; - } ->; - -export type GenericMilestone = Replace< - Milestone, - { - visibility: ProcessedComputable; - } ->; - -export function createMilestone( - optionsFunc?: OptionsFunc -): Milestone { - const earned = persistent(false, false); - return createLazyProxy(() => { - const milestone = optionsFunc?.() ?? ({} as ReturnType>); - milestone.id = getUniqueID("milestone-"); - milestone.type = MilestoneType; - milestone[Component] = MilestoneComponent as GenericComponent; - - milestone.earned = earned; - milestone.complete = function () { - const genericMilestone = milestone as GenericMilestone; - earned.value = true; - genericMilestone.onComplete?.(); - if (genericMilestone.display != null && unref(genericMilestone.showPopups) === true) { - const display = unref(genericMilestone.display); - const Display = coerceComponent( - isCoercableComponent(display) ? display : display.requirement - ); - toast( - <> -

Milestone earned!

-
- {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} - {/* @ts-ignore */} - -
- - ); - } - }; - - processComputable(milestone as T, "visibility"); - setDefault(milestone, "visibility", Visibility.Visible); - const visibility = milestone.visibility as ProcessedComputable; - milestone.visibility = computed(() => { - const display = unref((milestone as GenericMilestone).display); - switch (settings.msDisplay) { - default: - case MilestoneDisplay.All: - return unref(visibility); - case MilestoneDisplay.Configurable: - if ( - unref(milestone.earned) && - !( - display != null && - typeof display == "object" && - "optionsDisplay" in (display as Record) - ) - ) { - return Visibility.None; - } - return unref(visibility); - case MilestoneDisplay.Incomplete: - if (unref(milestone.earned)) { - return Visibility.None; - } - return unref(visibility); - case MilestoneDisplay.None: - return Visibility.None; - } - }); - - processComputable(milestone as T, "style"); - processComputable(milestone as T, "classes"); - processComputable(milestone as T, "display"); - processComputable(milestone as T, "showPopups"); - - milestone[GatherProps] = function (this: GenericMilestone) { - const { visibility, display, style, classes, earned, id } = this; - return { visibility, display, style: unref(style), classes, earned, id }; - }; - - if (milestone.shouldEarn) { - const genericMilestone = milestone as GenericMilestone; - watchEffect(() => { - if (settings.active !== player.id) return; - if ( - !genericMilestone.earned.value && - isVisible(genericMilestone.visibility) && - genericMilestone.shouldEarn?.() - ) { - genericMilestone.earned.value = true; - genericMilestone.onComplete?.(); - if ( - genericMilestone.display != null && - unref(genericMilestone.showPopups) === true - ) { - const display = unref(genericMilestone.display); - const Display = coerceComponent( - isCoercableComponent(display) ? display : display.requirement - ); - toast( - <> -

Milestone earned!

-
- {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} - {/* @ts-ignore */} - -
- - ); - } - } - }); - } - - return milestone as unknown as Milestone; - }); -} - -declare module "game/settings" { - interface Settings { - msDisplay: MilestoneDisplay; - } -} - -globalBus.on("loadSettings", settings => { - setDefault(settings, "msDisplay", MilestoneDisplay.All); -}); - -const msDisplayOptions = Object.values(MilestoneDisplay).map(option => ({ - label: camelToTitle(option), - value: option -})); - -registerSettingField( - jsx(() => ( -