Split card design into front+back, add sound effects & background music
Card design: - Separate cardFront + cardBack (each own/equip independently) - Fronts: classic (free), ivory/rosegold (buy), parchment/mint (earned) - Backs: classic (free), sapphire/emerald (buy), ruby/royal (earned) - PlayingCard `front` prop; table applies front to all faces, back to opponents - Profile has front + back pickers; shop has both sections Audio: - Web Audio synth engine (no asset files): SFX for card/deal/trump/trick, win/lose, message, notify, award, levelup, purchase, kot + ambient music - Toggles in profile (Audio) + mute button in game HUD; prefs persisted - Wired across game-store, rewards, daily, shop, chat Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
import {
|
||||
AchievementDef,
|
||||
AchievementUnlock,
|
||||
CardStyleDef,
|
||||
CardBackDef,
|
||||
CardFrontDef,
|
||||
LeagueInfo,
|
||||
MatchSummary,
|
||||
PlayerStats,
|
||||
@@ -218,16 +219,51 @@ export function titleUnlocked(
|
||||
|
||||
/* ---------------------------- Card styles ---------------------------- */
|
||||
|
||||
export const CARD_STYLES: CardStyleDef[] = [
|
||||
{ id: "classic", nameFa: "کلاسیک", nameEn: "Classic", c1: "#14274f", c2: "#0a142e", accent: "#d4af37", price: 0 },
|
||||
// Card BACKS (pattern on the reverse of every card).
|
||||
export const CARD_BACKS: CardBackDef[] = [
|
||||
{ id: "classic", nameFa: "کلاسیک", nameEn: "Classic", c1: "#14274f", c2: "#0a142e", accent: "#d4af37", price: 0, default: true },
|
||||
{ id: "sapphire", nameFa: "یاقوت کبود", nameEn: "Sapphire", c1: "#0b3a82", c2: "#06173a", accent: "#6aa6ff", price: 800 },
|
||||
{ id: "ruby", nameFa: "یاقوت", nameEn: "Ruby", c1: "#7f1d2e", c2: "#2b0a12", accent: "#ff7a90", price: 800 },
|
||||
{ id: "emerald", nameFa: "زمرد", nameEn: "Emerald", c1: "#0d6b5e", c2: "#062420", accent: "#2dd4bf", price: 1000 },
|
||||
{ id: "royal", nameFa: "سلطنتی", nameEn: "Royal", c1: "#4a1d7f", c2: "#1a0a2e", accent: "#c77dff", price: 1500 },
|
||||
{ id: "ruby", nameFa: "یاقوت", nameEn: "Ruby", c1: "#7f1d2e", c2: "#2b0a12", accent: "#ff7a90", price: 0, unlockRating: 1300 }, // earned
|
||||
{ id: "royal", nameFa: "سلطنتی", nameEn: "Royal", c1: "#4a1d7f", c2: "#1a0a2e", accent: "#c77dff", price: 0, unlockWins: 50 }, // earned
|
||||
];
|
||||
|
||||
export function cardStyleById(id: string): CardStyleDef {
|
||||
return CARD_STYLES.find((c) => c.id === id) ?? CARD_STYLES[0];
|
||||
// Card FRONTS (the face background/border behind the suit + rank).
|
||||
export const CARD_FRONTS: CardFrontDef[] = [
|
||||
{ id: "classic", nameFa: "کلاسیک", nameEn: "Classic", bg1: "#fffdf7", bg2: "#f3ead2", border: "rgba(0,0,0,0.12)", price: 0, default: true },
|
||||
{ id: "ivory", nameFa: "عاج", nameEn: "Ivory", bg1: "#ffffff", bg2: "#eef2f8", border: "#c9ccd6", price: 600 },
|
||||
{ id: "rosegold", nameFa: "رزگلد", nameEn: "Rose Gold", bg1: "#fff1ee", bg2: "#f6d9cf", border: "#d98a72", price: 900 },
|
||||
{ id: "parchment", nameFa: "پوستنوشت", nameEn: "Parchment", bg1: "#fbf2d8", bg2: "#efd9a3", border: "#caa84a", price: 0, unlockRating: 1300 }, // earned
|
||||
{ id: "mint", nameFa: "نعنایی", nameEn: "Mint", bg1: "#f0fff8", bg2: "#d3f3e3", border: "#57c79a", price: 0, unlockWins: 50 }, // earned
|
||||
];
|
||||
|
||||
export function cardBackById(id: string): CardBackDef {
|
||||
return CARD_BACKS.find((c) => c.id === id) ?? CARD_BACKS[0];
|
||||
}
|
||||
export function cardFrontById(id: string): CardFrontDef {
|
||||
return CARD_FRONTS.find((c) => c.id === id) ?? CARD_FRONTS[0];
|
||||
}
|
||||
|
||||
function ownedCosmeticIds(
|
||||
defs: { id: string; price: number; default?: boolean; unlockRating?: number; unlockWins?: number }[],
|
||||
profile: UserProfile,
|
||||
purchased: string[]
|
||||
): string[] {
|
||||
const ids = new Set<string>();
|
||||
for (const d of defs) {
|
||||
const earned =
|
||||
(d.unlockRating != null && profile.rating >= d.unlockRating) ||
|
||||
(d.unlockWins != null && profile.stats.wins >= d.unlockWins);
|
||||
if (d.default || earned || purchased.includes(d.id)) ids.add(d.id);
|
||||
}
|
||||
return [...ids];
|
||||
}
|
||||
|
||||
export function ownedCardBackIds(profile: UserProfile): string[] {
|
||||
return ownedCosmeticIds(CARD_BACKS, profile, profile.ownedCardBacks ?? []);
|
||||
}
|
||||
export function ownedCardFrontIds(profile: UserProfile): string[] {
|
||||
return ownedCosmeticIds(CARD_FRONTS, profile, profile.ownedCardFronts ?? []);
|
||||
}
|
||||
|
||||
/* --------------------- Reactions (Sheklak / شکلک) -------------------- */
|
||||
|
||||
Reference in New Issue
Block a user