Solo-Leveling-Self-Improvem.../utils/storage.ts

309 lines
7.9 KiB
TypeScript

// Import the InventoryItem interface
import type { InventoryItem } from "@/data/enemies";
import { Quest } from "@/interface/quest.interface";
// Define the user data structure
export interface UserStats {
name: string; // Add this line
level: number;
exp: number;
expToNextLevel: number;
job: string | null;
title: string | null;
hp: number;
maxHp: number;
mp: number;
maxMp: number;
fatigue: number;
gold: number; // Add gold currency
stats: {
str: number;
agi: number;
per: number;
int: number;
vit: number;
};
statPoints: number;
equipment: Equipment[];
quests: Quest[];
completedQuests: string[];
inventory: InventoryItem[]; // Add inventory array
}
export interface Equipment {
id: string;
name: string;
rarity: "Common" | "Uncommon" | "Rare" | "Epic" | "Legendary";
stats: string[];
setBonus: string;
slot: string;
equipped: boolean;
}
// Add some sample quests to the initial user stats
export const initialUserStats: UserStats = {
name: "", // Add this line with empty string as default
level: 1,
exp: 0,
expToNextLevel: 100, // Level 1 needs 100 XP to reach level 2
job: null,
title: null,
hp: 100,
maxHp: 100,
mp: 10,
maxMp: 10,
fatigue: 0,
gold: 0, // Start with 0 gold
stats: {
str: 10,
agi: 10,
per: 10,
int: 10,
vit: 10,
},
statPoints: 0,
equipment: [],
quests: [], // Removed initial quests
completedQuests: [],
inventory: [
{
id: "item-health-potion",
name: "Health Potion",
type: "Consumable",
rarity: "Common",
description: "Restores 100 HP when consumed.",
quantity: 3,
},
{
id: "item-mana-potion",
name: "Mana Potion",
type: "Consumable",
rarity: "Common",
description: "Restores 50 MP when consumed.",
quantity: 2,
},
],
};
// Save user data to localStorage
export const saveUserStats = (stats: UserStats): void => {
if (typeof window !== "undefined") {
localStorage.setItem("soloLevelUpUserStats", JSON.stringify(stats));
}
};
// Load user data from localStorage
export const loadUserStats = (): UserStats => {
if (typeof window !== "undefined") {
const savedStats = localStorage.getItem("soloLevelUpUserStats");
if (savedStats) {
return JSON.parse(savedStats);
}
}
return initialUserStats;
};
// Calculate XP needed for next level
export const calculateExpToNextLevel = (level: number): number => {
return Math.floor(100 * Math.pow(1.1, level - 1));
};
// Update the levelUp function to automatically add 1 point to all stats
export const levelUp = (stats: UserStats): UserStats => {
const newLevel = stats.level + 1;
// Automatically increase all stats by 1 point
const newStats = {
str: stats.stats.str + 1,
agi: stats.stats.agi + 1,
per: stats.stats.per + 1,
int: stats.stats.int + 1,
vit: stats.stats.vit + 1,
};
// HP and MP increases based on level and vitality/intelligence
const newMaxHp = Math.floor(100 + newLevel * 10 + newStats.vit * 5);
const newMaxMp = Math.floor(10 + newLevel * 2 + newStats.int * 2);
return {
...stats,
level: newLevel,
exp: stats.exp - stats.expToNextLevel,
expToNextLevel: calculateExpToNextLevel(newLevel),
maxHp: newMaxHp,
hp: newMaxHp, // Fully heal on level up
maxMp: newMaxMp,
mp: newMaxMp, // Fully restore MP on level up
stats: newStats,
// No longer adding stat points since we automatically increase all stats
};
};
// Add experience points
export const addExperience = (stats: UserStats, exp: number): UserStats => {
let updatedStats = { ...stats, exp: stats.exp + exp };
// Check if leveled up
while (updatedStats.exp >= updatedStats.expToNextLevel) {
updatedStats = levelUp(updatedStats);
}
return updatedStats;
};
// Allocate stat point
export const allocateStat = (
stats: UserStats,
stat: keyof UserStats["stats"]
): UserStats => {
if (stats.statPoints <= 0) return stats;
const newStats = { ...stats };
newStats.stats[stat]++;
newStats.statPoints--;
// Update derived stats
if (stat === "vit") {
newStats.maxHp = Math.floor(
100 + newStats.level * 10 + newStats.stats.vit * 5
);
}
if (stat === "int") {
newStats.maxMp = Math.floor(
10 + newStats.level * 2 + newStats.stats.int * 2
);
}
return newStats;
};
// Remove stat point (for UI)
export const deallocateStat = (
stats: UserStats,
stat: keyof UserStats["stats"]
): UserStats => {
if (stats.stats[stat] <= 10) return stats; // Can't go below base value
const newStats = { ...stats };
newStats.stats[stat]--;
newStats.statPoints++;
// Update derived stats
if (stat === "vit") {
newStats.maxHp = Math.floor(
100 + newStats.level * 10 + newStats.stats.vit * 5
);
}
if (stat === "int") {
newStats.maxMp = Math.floor(
10 + newStats.level * 2 + newStats.stats.int * 2
);
}
return newStats;
};
// Add item to inventory
export const addItemToInventory = (
stats: UserStats,
item: InventoryItem
): UserStats => {
const newStats = { ...stats };
const existingItem = newStats.inventory.find((i) => i.id === item.id);
if (existingItem && existingItem.quantity) {
// If item exists and has quantity, increment quantity
existingItem.quantity += item.quantity || 1;
} else {
// Otherwise add as new item
newStats.inventory.push({
...item,
quantity: item.quantity || 1,
});
}
return newStats;
};
// Remove item from inventory
export const removeItemFromInventory = (
stats: UserStats,
itemId: string,
quantity = 1
): UserStats => {
const newStats = { ...stats };
const itemIndex = newStats.inventory.findIndex((i) => i.id === itemId);
if (itemIndex === -1) return stats;
const item = newStats.inventory[itemIndex];
if (item.quantity && item.quantity > quantity) {
// Reduce quantity if there are more than requested
item.quantity -= quantity;
} else {
// Remove item completely
newStats.inventory.splice(itemIndex, 1);
}
return newStats;
};
// Use consumable item
export const useConsumableItem = (
stats: UserStats,
itemId: string
): UserStats => {
const newStats = { ...stats };
const item = newStats.inventory.find((i) => i.id === itemId);
if (!item || item.type !== "Consumable") return stats;
// First try specific item IDs for built-in items
switch (item.id) {
case "item-health-potion":
newStats.hp = Math.min(newStats.maxHp, newStats.hp + 100);
break;
case "item-mana-potion":
newStats.mp = Math.min(newStats.maxMp, newStats.mp + 50);
break;
case "item-focus-potion":
// This would need a temporary buff system to be implemented
break;
default:
// For custom/generated items, check name patterns instead of relying on specific IDs
if (
item.name.toLowerCase().includes("health") ||
item.name.toLowerCase().includes("healing") ||
item.name.toLowerCase().includes("hp")
) {
// Default healing amount (can be customized based on rarity)
let healAmount = 50;
if (item.rarity === "Uncommon") healAmount = 100;
if (item.rarity === "Rare") healAmount = 200;
if (item.rarity === "Epic") healAmount = 350;
if (item.rarity === "Legendary") healAmount = 500;
newStats.hp = Math.min(newStats.maxHp, newStats.hp + healAmount);
} else if (
item.name.toLowerCase().includes("mana") ||
item.name.toLowerCase().includes("mp")
) {
// Default mana restoration amount
let manaAmount = 25;
if (item.rarity === "Uncommon") manaAmount = 50;
if (item.rarity === "Rare") manaAmount = 100;
if (item.rarity === "Epic") manaAmount = 175;
if (item.rarity === "Legendary") manaAmount = 250;
newStats.mp = Math.min(newStats.maxMp, newStats.mp + manaAmount);
} else {
// Unknown consumable effect
return stats;
}
}
// Remove one of the item
return removeItemFromInventory(newStats, itemId, 1);
};