Level-Embeds aufgewertet, Server-Footer korrigiert
Server-Monitor: Der Footer behauptete fest "alle 2 min", obwohl das Intervall
seit den einstellbaren Werten aus monitor_interval kommt. Wer im Panel etwas
anderes setzt, bekam eine falsche Angabe. Liest jetzt den echten Wert.
Level-Aufstieg: War als einziges im Community-Bereich reiner Text, waehrend
Geburtstage, Verlosungen und Bewerbungen laengst Embeds sind. Jetzt ueber
brandEmbed mit Avatar, Gesamt-XP und Rest bis zum naechsten Level. Der Text
bleibt die Vorlage aus dem Panel — nur der Rahmen ist neu.
Dazu zeigt das Embed die Belohnungs-Rolle: entweder die gerade vergebene oder
die naechste, auf die man hinspielt. grantRewards() gibt dafuer zurueck, was
wirklich dazukam.
Ist die Vorlage im Panel leer, wirft setDescription('') — der Aufstieg waere
still ausgefallen. Faellt jetzt auf eine schlichte Zeile zurueck.
/rank: Avatar als Thumbnail, Podest-Zeichen fuer die ersten drei, Rest-XP und
naechste Belohnung als eigene Felder. Das Feld erscheint nur, wenn es
Belohnungs-Rollen gibt — sonst stuende dort ein leeres Feld.
Nebenbei zwei veraltete ephemeral: true auf flags: MessageFlags.Ephemeral
umgestellt, wie es der Rest der Befehle schon macht.
Geprueft: alle vier Embeds wirklich gebaut und ausgegeben, discord.js
validiert dabei. Das Intervall im Footer zog den auf 7 gestellten Wert.
Die negative XP-Differenz im ersten Testlauf war ein inkonsistenter
Testdatensatz — mit 4200 XP ist man Level 9, nicht 7; ueber 0..60000 XP
durchgespielt wird die Differenz nie negativ.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+40
-15
@@ -1,8 +1,12 @@
|
||||
// /rank — eigenes Level, XP-Fortschritt und Platzierung anzeigen
|
||||
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder, MessageFlags } from 'discord.js';
|
||||
import { getLevelRow, rankOf } from '../../db.js';
|
||||
import { xpForLevel } from '../levels.js';
|
||||
import { levelsEnabled, publicUrl, brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
import { brandEmbed } from '../../embeds.js';
|
||||
import { levelsEnabled, publicUrl, levelRewards } from '../../runtime-settings.js';
|
||||
|
||||
// Platz 1–3 bekommen ein Zeichen, danach schlicht die Nummer
|
||||
const PODEST = ['🥇', '🥈', '🥉'];
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('rank')
|
||||
@@ -11,13 +15,19 @@ export const data = new SlashCommandBuilder()
|
||||
|
||||
export async function execute(interaction) {
|
||||
if (!levelsEnabled()) {
|
||||
await interaction.reply({ content: '❌ Das Level-System ist nicht aktiviert.', ephemeral: true });
|
||||
await interaction.reply({
|
||||
content: '❌ Das Level-System ist nicht aktiviert.',
|
||||
flags: MessageFlags.Ephemeral,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const user = interaction.options.getUser('member') ?? interaction.user;
|
||||
const row = getLevelRow(user.id);
|
||||
if (!row) {
|
||||
await interaction.reply({ content: `**${user.username}** hat noch keine XP — einfach mitschreiben! ✍️`, ephemeral: true });
|
||||
await interaction.reply({
|
||||
content: `**${user.username}** hat noch keine XP — einfach mitschreiben! ✍️`,
|
||||
flags: MessageFlags.Ephemeral,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,15 +39,30 @@ export async function execute(interaction) {
|
||||
const barLen = 14;
|
||||
const bar = '█'.repeat(Math.round((pct / 100) * barLen)).padEnd(barLen, '·');
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(brandColor())
|
||||
.setAuthor({ name: user.username, iconURL: user.displayAvatarURL({ size: 64 }) })
|
||||
.setTitle(`Level ${row.level} · Platz #${rankOf(user.id)}`)
|
||||
.setDescription(`\`${bar}\` ${pct}%\n**${progress} / ${needed} XP** bis Level ${row.level + 1} · gesamt ${row.xp} XP`)
|
||||
.setURL(`${publicUrl()}/level`)
|
||||
.setFooter({ text: brandFooter('LEVEL') }),
|
||||
],
|
||||
});
|
||||
const platz = rankOf(user.id);
|
||||
const zahl = (n) => n.toLocaleString('de-DE');
|
||||
const naechste = levelRewards().find((r) => r.level > row.level) ?? null;
|
||||
|
||||
const embed = brandEmbed(interaction.client, 'LEVEL')
|
||||
.setAuthor({ name: user.username, iconURL: user.displayAvatarURL({ size: 64 }) })
|
||||
.setTitle(`${PODEST[platz - 1] ?? ''} Level ${row.level} · Platz #${platz}`.trim())
|
||||
.setURL(`${publicUrl()}/level`)
|
||||
.setThumbnail(user.displayAvatarURL({ size: 128 }))
|
||||
.setDescription(`\`${bar}\` **${pct}%**`)
|
||||
.addFields(
|
||||
{ name: `Bis Level ${row.level + 1}`, value: `${zahl(needed - progress)} XP`, inline: true },
|
||||
{ name: 'Gesamt', value: `${zahl(row.xp)} XP`, inline: true },
|
||||
);
|
||||
|
||||
// Nur zeigen, was es auch gibt — ohne Belohnungs-Rollen bliebe hier ein
|
||||
// leeres Feld stehen und das Embed sähe kaputt aus.
|
||||
if (naechste) {
|
||||
embed.addFields({
|
||||
name: 'Nächste Belohnung',
|
||||
value: `<@&${naechste.roleId}> ab Level ${naechste.level}`,
|
||||
inline: true,
|
||||
});
|
||||
}
|
||||
|
||||
await interaction.reply({ embeds: [embed], allowedMentions: { parse: [] } });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user