Store XP packs (expensive), winner 2x XP, premium perks
- XP packs in the store (coin-priced, intentionally expensive): xp1 200/5k, xp2 600/12k, xp3 1500/25k. Consumable (grant XP, can level up) — server ShopBuy handles kind "xp" via an authoritative XpPacks map + Gamification.GrantXp; mock mirrors. New shop section + shop.xp/xpHint i18n. - Every game grants XP and the WINNER earns 2x: matchXp is now base*(won?2:1)*leagueFactor (was a flat +80 win bonus). Mirrored server-side. - Premium (pro) perks: 1.5x XP multiplier (applied in applyMatchResult / ApplyMatch by plan), plus animated shimmering gold chat bubbles for your own messages (premium-chat CSS; ChatScreen gates on plan). Verified: tsc + next + dotnet build clean; sim passes; live server — buying xp2 took L1→L3 and deducted 12k coins under the new curve. Images rebuilt :1500/:1505. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -112,9 +112,30 @@ public class ProfileService
|
||||
|
||||
/* ----------------------------- shop ------------------------------- */
|
||||
|
||||
// Coin-priced XP packs (XP is intentionally expensive). Server-authoritative.
|
||||
public static readonly Dictionary<string, (int Price, int Xp)> XpPacks = new()
|
||||
{
|
||||
["xp1"] = (5000, 200),
|
||||
["xp2"] = (12000, 600),
|
||||
["xp3"] = (25000, 1500),
|
||||
};
|
||||
|
||||
public async Task<(bool ok, ProfileDto? profile, string error)> ShopBuy(string uid, string kind, string id, int price)
|
||||
{
|
||||
var p = await GetOrCreate(uid, null);
|
||||
|
||||
// XP packs are consumable (grant XP, may level up) — not added to an owned list.
|
||||
if (kind == "xp")
|
||||
{
|
||||
if (!XpPacks.TryGetValue(id, out var pk)) return (false, p, "bad_kind");
|
||||
if (p.Coins < pk.Price) return (false, p, "insufficient");
|
||||
p.Coins -= pk.Price;
|
||||
Gamification.GrantXp(p, pk.Xp);
|
||||
await Save(p);
|
||||
await Ledger(uid, "xp", -pk.Price, id);
|
||||
return (true, p, "");
|
||||
}
|
||||
|
||||
var list = kind switch
|
||||
{
|
||||
"avatar" => p.OwnedAvatars,
|
||||
|
||||
Reference in New Issue
Block a user