feat(achievements): remove secret achievements and add new ones. also play sound only when notification comes up instead of instantly
This commit is contained in:
@@ -6,6 +6,8 @@ const { onRender } = useScreen();
|
|||||||
const achievements = useAchievementsStore();
|
const achievements = useAchievementsStore();
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
|
const confetti = useConfetti();
|
||||||
|
|
||||||
const queue = ref<Achievement[]>([]);
|
const queue = ref<Achievement[]>([]);
|
||||||
const currentAchievement = ref<Achievement | null>(null);
|
const currentAchievement = ref<Achievement | null>(null);
|
||||||
const x = ref(LOGICAL_WIDTH);
|
const x = ref(LOGICAL_WIDTH);
|
||||||
@@ -20,16 +22,16 @@ const NOTIF_X_VISIBLE = LOGICAL_WIDTH - NOTIF_WIDTH;
|
|||||||
const TEXT_X_OFFSET = LOGO_SIZE + PADDING * 2;
|
const TEXT_X_OFFSET = LOGO_SIZE + PADDING * 2;
|
||||||
const LINE_HEIGHT = 8;
|
const LINE_HEIGHT = 8;
|
||||||
|
|
||||||
achievements.$onAction(({ name, args, after }) => {
|
watch(
|
||||||
if (name === "unlock") {
|
() => achievements.unlocked,
|
||||||
after((wasUnlocked) => {
|
(newVal, oldVal) => {
|
||||||
if (wasUnlocked) {
|
const added = newVal.filter((id) => !oldVal?.includes(id));
|
||||||
queue.value.push(args[0]);
|
for (const id of added) {
|
||||||
processQueue();
|
queue.value.push(id);
|
||||||
}
|
}
|
||||||
});
|
if (added.length > 0) processQueue();
|
||||||
}
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
const processQueue = () => {
|
const processQueue = () => {
|
||||||
if (isAnimating.value || queue.value.length === 0) return;
|
if (isAnimating.value || queue.value.length === 0) return;
|
||||||
@@ -40,6 +42,14 @@ const processQueue = () => {
|
|||||||
currentAchievement.value = next;
|
currentAchievement.value = next;
|
||||||
isAnimating.value = true;
|
isAnimating.value = true;
|
||||||
|
|
||||||
|
assets.audio.messageReceived.play(0.5);
|
||||||
|
|
||||||
|
if (next === "all_achievements") {
|
||||||
|
confetti.spawn();
|
||||||
|
} else {
|
||||||
|
confetti.spawn(50, 175);
|
||||||
|
}
|
||||||
|
|
||||||
gsap
|
gsap
|
||||||
.timeline()
|
.timeline()
|
||||||
.to(x, {
|
.to(x, {
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ const handleActivateA = async (button: typeof selected.value) => {
|
|||||||
|
|
||||||
if (button === "git") {
|
if (button === "git") {
|
||||||
achievements.unlock("contact_git_visit");
|
achievements.unlock("contact_git_visit");
|
||||||
|
} else if (button === "linkedin") {
|
||||||
|
achievements.unlock("contact_linkedin_visit");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -291,13 +291,6 @@ const handleActivateA = () => {
|
|||||||
achievements.unlock("settings_color_change");
|
achievements.unlock("settings_color_change");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!achievements.advancement.colors.includes(app.color.hex)) {
|
|
||||||
achievements.advancement.colors.push(app.color.hex);
|
|
||||||
if (achievements.advancement.colors.length === APP_COLORS.flat().length) {
|
|
||||||
achievements.unlock("settings_color_try_all");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmationModal.open({
|
confirmationModal.open({
|
||||||
text: $t("settings.user.color.confirmation"),
|
text: $t("settings.user.color.confirmation"),
|
||||||
onClosed: async () => {
|
onClosed: async () => {
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useKeyDown(async ({ key, ndsButton, repeated }) => {
|
useKeyDown(async ({ key, repeated }) => {
|
||||||
if (!repeated && key.toLocaleLowerCase() === "h") {
|
if (!repeated && key.toLocaleLowerCase() === "h") {
|
||||||
if (app.hintsVisible) {
|
if (app.hintsVisible) {
|
||||||
hideHelpLabels();
|
hideHelpLabels();
|
||||||
|
|||||||
@@ -13,43 +13,34 @@ export const ACHIEVEMENTS = [
|
|||||||
// contact
|
// contact
|
||||||
{ id: "contact_visit", secret: false },
|
{ id: "contact_visit", secret: false },
|
||||||
{ id: "contact_git_visit", secret: false },
|
{ id: "contact_git_visit", secret: false },
|
||||||
|
{ id: "contact_linkedin_visit", secret: false },
|
||||||
// settings
|
// settings
|
||||||
{ id: "settings_color_change", secret: false },
|
{ id: "settings_color_change", secret: false },
|
||||||
|
{ id: "settings_visit_all", secret: false },
|
||||||
// snake
|
// snake
|
||||||
{ id: "snake_score_25", secret: false },
|
{ id: "snake_score_25", secret: false },
|
||||||
// 2048
|
// 2048
|
||||||
{ id: "2048_score_512", secret: false },
|
{ id: "2048_score_512", secret: false },
|
||||||
// taptap
|
// taptap
|
||||||
{ id: "taptap_score_20", secret: false },
|
{ id: "taptap_score_20", secret: false },
|
||||||
// secrets
|
// meta
|
||||||
{ id: "settings_color_try_all", secret: true },
|
{ id: "all_achievements", secret: false },
|
||||||
{ id: "settings_visit_all", secret: true },
|
|
||||||
{ id: "contact_36_notifications", secret: true },
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type Achievement = (typeof ACHIEVEMENTS)[number]["id"];
|
export type Achievement = (typeof ACHIEVEMENTS)[number]["id"];
|
||||||
|
|
||||||
export const useAchievementsStore = defineStore("achievements", () => {
|
export const useAchievementsStore = defineStore("achievements", () => {
|
||||||
const app = useAppStore();
|
|
||||||
|
|
||||||
const storage = useLocalStorage(
|
const storage = useLocalStorage(
|
||||||
STORAGE_ID,
|
STORAGE_ID,
|
||||||
{
|
{
|
||||||
unlocked: [] as Achievement[],
|
unlocked: [] as Achievement[],
|
||||||
advancement: {
|
advancement: {
|
||||||
colors: [app.color.hex],
|
|
||||||
visitedSettings: [] as string[],
|
visitedSettings: [] as string[],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ mergeDefaults: true },
|
{ mergeDefaults: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!storage.value.advancement.colors.includes(app.color.hex)) {
|
|
||||||
storage.value.advancement.colors.push(app.color.hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
const confetti = useConfetti();
|
|
||||||
|
|
||||||
const unlock = (name: Achievement) => {
|
const unlock = (name: Achievement) => {
|
||||||
if (storage.value.unlocked.includes(name)) {
|
if (storage.value.unlocked.includes(name)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -57,13 +48,14 @@ export const useAchievementsStore = defineStore("achievements", () => {
|
|||||||
|
|
||||||
storage.value.unlocked.push(name);
|
storage.value.unlocked.push(name);
|
||||||
|
|
||||||
const { assets } = useAssets();
|
if (name !== "all_achievements") {
|
||||||
assets.audio.messageReceived.play(0.5);
|
const othersCount = ACHIEVEMENTS.length - 1;
|
||||||
|
const unlockedOthers = storage.value.unlocked.filter(
|
||||||
if (storage.value.unlocked.length === ACHIEVEMENTS.length) {
|
(id) => id !== "all_achievements" && validIds.has(id as Achievement),
|
||||||
confetti.spawn();
|
).length;
|
||||||
} else {
|
if (unlockedOthers === othersCount) {
|
||||||
confetti.spawn(50, 175);
|
unlock("all_achievements");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -73,18 +65,20 @@ export const useAchievementsStore = defineStore("achievements", () => {
|
|||||||
storage.value = {
|
storage.value = {
|
||||||
unlocked: [],
|
unlocked: [],
|
||||||
advancement: {
|
advancement: {
|
||||||
colors: [app.color.hex],
|
|
||||||
visitedSettings: [],
|
visitedSettings: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validIds = new Set(ACHIEVEMENTS.map((a) => a.id));
|
||||||
|
const unlocked = computed(() =>
|
||||||
|
storage.value.unlocked.filter((id) => validIds.has(id as Achievement)),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
unlocked: computed(() => storage.value.unlocked),
|
unlocked,
|
||||||
advancement: computed(() => storage.value.advancement),
|
advancement: computed(() => storage.value.advancement),
|
||||||
allObtained: computed(
|
allObtained: computed(() => unlocked.value.length === ACHIEVEMENTS.length),
|
||||||
() => storage.value.unlocked.length === ACHIEVEMENTS.length,
|
|
||||||
),
|
|
||||||
unlock,
|
unlock,
|
||||||
reset,
|
reset,
|
||||||
isUnlocked: computed(
|
isUnlocked: computed(
|
||||||
|
|||||||
@@ -86,10 +86,6 @@ export const useContactStore = defineStore("contact", {
|
|||||||
{ notificationsYOffset: 0, duration: 0.075 },
|
{ notificationsYOffset: 0, duration: 0.075 },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.notifications.length === 36) {
|
|
||||||
const achievements = useAchievementsStore();
|
|
||||||
achievements.unlock("contact_36_notifications");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
animateOutro() {
|
animateOutro() {
|
||||||
|
|||||||
@@ -64,9 +64,9 @@
|
|||||||
"snake_score_25": "Score 25 points\nin Snake",
|
"snake_score_25": "Score 25 points\nin Snake",
|
||||||
"2048_score_512": "Reach the 512 tile\nin 2048",
|
"2048_score_512": "Reach the 512 tile\nin 2048",
|
||||||
"taptap_score_20": "Score 20 points\nin TapTap",
|
"taptap_score_20": "Score 20 points\nin TapTap",
|
||||||
"settings_color_try_all": "Try all colors",
|
|
||||||
"settings_visit_all": "Visit all settings\nsubmenus",
|
"settings_visit_all": "Visit all settings\nsubmenus",
|
||||||
"contact_36_notifications": "Trigger 36\nnotifications"
|
"contact_linkedin_visit": "Visit my LinkedIn\nprofile",
|
||||||
|
"all_achievements": "Unlock all\nachievements"
|
||||||
},
|
},
|
||||||
"intro": {
|
"intro": {
|
||||||
"copyright": "WARNING - COPYRIGHT",
|
"copyright": "WARNING - COPYRIGHT",
|
||||||
|
|||||||
@@ -64,9 +64,9 @@
|
|||||||
"snake_score_25": "Marquer 25 points\nà Snake",
|
"snake_score_25": "Marquer 25 points\nà Snake",
|
||||||
"2048_score_512": "Atteindre la tuile 512\nà 2048",
|
"2048_score_512": "Atteindre la tuile 512\nà 2048",
|
||||||
"taptap_score_20": "Marquer 20 points\nà TapTap",
|
"taptap_score_20": "Marquer 20 points\nà TapTap",
|
||||||
"settings_color_try_all": "Essayer toutes les\ncouleurs",
|
|
||||||
"settings_visit_all": "Visiter tous les\nparamètres",
|
"settings_visit_all": "Visiter tous les\nparamètres",
|
||||||
"contact_36_notifications": "Déclencher 36\nnotifications"
|
"contact_linkedin_visit": "Visiter mon profil\nLinkedIn",
|
||||||
|
"all_achievements": "Débloquer tous\nles succès"
|
||||||
},
|
},
|
||||||
"intro": {
|
"intro": {
|
||||||
"copyright": "AVERTISSEMENT - COPYRIGHT",
|
"copyright": "AVERTISSEMENT - COPYRIGHT",
|
||||||
|
|||||||
Reference in New Issue
Block a user