1
0
Fork 0

Compare commits

...

3 commits

Author SHA1 Message Date
559ee64258 v0.2.34 - pause poker XP payouts, add v0.2.33 changelog notes 2026-09-11 12:57:42 -04:00
7433287be0 docs(changelog): add v0.2.33 release notes
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 12:57:34 -04:00
117de8ecee feat(poker): pause placement XP behind POKER_XP_ENABLED switch
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 12:57:34 -04:00
3 changed files with 38 additions and 8 deletions

View file

@ -1,5 +1,23 @@
# Changelog # Changelog
# v0.2.33
Three releases in one: a full poker minigame, a ribbon design studio for the awards program, and a reworked announce command for staff.
### Features
- **Poker**: sit down at sit-and-go tables and play full hold'em hands: betting rounds, side pots, hand hints, and showdowns. Results land in your profile stats, and tables update in real time as hands play out.
- **Ribbon design studio**: submit your own ribbon designs for awards. Submissions go to a review queue where staff approve or reject them, and you get a notification when a decision comes down.
- **Announcements**: staff writing `/announce` now compose it in a paste-friendly modal and pick the target channel right there. Announcements also post only to the announce channel by default: an unconfigured announce channel errors clearly instead of silently dropping the post into the ops channel.
- **Aim trainer crosshair**: the qualification course lets you draw your own crosshair. Pick the style (including a dot) and color from a settings popover.
### Fixes
- Wiki moderation actions (restore, lock, delete) now require intel write permissions, not just read.
- Rank groups on the roster sort in the intended order.
- Filtering the mission list by campaign no longer breaks when the campaign link is in an unexpected state.
- Campaign cards wrap evenly and banking activity tabs hold their layout.
# v0.2.30 # v0.2.30
A big run for the training grounds: OPORD Recall joins the lineup, you can build your own minefields and radio tests, and the dashboard bends to your will. A big run for the training grounds: OPORD Recall joins the lineup, you can build your own minefields and radio tests, and the dashboard bends to your will.

View file

@ -1,6 +1,6 @@
{ {
"name": "polaris-task-force", "name": "polaris-task-force",
"version": "0.2.33", "version": "0.2.34",
"description": "Web app for the Arma 3 unit Polaris Task Force. Uses Next.js for client- and server-side rendering, with a Postgres database and some other neat libraries.", "description": "Web app for the Arma 3 unit Polaris Task Force. Uses Next.js for client- and server-side rendering, with a Postgres database and some other neat libraries.",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",

View file

@ -31,6 +31,13 @@ export interface PokerStats {
xpEarned: number; xpEarned: number;
} }
/**
* XP rework in progress: when false, finished games still record placements,
* hands won, and best chips, but xpEarned is untouched and no XP push fires.
* Flip to true to resume placement-based XP payouts.
*/
export const POKER_XP_ENABLED = false;
/** /**
* XP per placement, scaled by table size: * XP per placement, scaled by table size:
* 1st = 40x, 2nd = 20x, 3rd = 10x, 4th = 5x (times playerCount). * 1st = 40x, 2nd = 20x, 3rd = 10x, 4th = 5x (times playerCount).
@ -105,7 +112,7 @@ export async function awardPokerGameResult(
const xpByUser: Record<number, number> = {}; const xpByUser: Record<number, number> = {};
for (const result of results) { for (const result of results) {
const xp = xpForPlacement(result.placement, playerCount); const xp = POKER_XP_ENABLED ? xpForPlacement(result.placement, playerCount) : 0;
xpByUser[result.userId] = xp; xpByUser[result.userId] = xp;
try { try {
@ -123,7 +130,10 @@ export async function awardPokerGameResult(
} }
const current = readPokerStats(profile); const current = readPokerStats(profile);
const next = computePokerStatsDelta(current, result, playerCount); const delta = computePokerStatsDelta(current, result, playerCount);
const next: PokerStats = POKER_XP_ENABLED
? delta
: { ...delta, xpEarned: current.xpEarned };
const progression = (profile.progression ?? {}) as Record<string, unknown>; const progression = (profile.progression ?? {}) as Record<string, unknown>;
const minigames = (progression.minigames ?? {}) as Record<string, unknown>; const minigames = (progression.minigames ?? {}) as Record<string, unknown>;
@ -143,11 +153,13 @@ export async function awardPokerGameResult(
depth: 0, depth: 0,
}); });
broadcastToUser("profile-update", result.userId, { if (xp > 0) {
reason: "xp", broadcastToUser("profile-update", result.userId, {
xpGained: xp, reason: "xp",
profileId: profile.id, xpGained: xp,
}); profileId: profile.id,
});
}
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : String(error); const message = error instanceof Error ? error.message : String(error);
payload.logger.error( payload.logger.error(