Skip to content

feat(scoring): pool-based map point distribution for cosmetic currency #180

@TheMeinerLP

Description

@TheMeinerLP

Description

The game designer has specified a new scoring model to replace (or augment) the time-bracket system introduced in Epic #168. Rather than awarding fixed bracket points per tier, a per-map point pool is distributed among all players who completed the map in that session, proportional to each player's finish time relative to a reference time.

This model decouples competitive performance feedback (medal tiers) from cosmetic currency reward, and makes the currency feel dynamic — the pool is finite and shared.

Mechanic Specification

Reference Time

  • Primary source: all-time fastest completion of the map, stored in map_records table (requires V4 migration).
  • Fallback (no record exists): fastest finisher of the current session becomes the reference for that session's pool distribution only. The record is then written to map_records so future sessions have a persistent reference.

Point Pool

  • Each map carries a fixed point pool (exact size and configurability TBD — see open questions).
  • At map-end, the pool is split among all players who completed the map in that session.
  • Distribution is proportional to performance vs the reference time: finishing at or faster than the reference time yields a larger share; finishing slower yields a smaller share.
  • The total distributed across all players must not exceed the pool (no inflation).

Currency

  • Points awarded by this system are a cosmetic currency used to purchase cosmetic items.
  • The currency name is TBD (see open questions).
  • This is distinct from any competitive leaderboard metric.

No-Completion Case

Open Questions (must be resolved before implementation)

  • Pool size: Fixed value (e.g. 1000 per map)? Configurable per map in MapDefinition? Or formula-based (e.g. base * number_of_rings)?
  • Split formula: Weighted proportional (each player's weight = referenceTime / playerTime)? Threshold-based buckets? Something else?
  • Slow-finisher floor: Do players finishing slower than the reference time always receive a reduced but non-zero share, or can the share reach 0 for extreme outliers?
  • Currency name: What is the cosmetic currency called in-game?
  • Medal tier coexistence: Does this pool system replace the DIAMOND/GOLD/SILVER/BRONZE bracket tiers (Epic feat(race): implement time-bracket scoring for Race Mode #168) entirely, or do medal tiers continue as a separate performance feedback layer while the pool drives currency rewards?
  • Record write-back: Is the session-fastest written to map_records only when it beats the existing record, or always (first-time insert)?
  • Multi-map cups: Is the pool distributed per map or aggregated across the full cup?

Acceptance Criteria

  • MapDefinition has a configurable point pool value (exact type and default TBD per open questions above)
  • map_records table stores the all-time fastest completion per map; referenced at distribution time
  • PoolScoringStrategy (or equivalent) implements ScoringStrategy from the ADR-0007 sealed hierarchy introduced in PR feat(scoring): Zeit-Bracket scoring strategy for Race Mode (#168) #178
  • Pool distribution formula is unit-tested for: all players equal time, one player significantly faster, one player at exactly reference time, fallback (no pre-existing record)
  • Session-fastest is written to map_records when no prior record exists (and optionally when beaten)
  • Cosmetic currency amount is recorded on GameResultEntity and persisted
  • All open questions above are answered and reflected in updated MapDefinition + ADR
  • Existing bracket medal tiers (DIAMOND/GOLD/SILVER/BRONZE) either remain for feedback-only purposes or are explicitly removed — decision documented in ADR
  • ArchUnit tests still pass (no cross-module boundary violations)
  • Flyway migration adds map_records table (V4) and any new currency column(s) on game_results

Technical Details

  • The ScoringStrategy sealed interface (introduced in PR feat(scoring): Zeit-Bracket scoring strategy for Race Mode (#168) #178) is the correct extension point. Add a PoolScoringStrategy permit.
  • Distribution math runs in applyMapResults() after all finish times for a session are known.
  • The reference-time lookup must be async-safe (DB read at map-start or cached at session-start).
  • Component: ScoreComponent may need a cosmeticCurrencyEarned field (Java record, compact constructor validation).
  • Follow the ManisGame enum DSL pattern if a distribution-tier enum is introduced.

Dependencies

Estimate

L

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgameplayGameplay mechanics

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions