Recruiter badge: the card for bringing someone who actually hunts

Matches the existing set at 1080x1080, same violet and gold, same laurel
wreath and floating Polygon coins, with a blank ribbon for the hunter's name.
Inside the wreath, four anonymous figures wired together as a team tree, one
at the top lighting up the three below it.

Awarded on a bounty rather than a match, so it means a person they brought
turned up and found their first code, not merely that an existing hunter
kept hunting. It shows locked on the board until then, which is the point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-23 06:10:00 -05:00
parent 48611374d6
commit c316dab8e6
3 changed files with 4 additions and 1 deletions
+3
View File
@@ -19,6 +19,7 @@ const BADGES = [
{ id: 'lucky', name: 'Lucky Find', icon: '\u{1F48E}', why: 'one drip of 0.4 POL or more' },
{ id: 'streak', name: 'On a Streak', icon: '\u{1F525}', why: 'finds on three days in a row' },
{ id: 'top', name: 'Top Hunter', icon: '\u{1F3C6}', why: 'won a weekly prize as #1' },
{ id: 'recruiter', name: 'Recruiter', icon: '\u{1F91D}', why: 'brought a hunter who found their first code' },
];
const PRIZE_DEFAULTS = { weeklyPrizes: [3, 2, 1], weeklyMinFinds: 10 };
function prizeRules() { const s = rewards.settings(); return { pol: Array.isArray(s.weeklyPrizes) && s.weeklyPrizes.length ? s.weeklyPrizes.map(Number) : PRIZE_DEFAULTS.weeklyPrizes, minFinds: Number(s.weeklyMinFinds) > 0 ? Number(s.weeklyMinFinds) : PRIZE_DEFAULTS.weeklyMinFinds }; }
@@ -49,6 +50,8 @@ function badgesFor(memberId, list) {
const days = new Set(mine.map(p => p.day));
for (const d of days) { if (days.has(dayMinus(d, 1)) && days.has(dayMinus(d, 2))) { out.add('streak'); break; } }
if (store.read('payouts', []).some(p => p.memberId === Number(memberId) && p.prize && p.prize.rank === 1 && p.status !== 'failed')) out.add('top');
// earned by a bounty, not a match: someone they brought turned up and found their first code
if (store.read('payouts', []).some(p => p.memberId === Number(memberId) && p.ref && p.ref.kind === 'bounty' && p.status !== 'failed')) out.add('recruiter');
return BADGES.filter(b => out.has(b.id));
}