Add designed sticker packs (SVG art) to the reactions system
- 15 hand-designed inline-SVG stickers (faces, Hokm: حکم/کُت/crown/ace, Persian: chai/آفرین/rose, taunts: clown/zzz/ضعیف) in components/online/Sticker.tsx - Sticker packs: faces (free), hokm (earned @rating 1300), persian & taunt (buy) - In-game tray now tabbed Emoji | Stickers; stickers broadcast as "sticker:<id>" and render as large animated bubbles per seat - Shop sells sticker packs; profile.ownedStickerPacks; gamification helpers ownedStickers/ownedStickerPackIds; mock opponents send stickers too Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,13 @@
|
||||
// Simulates remote players, friends presence, room invites and matchmaking
|
||||
// with timers, and computes rewards via gamification.ts.
|
||||
|
||||
import { CARD_STYLES, REACTION_PACKS, applyMatchResult, dailyRewardFor } from "./gamification";
|
||||
import {
|
||||
CARD_STYLES,
|
||||
REACTION_PACKS,
|
||||
STICKER_PACKS,
|
||||
applyMatchResult,
|
||||
dailyRewardFor,
|
||||
} from "./gamification";
|
||||
import {
|
||||
CreateRoomOptions,
|
||||
MatchmakingOptions,
|
||||
@@ -113,6 +119,7 @@ function defaultProfile(session: AuthSession): UserProfile {
|
||||
ownedCardStyles: ["classic"],
|
||||
ownedTitles: ["novice"],
|
||||
ownedReactionPacks: [],
|
||||
ownedStickerPacks: [],
|
||||
title: "novice",
|
||||
cardStyle: "classic",
|
||||
achievements: {},
|
||||
@@ -130,6 +137,7 @@ function migrateProfile(p: UserProfile): UserProfile {
|
||||
ownedCardStyles: p.ownedCardStyles ?? ["classic"],
|
||||
ownedTitles: p.ownedTitles ?? ["novice"],
|
||||
ownedReactionPacks: p.ownedReactionPacks ?? [],
|
||||
ownedStickerPacks: p.ownedStickerPacks ?? [],
|
||||
title: p.title ?? "novice",
|
||||
cardStyle: p.cardStyle ?? "classic",
|
||||
};
|
||||
@@ -452,7 +460,10 @@ export class MockOnlineService implements OnlineService {
|
||||
onReaction(cb: (seat: number, reaction: string) => void): Unsubscribe {
|
||||
this.reactionCbs.add(cb);
|
||||
if (this.reactionTimer == null) {
|
||||
const pool = ["👍", "😂", "🔥", "😮", "👏", "😎", "🙄", "😭"];
|
||||
const pool = [
|
||||
"👍", "😂", "🔥", "😮", "👏", "🙄",
|
||||
"sticker:happy", "sticker:cool", "sticker:kot-stamp", "sticker:crown",
|
||||
];
|
||||
this.reactionTimer = setInterval(() => {
|
||||
if (this.reactionCbs.size === 0) return;
|
||||
const seat = randInt(1, 3);
|
||||
@@ -761,7 +772,15 @@ export class MockOnlineService implements OnlineService {
|
||||
price: r.price,
|
||||
preview: r.reactions[0],
|
||||
}));
|
||||
return [...avatarItems, ...cardItems, ...reactionItems];
|
||||
const stickerItems: ShopItem[] = STICKER_PACKS.filter((p) => p.price > 0).map((p) => ({
|
||||
id: p.id,
|
||||
kind: "stickerpack",
|
||||
nameFa: p.nameFa,
|
||||
nameEn: p.nameEn,
|
||||
price: p.price,
|
||||
preview: p.stickers[0], // sticker id; ShopScreen renders via <Sticker>
|
||||
}));
|
||||
return [...avatarItems, ...cardItems, ...reactionItems, ...stickerItems];
|
||||
}
|
||||
|
||||
async buyItem(id: string) {
|
||||
@@ -774,7 +793,9 @@ export class MockOnlineService implements OnlineService {
|
||||
? p.ownedAvatars.includes(id)
|
||||
: item.kind === "cardstyle"
|
||||
? p.ownedCardStyles.includes(id)
|
||||
: p.ownedReactionPacks.includes(id);
|
||||
: item.kind === "reactionpack"
|
||||
? p.ownedReactionPacks.includes(id)
|
||||
: p.ownedStickerPacks.includes(id);
|
||||
if (owned) return { ok: false, messageFa: "قبلاً خریداری شده", messageEn: "Already owned" };
|
||||
if (p.coins < item.price)
|
||||
return { ok: false, messageFa: "سکه کافی نیست", messageEn: "Not enough coins" };
|
||||
@@ -787,6 +808,8 @@ export class MockOnlineService implements OnlineService {
|
||||
item.kind === "cardstyle" ? [...p.ownedCardStyles, id] : p.ownedCardStyles,
|
||||
ownedReactionPacks:
|
||||
item.kind === "reactionpack" ? [...p.ownedReactionPacks, id] : p.ownedReactionPacks,
|
||||
ownedStickerPacks:
|
||||
item.kind === "stickerpack" ? [...p.ownedStickerPacks, id] : p.ownedStickerPacks,
|
||||
};
|
||||
this.saveProfile();
|
||||
return { ok: true, profile: this.profile, messageFa: "خرید انجام شد", messageEn: "Purchased" };
|
||||
|
||||
Reference in New Issue
Block a user