117 lines
2.9 KiB
Vue
117 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
const { onRender } = useScreen();
|
|
const store = useAchievementsScreen();
|
|
const achievementsStore = useAchievementsStore();
|
|
|
|
const PROGRESS_BAR_WIDTH = 140;
|
|
const PROGRESS_BAR_HEIGHT = 10;
|
|
const PROGRESS_BAR_X = (LOGICAL_WIDTH - PROGRESS_BAR_WIDTH) / 2;
|
|
const PROGRESS_BAR_Y = ACHIEVEMENTS_HEADER_Y + 27;
|
|
|
|
onMounted(() => {
|
|
store.$reset();
|
|
store.animateIntro();
|
|
});
|
|
|
|
onRender((ctx) => {
|
|
ctx.fillStyle = "#000000";
|
|
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
|
|
|
// header
|
|
ctx.globalAlpha = store.isIntro
|
|
? store.intro.stage1Opacity
|
|
: store.isOutro
|
|
? store.outro.stage2Opacity
|
|
: 1;
|
|
ctx.fillStyle = "#ffffff";
|
|
ctx.textBaseline = "top";
|
|
|
|
// title
|
|
ctx.font = "10px NDS10";
|
|
fillTextHCentered(
|
|
ctx,
|
|
$t("achievementsScreen.title"),
|
|
0,
|
|
ACHIEVEMENTS_HEADER_Y,
|
|
LOGICAL_WIDTH,
|
|
);
|
|
|
|
// progress text
|
|
const unlockedCount = achievementsStore.unlocked.length;
|
|
const totalCount = ACHIEVEMENTS.length;
|
|
|
|
ctx.font = "7px NDS7";
|
|
fillTextHCentered(
|
|
ctx,
|
|
`${unlockedCount}/${totalCount}`,
|
|
0,
|
|
ACHIEVEMENTS_HEADER_Y + 13,
|
|
LOGICAL_WIDTH,
|
|
);
|
|
|
|
// progress bar
|
|
ctx.fillStyle = "#ffffff";
|
|
ctx.fillRect(PROGRESS_BAR_X, PROGRESS_BAR_Y, PROGRESS_BAR_WIDTH, 1);
|
|
ctx.fillRect(
|
|
PROGRESS_BAR_X,
|
|
PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT - 1,
|
|
PROGRESS_BAR_WIDTH,
|
|
1,
|
|
);
|
|
ctx.fillRect(
|
|
PROGRESS_BAR_X + PROGRESS_BAR_WIDTH - 1,
|
|
PROGRESS_BAR_Y,
|
|
1,
|
|
PROGRESS_BAR_HEIGHT,
|
|
);
|
|
ctx.fillRect(PROGRESS_BAR_X, PROGRESS_BAR_Y, 1, PROGRESS_BAR_HEIGHT);
|
|
|
|
ctx.fillStyle = "#ffffff";
|
|
const fill =
|
|
(unlockedCount / totalCount) *
|
|
(store.isIntro ? store.intro.progressBar : 1);
|
|
ctx.fillRect(
|
|
PROGRESS_BAR_X + 2,
|
|
PROGRESS_BAR_Y + 2,
|
|
Math.ceil((PROGRESS_BAR_WIDTH - 4) * fill),
|
|
PROGRESS_BAR_HEIGHT - 4,
|
|
);
|
|
|
|
// achievement list (reversed iteration because they appear in cascade)
|
|
ctx.globalAlpha = store.isIntro
|
|
? store.intro.stage1Opacity
|
|
: store.isOutro
|
|
? store.outro.stage1Opacity
|
|
: 1;
|
|
ctx.font = "7px NDS7";
|
|
for (let i = ACHIEVEMENTS_TOP_SCREEN_COUNT - 1; i >= 0; i--) {
|
|
const achievement = ACHIEVEMENTS[i]!;
|
|
const isUnlocked = achievementsStore.isUnlocked(achievement.id);
|
|
|
|
const offset = store.getItemOffset(i);
|
|
if (offset === -ACHIEVEMENTS_LINE_HEIGHT) continue;
|
|
|
|
const baseY = ACHIEVEMENTS_LIST_START_Y + i * ACHIEVEMENTS_LINE_HEIGHT;
|
|
const y = baseY + offset;
|
|
|
|
// needed for the sliding animation
|
|
ctx.fillStyle = "#000000";
|
|
ctx.fillRect(0, y, LOGICAL_WIDTH, ACHIEVEMENTS_LINE_HEIGHT);
|
|
|
|
ctx.fillStyle = isUnlocked ? "#ffffff" : "#666666";
|
|
drawCheckbox(ctx, ACHIEVEMENTS_X, y, isUnlocked);
|
|
ctx.fillText(
|
|
achievement.secret && !isUnlocked
|
|
? "???"
|
|
: $t(`achievements.${achievement.id}`).replace("\n", " "),
|
|
ACHIEVEMENTS_X + CHECKBOX_SIZE + CHECKBOX_TEXT_GAP,
|
|
y,
|
|
);
|
|
}
|
|
});
|
|
|
|
defineOptions({
|
|
render: () => null,
|
|
});
|
|
</script>
|