feat: computed achievement system — 20 achievements derived from bot stats
Achievements computed on-the-fly from existing stats + fight history: win milestones, streaks, tiers, ELO, perfect/KO wins, resilience, activity. Wired into /api/bots/:name/stats endpoint. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0ae3970433
commit
3b8208be08
@@ -4,6 +4,7 @@ import { createHash, randomBytes } from 'crypto'
|
||||
import { db, schema } from '../db/index.js'
|
||||
import { eq, or, desc, sql } from 'drizzle-orm'
|
||||
import { TIER_NAMES, TIER_COLORS } from '../engine/scoring.js'
|
||||
import { computeAchievements } from '../engine/achievements.js'
|
||||
import { isAllowedWebhookUrl } from '../engine/orchestrator.js'
|
||||
import { testWebhook } from '../engine/webhook-test.js'
|
||||
import { rateLimit } from '../middleware/rate-limit.js'
|
||||
@@ -180,15 +181,27 @@ botsRouter.get('/:name/stats', async (c) => {
|
||||
allBots.sort((a, b) => b.eloRating - a.eloRating)
|
||||
const rank = allBots.findIndex(b => b.id === bot.id) + 1
|
||||
|
||||
// Recent fights (last 10)
|
||||
const fights = await db.select()
|
||||
.from(schema.fights)
|
||||
// All fights for achievements
|
||||
const allFights = await db.select({
|
||||
winnerId: schema.fights.winnerId,
|
||||
totalRounds: schema.fights.totalRounds,
|
||||
botAHp: schema.fights.botAHp,
|
||||
botBHp: schema.fights.botBHp,
|
||||
botAId: schema.fights.botAId,
|
||||
botBId: schema.fights.botBId,
|
||||
createdAt: schema.fights.createdAt,
|
||||
endedAt: schema.fights.endedAt,
|
||||
id: schema.fights.id,
|
||||
arena: schema.fights.arena,
|
||||
}).from(schema.fights)
|
||||
.where(or(
|
||||
eq(schema.fights.botAId, bot.id),
|
||||
eq(schema.fights.botBId, bot.id),
|
||||
))
|
||||
.orderBy(desc(schema.fights.createdAt))
|
||||
.limit(10)
|
||||
|
||||
// Recent fights (last 10)
|
||||
const fights = allFights.slice(0, 10)
|
||||
|
||||
// Resolve opponent names
|
||||
const opponentIds = new Set<string>()
|
||||
@@ -217,6 +230,15 @@ botsRouter.get('/:name/stats', async (c) => {
|
||||
}
|
||||
})
|
||||
|
||||
const achievements = computeAchievements(bot.id, {
|
||||
wins: bot.wins,
|
||||
losses: bot.losses,
|
||||
winStreak: bot.winStreak,
|
||||
bestStreak: bot.bestStreak,
|
||||
tier: bot.tier,
|
||||
eloRating: bot.eloRating,
|
||||
}, allFights)
|
||||
|
||||
return c.json({
|
||||
...bot,
|
||||
tierName: TIER_NAMES[bot.tier] || 'BABY',
|
||||
@@ -226,6 +248,7 @@ botsRouter.get('/:name/stats', async (c) => {
|
||||
rank,
|
||||
totalBots: allBots.length,
|
||||
recentFights,
|
||||
achievements,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user