From 5898f0495098bb5bcb6873d80b3a751f4ea2d06e Mon Sep 17 00:00:00 2001 From: Arjun S <37960163+arjunindia@users.noreply.github.com> Date: Mon, 4 Aug 2025 08:14:53 +0000 Subject: [PATCH] updated milestones --- party/index.ts | 97 ++++++++++++++++++++-------------- src/App.tsx | 25 +++++---- src/components/UpgradeShop.tsx | 20 ++++--- src/config/milestones.ts | 14 ++--- src/types.ts | 15 ++++-- 5 files changed, 103 insertions(+), 68 deletions(-) diff --git a/party/index.ts b/party/index.ts index 6c9ab0d..833639d 100644 --- a/party/index.ts +++ b/party/index.ts @@ -25,13 +25,21 @@ export interface MascotTier { rarity: number; } -interface GameState { - totalClicks: number; - users: Record; +interface UserState { + name: string; + clicks: number; + lastSeen: number; + bonusMultiplier: number; + lastClickTime?: number; upgrades: Record; - milestones: Record; clickMultiplier: number; autoClickRate: number; +} + +interface GameState { + totalClicks: number; + users: Record; + milestones: Record; currentBackground: string; currentClickImage: string; } @@ -216,13 +224,13 @@ const MILESTONES = [ { threshold: 5000000, id: 'mega-bozo', background: 'mega-bozo', image: 'https://media1.tenor.com/m/x8v1oNUOmg4AAAAd/spinning-rat-rat.gif' }, { threshold: 8008008, id: 'galactic-bozo', background: 'galactic-bozo', image: 'https://cdn.discordapp.com/emojis/1297946545626288312.webp' }, { threshold: 10000000, id: 'cosmic-bozo', background: 'cosmic-bozo', image: 'https://media.discordapp.net/stickers/1377379131649429554.gif?size=160&quality=lossless' }, - { threshold: 100000000, id: 'interdimensional-bozo', background: 'interdimensional', image: 'https://media.discordapp.net/stickers/1397981135266648064.webp?size=160&quality=lossless' }, - { threshold: 500000000, id: 'multiversal-bozo', background: 'multiversal', image: 'https://media.discordapp.net/stickers/1294812453112123453.webp?quality=lossless' }, - { threshold: 1000000000, id: 'billionaire-bozo', background: 'billionaire', image: 'https://media1.tenor.com/m/x8v1oNUOmg4AAAAd/spinning-rat-rat.gif' }, - { threshold: 10000000000, id: 'ten-billion-bozo', background: 'ten-billion', image: 'https://cdn.discordapp.com/emojis/1297946545626288312.webp' }, - { threshold: 100000000000, id: 'hundred-billion-bozo', background: 'hundred-billion', image: 'https://media.discordapp.net/stickers/1377379131649429554.gif?size=160&quality=lossless' }, - { threshold: 500000000000, id: 'half-trillion-bozo', background: 'half-trillion', image: 'https://media1.tenor.com/m/pV74fmh_NLgAAAAd/louie-rat-spinning-rat.gif' }, - { threshold: 1000000000000, id: 'trillionaire-bozo', background: 'trillionaire', image: 'https://media.discordapp.net/stickers/1397981135266648064.webp?size=160&quality=lossless' } + { threshold: 100000000, id: 'interdimensional-bozo', background: 'interdimensional', image: 'https://tenor.com/view/horizontally-spinning-rat-gif-2222021229431992839.gif' }, + { threshold: 500000000, id: 'multiversal-bozo', background: 'multiversal', image: 'https://tenor.com/view/spinning-rat-gif-26132.gif' }, + { threshold: 1000000000, id: 'billionaire-bozo', background: 'billionaire', image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif' }, + { threshold: 10000000000, id: 'ten-billion-bozo', background: 'ten-billion', image: 'https://tenor.com/view/horizontally-spinning-rat-gif-2222021229431992839.gif' }, + { threshold: 100000000000, id: 'hundred-billion-bozo', background: 'hundred-billion', image: 'https://tenor.com/view/spinning-rat-gif-26132.gif' }, + { threshold: 500000000000, id: 'half-trillion-bozo', background: 'half-trillion', image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif' }, + { threshold: 1000000000000, id: 'trillionaire-bozo', background: 'trillionaire', image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif' } ]; export default class GameServer implements Party.Server { @@ -238,13 +246,7 @@ export default class GameServer implements Party.Server { gameState: GameState = { totalClicks: 0, users: {}, - upgrades: UPGRADES.reduce((acc, upgrade) => { - acc[upgrade.id] = { owned: 0, cost: upgrade.baseCost }; - return acc; - }, {} as Record), milestones: {}, - clickMultiplier: 1, - autoClickRate: 0, currentBackground: 'default', currentClickImage: 'https://media1.tenor.com/m/pV74fmh_NLgAAAAd/louie-rat-spinning-rat.gif' }; @@ -315,7 +317,13 @@ export default class GameServer implements Party.Server { name: currentUserName, clicks: 0, lastSeen: Date.now(), - bonusMultiplier: 1 // Initialize bonus multiplier + bonusMultiplier: 1, // Initialize bonus multiplier + upgrades: UPGRADES.reduce((acc, upgrade) => { + acc[upgrade.id] = { owned: 0, cost: upgrade.baseCost }; + return acc; + }, {} as Record), + clickMultiplier: 1, + autoClickRate: 0, }; } this.gameState.users[currentUserId].lastSeen = Date.now(); @@ -396,7 +404,7 @@ export default class GameServer implements Party.Server { // Apply global click multiplier and user-specific bonus multiplier const userBonusMultiplier = userState.bonusMultiplier || 1; - const clickValue = this.gameState.clickMultiplier * userBonusMultiplier; + const clickValue = userState.clickMultiplier * userBonusMultiplier; this.gameState.totalClicks += clickValue; userState.clicks += clickValue; @@ -441,9 +449,11 @@ export default class GameServer implements Party.Server { handlePurchaseUpgrade(data: PurchaseUpgradeMessage, authenticatedUserId: string) { const upgradeConfig = UPGRADES.find(u => u.id === data.upgradeId); - const currentUpgradeState = this.gameState.upgrades[data.upgradeId]; + const userState = this.gameState.users[authenticatedUserId]; - if (!upgradeConfig || !currentUpgradeState) return; + if (!upgradeConfig || !userState) return; + + const currentUpgradeState = userState.upgrades[data.upgradeId]; // Prevent purchasing one-time upgrades if already owned if (upgradeConfig.oneTime && currentUpgradeState.owned > 0) { @@ -451,9 +461,9 @@ export default class GameServer implements Party.Server { return; } - // Check affordability against totalClicks - if (this.gameState.totalClicks >= currentUpgradeState.cost) { - this.gameState.totalClicks -= currentUpgradeState.cost; // Deduct from totalClicks + // Check affordability against user's clicks + if (userState.clicks >= currentUpgradeState.cost) { + userState.clicks -= currentUpgradeState.cost; // Deduct from user's clicks currentUpgradeState.owned += 1; // For one-time upgrades, cost doesn't change after first purchase @@ -461,26 +471,27 @@ export default class GameServer implements Party.Server { currentUpgradeState.cost = Math.floor(upgradeConfig.baseCost * Math.pow(upgradeConfig.multiplier, currentUpgradeState.owned)); } - this.updateGameMultipliers(); + this.updateGameMultipliers(authenticatedUserId); } } - updateGameMultipliers() { - this.gameState.clickMultiplier = 1; - this.gameState.autoClickRate = 0; + updateGameMultipliers(userId: string) { + const userState = this.gameState.users[userId]; + if (!userState) return; - Object.entries(this.gameState.upgrades).forEach(([upgradeId, upgradeState]) => { + userState.clickMultiplier = 1; + userState.autoClickRate = 0; + + Object.entries(userState.upgrades).forEach(([upgradeId, upgradeState]) => { const config = UPGRADES.find(u => u.id === upgradeId); - if (!config) return; // Should not happen if UPGRADES is consistent + if (!config) return; if (config.clickBonus) { - this.gameState.clickMultiplier += config.clickBonus * upgradeState.owned; + userState.clickMultiplier += config.clickBonus * upgradeState.owned; } if (config.autoClickRate) { - this.gameState.autoClickRate += config.autoClickRate * upgradeState.owned; + userState.autoClickRate += config.autoClickRate * upgradeState.owned; } - // Note: clickMultiplierBonus from upgrades.ts is handled client-side for spawning frequency - // and applied per-click on the server via handleApplyMultiplierBonus }); this.setupAutoClicker(); @@ -491,13 +502,21 @@ export default class GameServer implements Party.Server { clearInterval(this.autoClickInterval); } - if (this.gameState.autoClickRate > 0) { - this.autoClickInterval = setInterval(() => { - this.gameState.totalClicks += this.gameState.autoClickRate; + this.autoClickInterval = setInterval(() => { + let totalAutoClicks = 0; + Object.values(this.gameState.users).forEach(user => { + if (user.autoClickRate > 0) { + user.clicks += user.autoClickRate; + totalAutoClicks += user.autoClickRate; + } + }); + + if (totalAutoClicks > 0) { + this.gameState.totalClicks += totalAutoClicks; this.checkMilestones(); this.broadcast(); - }, 1000); - } + } + }, 1000); } checkMilestones() { diff --git a/src/App.tsx b/src/App.tsx index 5ddaf82..4ed6c69 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,6 +30,8 @@ function App() { const [adminBroadcastMessage, setAdminBroadcastMessage] = useState(null); // New state for admin messages const [showSecretVideo, setShowSecretVideo] = useState(false); // New state for secret video + const userState = isSignedIn && userId ? gameState.users[userId] : null; + // Admin user ID from .env const CLERK_ADMIN_USERID = import.meta.env.VITE_CLERK_ADMIN_USERID; const isAdmin = clerkUserId === CLERK_ADMIN_USERID; @@ -57,10 +59,10 @@ function App() { // Effect for secret video useEffect(() => { - if (gameState?.upgrades['secretVideo']?.owned > 0) { + if (userState?.upgrades?.['secretVideo']?.owned > 0) { setShowSecretVideo(true); } - }, [gameState?.upgrades['secretVideo']?.owned]); + }, [userState]); // Effect for receiving admin broadcast messages useEffect(() => { @@ -84,11 +86,10 @@ function App() { // Effect for spawning mascots useEffect(() => { - // Use gameStateRef.current for initial check and to get latest state inside spawnMascot - if (!gameStateRef.current) return; + if (!userState) return; const friendBoostUpgrade = UPGRADES.find(u => u.id === 'friendBoost') as Upgrade | undefined; - const ownedFriendBoost = gameStateRef.current.upgrades['friendBoost']?.owned || 0; + const ownedFriendBoost = userState.upgrades['friendBoost']?.owned || 0; if (timeoutRef.current) { clearTimeout(timeoutRef.current); @@ -163,7 +164,7 @@ function App() { clearTimeout(timeoutRef.current); } }; - }, [gameState?.upgrades['friendBoost']?.owned]); // Only depend on friendBoost level + }, [userState]); // Only depend on userState const handleMascotClick = (id: string, multiplierBonus: number) => { // Renamed handler sendMascotClickBonus(multiplierBonus); // Renamed function call @@ -184,8 +185,10 @@ function App() { ); } - const userBonusMultiplier = isSignedIn && userId ? gameState.users[userId]?.bonusMultiplier || 1 : 1; - const effectiveClickMultiplier = gameState.clickMultiplier * userBonusMultiplier; + + + const userBonusMultiplier = userState?.bonusMultiplier || 1; + const effectiveClickMultiplier = (userState?.clickMultiplier || 1) * userBonusMultiplier; // Render the AdminPage if the current location is /admin if (location === '/admin') { @@ -229,7 +232,7 @@ function App() { )} {/* News Marquee */} - {gameState.upgrades['news']?.owned > 0 && UPGRADES.find(u => u.id === 'news')?.newsTitles && ( + {userState?.upgrades['news']?.owned > 0 && UPGRADES.find(u => u.id === 'news')?.newsTitles && ( u.id === 'news')!.newsTitles!} /> )} @@ -238,7 +241,7 @@ function App() {
@@ -270,7 +273,7 @@ function App() {
diff --git a/src/components/UpgradeShop.tsx b/src/components/UpgradeShop.tsx index 9f6a9b8..e684dc4 100644 --- a/src/components/UpgradeShop.tsx +++ b/src/components/UpgradeShop.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { UPGRADES } from '../config/upgrades'; -import { GameState, MascotTier } from '../types'; // Import MascotTier +import { GameState, MascotTier, UserState } from '../types'; // Import MascotTier interface UpgradeShopProps { gameState: GameState; - totalClicks: number; // Changed from userClicks + userState: UserState | null; onPurchase: (upgradeId: string) => void; } @@ -22,7 +22,13 @@ const getMascotName = (imageSrc: string): string => { .join(' '); }; -export function UpgradeShop({ gameState, totalClicks, onPurchase }: UpgradeShopProps) { // Changed from userClicks +export function UpgradeShop({ gameState, userState, onPurchase }: UpgradeShopProps) { // Changed from userClicks + if (!userState) { + return null; // Or a loading/signed-out state + } + + const { clicks: userClicks, upgrades: userUpgrades } = userState; + return (

@@ -31,9 +37,9 @@ export function UpgradeShop({ gameState, totalClicks, onPurchase }: UpgradeShopP
{UPGRADES.map((upgrade) => { - const owned = gameState.upgrades[upgrade.id]?.owned || 0; - const cost = gameState.upgrades[upgrade.id]?.cost || upgrade.baseCost; - const canAfford = totalClicks >= cost; // Changed from userClicks + const owned = userUpgrades[upgrade.id]?.owned || 0; + const cost = userUpgrades[upgrade.id]?.cost || upgrade.baseCost; + const canAfford = userClicks >= cost; // If it's a one-time upgrade and already owned, don't display it if (upgrade.oneTime && owned > 0) { @@ -93,7 +99,7 @@ export function UpgradeShop({ gameState, totalClicks, onPurchase }: UpgradeShopP
- Total Clicks: {totalClicks.toLocaleString()} + Your Clicks: {userClicks.toLocaleString()}
diff --git a/src/config/milestones.ts b/src/config/milestones.ts index 7ee232a..a5a75a3 100644 --- a/src/config/milestones.ts +++ b/src/config/milestones.ts @@ -97,7 +97,7 @@ export const MILESTONES: Milestone[] = [ name: 'Interdimensional Bozo', description: 'You are breaking the barriers of reality!', background: 'interdimensional', - image: 'https://media.discordapp.net/stickers/1397981135266648064.webp?size=160&quality=lossless', + image: 'https://tenor.com/view/horizontally-spinning-rat-gif-2222021229431992839.gif', reward: '🌀 Interdimensional Background Unlocked!' }, { @@ -106,7 +106,7 @@ export const MILESTONES: Milestone[] = [ name: 'Multiversal Bozo', description: 'Your bozo energy resonates across multiverses!', background: 'multiversal', - image: 'https://media.discordapp.net/stickers/1294812453112123453.webp?quality=lossless', + image: 'https://tenor.com/view/spinning-rat-gif-26132.gif', reward: '🌌 Multiversal Background Unlocked!' }, { @@ -115,7 +115,7 @@ export const MILESTONES: Milestone[] = [ name: 'Billionaire Bozo', description: 'You have achieved a billion clicks!', background: 'billionaire', - image: 'https://media1.tenor.com/m/x8v1oNUOmg4AAAAd/spinning-rat-rat.gif', + image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif', reward: '💰 Billionaire Background Unlocked!' }, { @@ -124,7 +124,7 @@ export const MILESTONES: Milestone[] = [ name: 'Ten Billion Bozo', description: 'The clicks are overflowing!', background: 'ten-billion', - image: 'https://cdn.discordapp.com/emojis/1297946545626288312.webp', + image: 'https://tenor.com/view/horizontally-spinning-rat-gif-2222021229431992839.gif', reward: '📈 Ten Billion Background Unlocked!' }, { @@ -133,7 +133,7 @@ export const MILESTONES: Milestone[] = [ name: 'Hundred Billion Bozo', description: 'You are a legend in the world of bozos!', background: 'hundred-billion', - image: 'https://media.discordapp.net/stickers/1377379131649429554.gif?size=160&quality=lossless', + image: 'https://tenor.com/view/spinning-rat-gif-26132.gif', reward: '🏆 Hundred Billion Background Unlocked!' }, { @@ -142,7 +142,7 @@ export const MILESTONES: Milestone[] = [ name: 'Half Trillion Bozo', description: 'Almost there, you can taste the trillions!', background: 'half-trillion', - image: 'https://media1.tenor.com/m/pV74fmh_NLgAAAAd/louie-rat-spinning-rat.gif', + image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif', reward: '🚀 Half Trillion Background Unlocked!' }, { @@ -151,7 +151,7 @@ export const MILESTONES: Milestone[] = [ name: 'Trillionaire Bozo', description: 'You are the ultimate bozo, a true trillionaire!', background: 'trillionaire', - image: 'https://media.discordapp.net/stickers/1397981135266648064.webp?size=160&quality=lossless', + image: 'https://tenor.com/view/dancing-rat-rat-dance-gif-25151223.gif', reward: '👑 Trillionaire Background Unlocked!' } ]; diff --git a/src/types.ts b/src/types.ts index 1cd0b3f..9c479c2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,10 +1,17 @@ -export interface GameState { - totalClicks: number; - users: Record; // Added bonusMultiplier +export interface UserState { + name: string; + clicks: number; + lastSeen: number; + bonusMultiplier: number; upgrades: Record; - milestones: Record; clickMultiplier: number; autoClickRate: number; +} + +export interface GameState { + totalClicks: number; + users: Record; + milestones: Record; currentBackground: string; currentClickImage: string; }