updated milestones
This commit is contained in:
@@ -25,13 +25,21 @@ export interface MascotTier {
|
|||||||
rarity: number;
|
rarity: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GameState {
|
interface UserState {
|
||||||
totalClicks: number;
|
name: string;
|
||||||
users: Record<string, { name: string; clicks: number; lastSeen: number; bonusMultiplier: number; lastClickTime?: number }>;
|
clicks: number;
|
||||||
|
lastSeen: number;
|
||||||
|
bonusMultiplier: number;
|
||||||
|
lastClickTime?: number;
|
||||||
upgrades: Record<string, { owned: number; cost: number }>;
|
upgrades: Record<string, { owned: number; cost: number }>;
|
||||||
milestones: Record<string, boolean>;
|
|
||||||
clickMultiplier: number;
|
clickMultiplier: number;
|
||||||
autoClickRate: number;
|
autoClickRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GameState {
|
||||||
|
totalClicks: number;
|
||||||
|
users: Record<string, UserState>;
|
||||||
|
milestones: Record<string, boolean>;
|
||||||
currentBackground: string;
|
currentBackground: string;
|
||||||
currentClickImage: 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: 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: 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: 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: 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://media.discordapp.net/stickers/1294812453112123453.webp?quality=lossless' },
|
{ 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://media1.tenor.com/m/x8v1oNUOmg4AAAAd/spinning-rat-rat.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://cdn.discordapp.com/emojis/1297946545626288312.webp' },
|
{ 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://media.discordapp.net/stickers/1377379131649429554.gif?size=160&quality=lossless' },
|
{ 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://media1.tenor.com/m/pV74fmh_NLgAAAAd/louie-rat-spinning-rat.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://media.discordapp.net/stickers/1397981135266648064.webp?size=160&quality=lossless' }
|
{ 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 {
|
export default class GameServer implements Party.Server {
|
||||||
@@ -238,13 +246,7 @@ export default class GameServer implements Party.Server {
|
|||||||
gameState: GameState = {
|
gameState: GameState = {
|
||||||
totalClicks: 0,
|
totalClicks: 0,
|
||||||
users: {},
|
users: {},
|
||||||
upgrades: UPGRADES.reduce((acc, upgrade) => {
|
|
||||||
acc[upgrade.id] = { owned: 0, cost: upgrade.baseCost };
|
|
||||||
return acc;
|
|
||||||
}, {} as Record<string, { owned: number; cost: number }>),
|
|
||||||
milestones: {},
|
milestones: {},
|
||||||
clickMultiplier: 1,
|
|
||||||
autoClickRate: 0,
|
|
||||||
currentBackground: 'default',
|
currentBackground: 'default',
|
||||||
currentClickImage: 'https://media1.tenor.com/m/pV74fmh_NLgAAAAd/louie-rat-spinning-rat.gif'
|
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,
|
name: currentUserName,
|
||||||
clicks: 0,
|
clicks: 0,
|
||||||
lastSeen: Date.now(),
|
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<string, { owned: number; cost: number }>),
|
||||||
|
clickMultiplier: 1,
|
||||||
|
autoClickRate: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.gameState.users[currentUserId].lastSeen = Date.now();
|
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
|
// Apply global click multiplier and user-specific bonus multiplier
|
||||||
const userBonusMultiplier = userState.bonusMultiplier || 1;
|
const userBonusMultiplier = userState.bonusMultiplier || 1;
|
||||||
const clickValue = this.gameState.clickMultiplier * userBonusMultiplier;
|
const clickValue = userState.clickMultiplier * userBonusMultiplier;
|
||||||
|
|
||||||
this.gameState.totalClicks += clickValue;
|
this.gameState.totalClicks += clickValue;
|
||||||
userState.clicks += clickValue;
|
userState.clicks += clickValue;
|
||||||
@@ -441,9 +449,11 @@ export default class GameServer implements Party.Server {
|
|||||||
|
|
||||||
handlePurchaseUpgrade(data: PurchaseUpgradeMessage, authenticatedUserId: string) {
|
handlePurchaseUpgrade(data: PurchaseUpgradeMessage, authenticatedUserId: string) {
|
||||||
const upgradeConfig = UPGRADES.find(u => u.id === data.upgradeId);
|
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
|
// Prevent purchasing one-time upgrades if already owned
|
||||||
if (upgradeConfig.oneTime && currentUpgradeState.owned > 0) {
|
if (upgradeConfig.oneTime && currentUpgradeState.owned > 0) {
|
||||||
@@ -451,9 +461,9 @@ export default class GameServer implements Party.Server {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check affordability against totalClicks
|
// Check affordability against user's clicks
|
||||||
if (this.gameState.totalClicks >= currentUpgradeState.cost) {
|
if (userState.clicks >= currentUpgradeState.cost) {
|
||||||
this.gameState.totalClicks -= currentUpgradeState.cost; // Deduct from totalClicks
|
userState.clicks -= currentUpgradeState.cost; // Deduct from user's clicks
|
||||||
currentUpgradeState.owned += 1;
|
currentUpgradeState.owned += 1;
|
||||||
|
|
||||||
// For one-time upgrades, cost doesn't change after first purchase
|
// 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));
|
currentUpgradeState.cost = Math.floor(upgradeConfig.baseCost * Math.pow(upgradeConfig.multiplier, currentUpgradeState.owned));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateGameMultipliers();
|
this.updateGameMultipliers(authenticatedUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGameMultipliers() {
|
updateGameMultipliers(userId: string) {
|
||||||
this.gameState.clickMultiplier = 1;
|
const userState = this.gameState.users[userId];
|
||||||
this.gameState.autoClickRate = 0;
|
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);
|
const config = UPGRADES.find(u => u.id === upgradeId);
|
||||||
if (!config) return; // Should not happen if UPGRADES is consistent
|
if (!config) return;
|
||||||
|
|
||||||
if (config.clickBonus) {
|
if (config.clickBonus) {
|
||||||
this.gameState.clickMultiplier += config.clickBonus * upgradeState.owned;
|
userState.clickMultiplier += config.clickBonus * upgradeState.owned;
|
||||||
}
|
}
|
||||||
if (config.autoClickRate) {
|
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();
|
this.setupAutoClicker();
|
||||||
@@ -491,13 +502,21 @@ export default class GameServer implements Party.Server {
|
|||||||
clearInterval(this.autoClickInterval);
|
clearInterval(this.autoClickInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.gameState.autoClickRate > 0) {
|
|
||||||
this.autoClickInterval = setInterval(() => {
|
this.autoClickInterval = setInterval(() => {
|
||||||
this.gameState.totalClicks += this.gameState.autoClickRate;
|
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.checkMilestones();
|
||||||
this.broadcast();
|
this.broadcast();
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkMilestones() {
|
checkMilestones() {
|
||||||
|
|||||||
25
src/App.tsx
25
src/App.tsx
@@ -30,6 +30,8 @@ function App() {
|
|||||||
const [adminBroadcastMessage, setAdminBroadcastMessage] = useState<string | null>(null); // New state for admin messages
|
const [adminBroadcastMessage, setAdminBroadcastMessage] = useState<string | null>(null); // New state for admin messages
|
||||||
const [showSecretVideo, setShowSecretVideo] = useState(false); // New state for secret video
|
const [showSecretVideo, setShowSecretVideo] = useState(false); // New state for secret video
|
||||||
|
|
||||||
|
const userState = isSignedIn && userId ? gameState.users[userId] : null;
|
||||||
|
|
||||||
// Admin user ID from .env
|
// Admin user ID from .env
|
||||||
const CLERK_ADMIN_USERID = import.meta.env.VITE_CLERK_ADMIN_USERID;
|
const CLERK_ADMIN_USERID = import.meta.env.VITE_CLERK_ADMIN_USERID;
|
||||||
const isAdmin = clerkUserId === CLERK_ADMIN_USERID;
|
const isAdmin = clerkUserId === CLERK_ADMIN_USERID;
|
||||||
@@ -57,10 +59,10 @@ function App() {
|
|||||||
|
|
||||||
// Effect for secret video
|
// Effect for secret video
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (gameState?.upgrades['secretVideo']?.owned > 0) {
|
if (userState?.upgrades?.['secretVideo']?.owned > 0) {
|
||||||
setShowSecretVideo(true);
|
setShowSecretVideo(true);
|
||||||
}
|
}
|
||||||
}, [gameState?.upgrades['secretVideo']?.owned]);
|
}, [userState]);
|
||||||
|
|
||||||
// Effect for receiving admin broadcast messages
|
// Effect for receiving admin broadcast messages
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -84,11 +86,10 @@ function App() {
|
|||||||
|
|
||||||
// Effect for spawning mascots
|
// Effect for spawning mascots
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Use gameStateRef.current for initial check and to get latest state inside spawnMascot
|
if (!userState) return;
|
||||||
if (!gameStateRef.current) return;
|
|
||||||
|
|
||||||
const friendBoostUpgrade = UPGRADES.find(u => u.id === 'friendBoost') as Upgrade | undefined;
|
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) {
|
if (timeoutRef.current) {
|
||||||
clearTimeout(timeoutRef.current);
|
clearTimeout(timeoutRef.current);
|
||||||
@@ -163,7 +164,7 @@ function App() {
|
|||||||
clearTimeout(timeoutRef.current);
|
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
|
const handleMascotClick = (id: string, multiplierBonus: number) => { // Renamed handler
|
||||||
sendMascotClickBonus(multiplierBonus); // Renamed function call
|
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
|
// Render the AdminPage if the current location is /admin
|
||||||
if (location === '/admin') {
|
if (location === '/admin') {
|
||||||
@@ -229,7 +232,7 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* News Marquee */}
|
{/* 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 && (
|
||||||
<NewsMarquee titles={UPGRADES.find(u => u.id === 'news')!.newsTitles!} />
|
<NewsMarquee titles={UPGRADES.find(u => u.id === 'news')!.newsTitles!} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -238,7 +241,7 @@ function App() {
|
|||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<Counter
|
<Counter
|
||||||
totalClicks={gameState.totalClicks}
|
totalClicks={gameState.totalClicks}
|
||||||
autoClickRate={gameState.autoClickRate}
|
autoClickRate={userState?.autoClickRate || 0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -270,7 +273,7 @@ function App() {
|
|||||||
<div className="lg:col-span-1">
|
<div className="lg:col-span-1">
|
||||||
<UpgradeShop
|
<UpgradeShop
|
||||||
gameState={gameState}
|
gameState={gameState}
|
||||||
totalClicks={gameState.totalClicks}
|
userState={userState}
|
||||||
onPurchase={purchaseUpgrade}
|
onPurchase={purchaseUpgrade}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { UPGRADES } from '../config/upgrades';
|
import { UPGRADES } from '../config/upgrades';
|
||||||
import { GameState, MascotTier } from '../types'; // Import MascotTier
|
import { GameState, MascotTier, UserState } from '../types'; // Import MascotTier
|
||||||
|
|
||||||
interface UpgradeShopProps {
|
interface UpgradeShopProps {
|
||||||
gameState: GameState;
|
gameState: GameState;
|
||||||
totalClicks: number; // Changed from userClicks
|
userState: UserState | null;
|
||||||
onPurchase: (upgradeId: string) => void;
|
onPurchase: (upgradeId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +22,13 @@ const getMascotName = (imageSrc: string): string => {
|
|||||||
.join(' ');
|
.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 (
|
return (
|
||||||
<div className="bg-gradient-to-b from-purple-800 to-pink-600 p-6 rounded-xl border-4 border-cyan-400 shadow-2xl">
|
<div className="bg-gradient-to-b from-purple-800 to-pink-600 p-6 rounded-xl border-4 border-cyan-400 shadow-2xl">
|
||||||
<h2 className="text-3xl font-bold text-yellow-300 mb-6 text-center" style={{ fontFamily: 'Comic Sans MS, cursive' }}>
|
<h2 className="text-3xl font-bold text-yellow-300 mb-6 text-center" style={{ fontFamily: 'Comic Sans MS, cursive' }}>
|
||||||
@@ -31,9 +37,9 @@ export function UpgradeShop({ gameState, totalClicks, onPurchase }: UpgradeShopP
|
|||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{UPGRADES.map((upgrade) => {
|
{UPGRADES.map((upgrade) => {
|
||||||
const owned = gameState.upgrades[upgrade.id]?.owned || 0;
|
const owned = userUpgrades[upgrade.id]?.owned || 0;
|
||||||
const cost = gameState.upgrades[upgrade.id]?.cost || upgrade.baseCost;
|
const cost = userUpgrades[upgrade.id]?.cost || upgrade.baseCost;
|
||||||
const canAfford = totalClicks >= cost; // Changed from userClicks
|
const canAfford = userClicks >= cost;
|
||||||
|
|
||||||
// If it's a one-time upgrade and already owned, don't display it
|
// If it's a one-time upgrade and already owned, don't display it
|
||||||
if (upgrade.oneTime && owned > 0) {
|
if (upgrade.oneTime && owned > 0) {
|
||||||
@@ -93,7 +99,7 @@ export function UpgradeShop({ gameState, totalClicks, onPurchase }: UpgradeShopP
|
|||||||
|
|
||||||
<div className="mt-6 text-center">
|
<div className="mt-6 text-center">
|
||||||
<div className="text-2xl font-bold text-yellow-300">
|
<div className="text-2xl font-bold text-yellow-300">
|
||||||
Total Clicks: {totalClicks.toLocaleString()}
|
Your Clicks: {userClicks.toLocaleString()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Interdimensional Bozo',
|
name: 'Interdimensional Bozo',
|
||||||
description: 'You are breaking the barriers of reality!',
|
description: 'You are breaking the barriers of reality!',
|
||||||
background: 'interdimensional',
|
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!'
|
reward: '🌀 Interdimensional Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Multiversal Bozo',
|
name: 'Multiversal Bozo',
|
||||||
description: 'Your bozo energy resonates across multiverses!',
|
description: 'Your bozo energy resonates across multiverses!',
|
||||||
background: 'multiversal',
|
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!'
|
reward: '🌌 Multiversal Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -115,7 +115,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Billionaire Bozo',
|
name: 'Billionaire Bozo',
|
||||||
description: 'You have achieved a billion clicks!',
|
description: 'You have achieved a billion clicks!',
|
||||||
background: 'billionaire',
|
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!'
|
reward: '💰 Billionaire Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -124,7 +124,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Ten Billion Bozo',
|
name: 'Ten Billion Bozo',
|
||||||
description: 'The clicks are overflowing!',
|
description: 'The clicks are overflowing!',
|
||||||
background: 'ten-billion',
|
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!'
|
reward: '📈 Ten Billion Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -133,7 +133,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Hundred Billion Bozo',
|
name: 'Hundred Billion Bozo',
|
||||||
description: 'You are a legend in the world of bozos!',
|
description: 'You are a legend in the world of bozos!',
|
||||||
background: 'hundred-billion',
|
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!'
|
reward: '🏆 Hundred Billion Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -142,7 +142,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Half Trillion Bozo',
|
name: 'Half Trillion Bozo',
|
||||||
description: 'Almost there, you can taste the trillions!',
|
description: 'Almost there, you can taste the trillions!',
|
||||||
background: 'half-trillion',
|
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!'
|
reward: '🚀 Half Trillion Background Unlocked!'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,7 +151,7 @@ export const MILESTONES: Milestone[] = [
|
|||||||
name: 'Trillionaire Bozo',
|
name: 'Trillionaire Bozo',
|
||||||
description: 'You are the ultimate bozo, a true trillionaire!',
|
description: 'You are the ultimate bozo, a true trillionaire!',
|
||||||
background: '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!'
|
reward: '👑 Trillionaire Background Unlocked!'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
15
src/types.ts
15
src/types.ts
@@ -1,10 +1,17 @@
|
|||||||
export interface GameState {
|
export interface UserState {
|
||||||
totalClicks: number;
|
name: string;
|
||||||
users: Record<string, { name: string; clicks: number; lastSeen: number; bonusMultiplier: number }>; // Added bonusMultiplier
|
clicks: number;
|
||||||
|
lastSeen: number;
|
||||||
|
bonusMultiplier: number;
|
||||||
upgrades: Record<string, { owned: number; cost: number }>;
|
upgrades: Record<string, { owned: number; cost: number }>;
|
||||||
milestones: Record<string, boolean>;
|
|
||||||
clickMultiplier: number;
|
clickMultiplier: number;
|
||||||
autoClickRate: number;
|
autoClickRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameState {
|
||||||
|
totalClicks: number;
|
||||||
|
users: Record<string, UserState>;
|
||||||
|
milestones: Record<string, boolean>;
|
||||||
currentBackground: string;
|
currentBackground: string;
|
||||||
currentClickImage: string;
|
currentClickImage: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user