Shop: every item is coin-priced; level/rank/achievement only gate the purchase
No more earned-only (rank/wins) cosmetics — every avatar, card back/front, reaction & sticker pack now has a coin price. Rank/wins/achievement become purchase requirements (coin · coin+rank · coin+rank+achievement), enforced client (mock + ShopScreen lock label) and server (ProfileService.ItemGate, keyed by kind:id). Ownership = default + purchased only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1036,6 +1036,7 @@ export class MockOnlineService implements OnlineService {
|
||||
descEn: "A legendary profile avatar shown in games & the leaderboard",
|
||||
reqLevel: a.reqLevel,
|
||||
reqRating: a.reqRating,
|
||||
reqAchievement: a.reqAchievement,
|
||||
};
|
||||
});
|
||||
const backItems: ShopItem[] = CARD_BACKS.filter((c) => c.price > 0).map((c) => ({
|
||||
@@ -1049,6 +1050,7 @@ export class MockOnlineService implements OnlineService {
|
||||
descEn: "The pattern on the back of your cards",
|
||||
reqLevel: c.reqLevel,
|
||||
reqRating: c.reqRating,
|
||||
reqAchievement: c.reqAchievement,
|
||||
}));
|
||||
const frontItems: ShopItem[] = CARD_FRONTS.filter((c) => c.price > 0).map((c) => ({
|
||||
id: c.id,
|
||||
@@ -1059,6 +1061,9 @@ export class MockOnlineService implements OnlineService {
|
||||
preview: c.bg2,
|
||||
descFa: "ظاهر روی کارتهای شما",
|
||||
descEn: "The face style of your cards",
|
||||
reqLevel: c.reqLevel,
|
||||
reqRating: c.reqRating,
|
||||
reqAchievement: c.reqAchievement,
|
||||
}));
|
||||
const reactionItems: ShopItem[] = REACTION_PACKS.filter((r) => r.price > 0).map((r) => ({
|
||||
id: r.id,
|
||||
@@ -1070,6 +1075,9 @@ export class MockOnlineService implements OnlineService {
|
||||
contents: r.reactions,
|
||||
descFa: `${faNum(r.reactions.length)} ایموجی برای استفاده در بازی`,
|
||||
descEn: `${r.reactions.length} in-game emotes`,
|
||||
reqLevel: r.reqLevel,
|
||||
reqRating: r.reqRating,
|
||||
reqAchievement: r.reqAchievement,
|
||||
}));
|
||||
const stickerItems: ShopItem[] = STICKER_PACKS.filter((p) => p.price > 0).map((p) => ({
|
||||
id: p.id,
|
||||
@@ -1081,6 +1089,9 @@ export class MockOnlineService implements OnlineService {
|
||||
contents: p.stickers,
|
||||
descFa: `${faNum(p.stickers.length)} استیکر برای استفاده در بازی`,
|
||||
descEn: `${p.stickers.length} in-game stickers`,
|
||||
reqLevel: p.reqLevel,
|
||||
reqRating: p.reqRating,
|
||||
reqAchievement: p.reqAchievement,
|
||||
}));
|
||||
const titleItems: ShopItem[] = TITLES.filter((tt) => (tt.price ?? 0) > 0).map((tt) => ({
|
||||
id: tt.id,
|
||||
@@ -1114,8 +1125,12 @@ export class MockOnlineService implements OnlineService {
|
||||
const item = items.find((i) => i.id === id);
|
||||
if (!item) return { ok: false, messageFa: "آیتم یافت نشد", messageEn: "Item not found" };
|
||||
|
||||
// Purchase gate: locked until the level/rating requirement is met.
|
||||
if ((item.reqLevel && p.level < item.reqLevel) || (item.reqRating && p.rating < item.reqRating))
|
||||
// Purchase gate: locked until the level / rating / achievement requirement is met.
|
||||
if (
|
||||
(item.reqLevel && p.level < item.reqLevel) ||
|
||||
(item.reqRating && p.rating < item.reqRating) ||
|
||||
(item.reqAchievement && !(p.unlocked ?? []).includes(item.reqAchievement))
|
||||
)
|
||||
return { ok: false, messageFa: "هنوز باز نشده است", messageEn: "Locked — requirement not met" };
|
||||
|
||||
// XP packs are consumable — grant XP instead of adding to an owned list.
|
||||
|
||||
Reference in New Issue
Block a user