Kembali ke katalog plugin
game
topgame
Lihat leaderboard skor game
See the game score leaderboard
plugins/game/topgame.js
Lokasi file di repo kana-md
2
Perintah termasuk alias
3.4 KB
Ukuran file sumber
4/11/2026
Update terakhir, commit b7ba7f8
Daftar perintah
Ketuk tombol salin untuk menyalin perintah, lalu tempel di chat WhatsApp bot KANA.
.topgame.topskorCara pakai
.topgame [id]
Contoh
.topgame hello
Kode sumber plugin
Cara pasang: simpan file ini ke folder plugins/game/ di bot KANA kamu, lalu restart bot. Pemilik source code lain bisa mengambil update plugin terbaru dari halaman ini kapan saja.
import { listGames } from '../../src/services/game-catalog.js'
import { sendButtons } from '../../src/ui/buttons.js'
export const config = {
name: 'topgame',
alias: ['topskor'],
category: 'game',
description: { id: 'Lihat leaderboard skor game', en: 'See the game score leaderboard' },
usage: '.topgame [id]',
example: '.topgame hello',
cooldown: 3,
}
export const i18n = {
id: {
topgame: {
title: 'Leaderboard KANA',
summaryTitle: '🏆 Juara tiap game sejauh ini:',
summaryLine: '🏆 {game} : {name} ({score})',
boardTitle: '🏆 Top skor {game}:',
boardLine: '{rank}. {name} : {score}',
empty: 'Belum ada skor tercatat nih~ Main dulu lewat .games, jadilah yang pertama cetak skor yaa! {mood}',
emptyGame: 'Belum ada skor buat game ini nih~ Main lewat .game {id} dan jadilah yang pertama yaa! {mood}',
unknown: 'Ehh, game "{id}" nggak ada nih. Game yang ada: {list}~',
footer: 'KANA, bot WhatsApp moe',
gamesButton: '🎮 Daftar Game',
},
},
en: {
topgame: {
title: 'KANA Leaderboard',
summaryTitle: '🏆 Champions of each game so far:',
summaryLine: '🏆 {game} : {name} ({score})',
boardTitle: '🏆 Top scores for {game}:',
boardLine: '{rank}. {name} : {score}',
empty: 'No scores recorded yet~ Play via .games and be the first to set one! {mood}',
emptyGame: 'No scores for this game yet~ Play via .game {id} and be the first one! {mood}',
unknown: 'Eh, game "{id}" does not exist. Available games: {list}~',
footer: 'KANA, moe WhatsApp bot',
gamesButton: '🎮 Game List',
},
},
}
function sortedEntries(board) {
return Object.entries(board ?? {})
.map(([digit, entry]) => ({ digit, name: entry?.name || digit, score: Number(entry?.score) || 0 }))
.sort((a, b) => b.score - a.score)
}
export const test = { input: '.topgame', expect: /skor|score/i }
export async function handler(ctx) {
const games = await listGames()
const replies = [
...games.slice(0, 5).map((g) => ({ text: `🏆 ${g.title}`.slice(0, 25), id: `.topgame ${g.id}` })),
{ text: ctx.t('topgame.gamesButton'), id: '.games' },
]
const sendBoard = (body) =>
sendButtons(ctx.sock, ctx.chat, {
title: ctx.t('topgame.title'),
body,
footer: ctx.t('menu.footer'),
replies,
textFallback: body,
})
const id = (ctx.args?.[0] || '').toLowerCase()
if (id) {
const meta = games.find((g) => g.id === id)
if (!meta) {
return ctx.reply(ctx.t('topgame.unknown', { id, list: games.map((g) => g.id).join(', ') || '-' }))
}
const board = await ctx.storage.get('scores', meta.id)
const top = sortedEntries(board).slice(0, 10)
if (!top.length) return sendBoard(ctx.t('topgame.emptyGame', { id: meta.id, mood: ctx.say('gagal') }))
const body = [
ctx.t('topgame.boardTitle', { game: meta.title }),
...top.map((e, i) => ctx.t('topgame.boardLine', { rank: i + 1, name: e.name, score: e.score })),
].join('\n')
return sendBoard(body)
}
const lines = []
for (const g of games) {
const board = await ctx.storage.get('scores', g.id)
const top = sortedEntries(board)
if (top.length) lines.push(ctx.t('topgame.summaryLine', { game: g.title, name: top[0].name, score: top[0].score }))
}
if (!lines.length) return sendBoard(ctx.t('topgame.empty', { mood: ctx.say('senang') }))
return sendBoard([ctx.t('topgame.summaryTitle'), ...lines].join('\n'))
}
