pull-config.ts
Pull system configuration. Banner definitions, pull costs, pity thresholds, and ship rarity rates for the gacha metagame. Ships-only pulls.
Contract
- All rates in a rarity table sum to
1.0. - Pity counter is per-banner, persisted in the
player_pitytable.
Pull costs
| Constant | Value | Meaning |
|---|---|---|
SINGLE_PULL_GEM_COST | 100 | Warp Crystals per single pull (V32) |
TEN_PULL_GEM_COST | 1000 | Warp Crystals per 10-pull (V32) |
SINGLE_PULL_TICKET_COST | 1 | Tickets per single pull |
TEN_PULL_TICKET_COST | 10 | Tickets per 10-pull |
No discount on 10-pull cost — pure 10× the single price. The 10-pull’s value comes from TEN_PULL_GUARANTEE_RARITY, not price.
Daily ad tickets
| Constant | Value | Meaning |
|---|---|---|
DAILY_AD_TICKET_LIMIT | 5 | Max free tickets per day from ads |
Pity system
| Constant | Value | Meaning |
|---|---|---|
HARD_PITY_THRESHOLD | 50 | Pulls until guaranteed high-rarity |
SOFT_PITY_START | 40 | High-rarity chance ramps linearly from here |
TEN_PULL_GUARANTEE_RARITY | 'uncommon' | Floor rarity for any 10-pull |
Soft pity window: pulls 40–49 see linearly increasing high-rarity chance. Hard pity at pull 50 forces a guaranteed high-rarity drop. Counter resets on trigger and is stored per-banner.
Banners
BannerDef interface: id, name, emoji.
BANNERS record contains two entries:
| Key | Name | Emoji |
|---|---|---|
sun | Sun | ☀️ |
moon | Moon | 🌙 |
Ship rarity rates
SHIP_RARITY_RATES: Record<ShipRarity, number> — must sum to 1.0.
| Rarity | Weight |
|---|---|
common | 0.55 |
uncommon | 0.27 |
rare | 0.12 |
epic | 0.06 |
legendary | 0.00 |
Legendary is zero-weighted — currently unreachable through normal pulls. Sum: 0.55 + 0.27 + 0.12 + 0.06 + 0.00 = 1.00.
Pull result type
PullPullResult interface — what each pull resolves to:
| Field | Type | Meaning |
|---|---|---|
type | 'ship' | Always 'ship'; pulls only produce ships |
entityId | string | Ship template ID (e.g. 'dart_common') |
rarity | string | Rarity of the pulled ship |
isFeatured | boolean | UI highlight flag for featured entities |
wasPity | boolean | True if pity triggered this pull |
Exports
SINGLE_PULL_GEM_COST,TEN_PULL_GEM_COSTSINGLE_PULL_TICKET_COST,TEN_PULL_TICKET_COSTDAILY_AD_TICKET_LIMITHARD_PITY_THRESHOLD,SOFT_PITY_START,TEN_PULL_GUARANTEE_RARITYBannerDef(interface),BANNERSSHIP_RARITY_RATESPullPullResult(interface)
Dependencies
./ships— importsShipRaritytype for keying rate table and the pity guarantee.
EXTRACT-CANDIDATE
- The naming
PullPullResultis a typo/stutter (likely intendedPullResult). Rename candidate. legendary: 0.00is dead weight in the rate table — legendary ships can never drop here. Either remove the key or move legendary acquisition to a separate path (event banner, crafting, mission reward) and document it.- Pity thresholds (
HARD_PITY_THRESHOLD,SOFT_PITY_START) are global, not per-banner — banner-specific tuning would require splitting these into aRecord<BannerId, PityConfig>. - Banner
emojifield hardcodes display detail in a data table — UI concern leaking into config. Move to a banner-presentation layer if banner art/icons expand. SHIP_RARITY_RATESis single global table; no per-banner rate variation possible. If Sun/Moon need different drop weights (rate-up, featured ship boost), extract toRecord<BannerId, RarityRates>.- “Ships only” assumption is encoded in
PullPullResult.type = 'ship'. If pulls ever produce mods/artifacts/cosmetics, the type union and result shape need expansion.