| 60 | |
| 61 | // One peak stat, one dump stat, rest scattered. Rarity bumps the floor. |
| 62 | function rollStats( |
| 63 | rng: () => number, |
| 64 | rarity: Rarity, |
| 65 | ): Record<StatName, number> { |
| 66 | const floor = RARITY_FLOOR[rarity] |
| 67 | const peak = pick(rng, STAT_NAMES) |
| 68 | let dump = pick(rng, STAT_NAMES) |
| 69 | while (dump === peak) dump = pick(rng, STAT_NAMES) |
| 70 | |
| 71 | const stats = {} as Record<StatName, number> |
| 72 | for (const name of STAT_NAMES) { |
| 73 | if (name === peak) { |
| 74 | stats[name] = Math.min(100, floor + 50 + Math.floor(rng() * 30)) |
| 75 | } else if (name === dump) { |
| 76 | stats[name] = Math.max(1, floor - 10 + Math.floor(rng() * 15)) |
| 77 | } else { |
| 78 | stats[name] = floor + Math.floor(rng() * 40) |
| 79 | } |
| 80 | } |
| 81 | return stats |
| 82 | } |
| 83 | |
| 84 | const SALT = 'friend-2026-401' |
| 85 | |