add a secret achievement

This commit is contained in:
syuilo 2023-01-22 20:22:38 +09:00
parent 80a400a67c
commit 42f3d9188b
4 changed files with 88 additions and 46 deletions

View File

@ -1105,6 +1105,9 @@ _achievements:
title: "I Love Misskey" title: "I Love Misskey"
description: "\"I ❤ #Misskey\"を投稿した" description: "\"I ❤ #Misskey\"を投稿した"
flavor: "Misskeyを使ってくださりありがとうございます by 開発チーム" flavor: "Misskeyを使ってくださりありがとうございます by 開発チーム"
_foundTreasure:
title: "宝探し"
description: "隠されたお宝を発見した"
_client30min: _client30min:
title: "ひとやすみ" title: "ひとやすみ"
description: "クライアントを起動してから30分以上経過した" description: "クライアントを起動してから30分以上経過した"

View File

@ -62,6 +62,7 @@ const ACHIEVEMENT_TYPES = [
'collectAchievements30', 'collectAchievements30',
'viewAchievements3min', 'viewAchievements3min',
'iLoveMisskey', 'iLoveMisskey',
'foundTreasure',
'client30min', 'client30min',
'noteDeletedWithin1min', 'noteDeletedWithin1min',
'postedAtLateNight', 'postedAtLateNight',

View File

@ -4,12 +4,15 @@
<div style="overflow: clip;"> <div style="overflow: clip;">
<MkSpacer :content-max="600" :margin-min="20"> <MkSpacer :content-max="600" :margin-min="20">
<div class="_gaps_m znqjceqz"> <div class="_gaps_m znqjceqz">
<div ref="containerEl" v-panel class="about" :class="{ playing: easterEggEngine != null }"> <div v-panel class="about">
<div ref="containerEl" class="container" :class="{ playing: easterEggEngine != null }">
<img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/> <img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
<div class="misskey">Misskey</div> <div class="misskey">Misskey</div>
<div class="version">v{{ version }}</div> <div class="version">v{{ version }}</div>
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span> <span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div> </div>
<button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button>
</div>
<div style="text-align: center;"> <div style="text-align: center;">
{{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a> {{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a>
</div> </div>
@ -70,6 +73,8 @@ import { i18n } from '@/i18n';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import * as os from '@/os'; import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements';
import { $i } from '@/account';
const patrons = [ const patrons = [
'まっちゃとーにゅ', 'まっちゃとーにゅ',
@ -152,6 +157,8 @@ const patrons = [
'pixeldesu', 'pixeldesu',
]; ];
let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));
let easterEggReady = false; let easterEggReady = false;
let easterEggEmojis = $ref([]); let easterEggEmojis = $ref([]);
let easterEggEngine = $ref(null); let easterEggEngine = $ref(null);
@ -187,6 +194,11 @@ function iLoveMisskey() {
}); });
} }
function getTreasure() {
thereIsTreasure = false;
claimAchievement('foundTreasure');
}
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (easterEggEngine) { if (easterEggEngine) {
easterEggEngine.stop(); easterEggEngine.stop();
@ -206,10 +218,27 @@ definePageMetadata({
<style lang="scss" scoped> <style lang="scss" scoped>
.znqjceqz { .znqjceqz {
> .about { > .about {
position: relative;
border-radius: var(--radius);
> .treasure {
position: absolute;
top: 55px;
left: 0;
right: 0;
margin: 0 auto;
width: min-content;
> .treasureImg {
width: 25px;
vertical-align: bottom;
}
}
> .container {
position: relative; position: relative;
text-align: center; text-align: center;
padding: 16px; padding: 16px;
border-radius: var(--radius);
&.playing { &.playing {
&, * { &, * {
@ -230,6 +259,8 @@ definePageMetadata({
width: 80px; width: 80px;
margin: 0 auto; margin: 0 auto;
border-radius: 16px; border-radius: 16px;
position: relative;
z-index: 1;
} }
> .misskey { > .misskey {
@ -257,4 +288,5 @@ definePageMetadata({
} }
} }
} }
}
</style> </style>

View File

@ -58,6 +58,7 @@ export const ACHIEVEMENT_TYPES = [
'collectAchievements30', 'collectAchievements30',
'viewAchievements3min', 'viewAchievements3min',
'iLoveMisskey', 'iLoveMisskey',
'foundTreasure',
'client30min', 'client30min',
'noteDeletedWithin1min', 'noteDeletedWithin1min',
'postedAtLateNight', 'postedAtLateNight',
@ -331,6 +332,11 @@ export const ACHIEVEMENT_BADGES = {
bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))', bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))',
frame: 'silver', frame: 'silver',
}, },
'foundTreasure': {
img: '/fluent-emoji/1f3c6.png',
bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))',
frame: 'gold',
},
'client30min': { 'client30min': {
img: '/fluent-emoji/1f552.png', img: '/fluent-emoji/1f552.png',
bg: 'linear-gradient(0deg, rgb(220 223 225), rgb(172 192 207))', bg: 'linear-gradient(0deg, rgb(220 223 225), rgb(172 192 207))',
@ -437,7 +443,7 @@ export const ACHIEVEMENT_BADGES = {
frame: 'bronze' | 'silver' | 'gold' | 'platinum'; frame: 'bronze' | 'silver' | 'gold' | 'platinum';
}>; }>;
export const claimedAchievements = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : []; export const claimedAchievements: typeof ACHIEVEMENT_TYPES[number][] = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : [];
const claimingQueue = new Set<string>(); const claimingQueue = new Set<string>();