Delete src/lib/game/data/familiars.ts
Build and Publish Mana Loop Docker Image / build-and-publish (push) Has been cancelled
Build and Publish Mana Loop Docker Image / build-and-publish (push) Has been cancelled
This commit is contained in:
@@ -1,519 +0,0 @@
|
||||
// ─── Familiar Definitions ───────────────────────────────────────────────────────
|
||||
// Magical companions that provide passive bonuses and active assistance
|
||||
|
||||
import type { FamiliarDef, FamiliarAbility } from '../types';
|
||||
|
||||
// ─── Familiar Abilities ─────────────────────────────────────────────────────────
|
||||
|
||||
const ABILITIES = {
|
||||
// Combat abilities
|
||||
damageBonus: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'damageBonus',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% damage (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
critChance: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'critChance',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% crit chance (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
critDamage: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'critDamage',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% crit damage (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
castSpeed: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'castSpeed',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% cast speed (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
elementalBonus: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'elementalBonus',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% elemental damage (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
guardianDamage: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'guardianDamage',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% damage to guardians (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
manaSiphon: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'manaSiphon',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `Restore ${base}% of damage as mana (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
barrierBreaker: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'barrierBreaker',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% damage to barriers (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
// Mana abilities
|
||||
manaRegen: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'manaRegen',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base} mana regen (+${scaling} per level)`,
|
||||
}),
|
||||
|
||||
autoGather: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'autoGather',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `Auto-gather ${base} mana/hour (+${scaling} per level)`,
|
||||
}),
|
||||
|
||||
autoConvert: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'autoConvert',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `Auto-convert ${base} mana/hour (+${scaling} per level)`,
|
||||
}),
|
||||
|
||||
maxManaBonus: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'maxManaBonus',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base} max mana (+${scaling} per level)`,
|
||||
}),
|
||||
|
||||
// Support abilities
|
||||
bonusGold: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'bonusGold',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% insight gain (+${scaling}% per level)`,
|
||||
}),
|
||||
|
||||
studySpeed: (base: number, scaling: number): FamiliarAbility => ({
|
||||
type: 'studySpeed',
|
||||
baseValue: base,
|
||||
scalingPerLevel: scaling,
|
||||
desc: `+${base}% study speed (+${scaling}% per level)`,
|
||||
}),
|
||||
};
|
||||
|
||||
// ─── Familiar Definitions ───────────────────────────────────────────────────────
|
||||
|
||||
export const FAMILIARS_DEF: Record<string, FamiliarDef> = {
|
||||
// === COMMON FAMILIARS (Tier 1) ===
|
||||
|
||||
// Mana Wisps - Basic mana helpers
|
||||
manaWisp: {
|
||||
id: 'manaWisp',
|
||||
name: 'Mana Wisp',
|
||||
desc: 'A gentle spirit of pure mana that drifts lazily through the air.',
|
||||
role: 'mana',
|
||||
element: 'raw',
|
||||
rarity: 'common',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(0.5, 0.1),
|
||||
],
|
||||
baseStats: { power: 10, bond: 15 },
|
||||
unlockCondition: { type: 'mana', value: 100 },
|
||||
flavorText: 'It hums with quiet contentment, barely visible in dim light.',
|
||||
},
|
||||
|
||||
fireSpark: {
|
||||
id: 'fireSpark',
|
||||
name: 'Fire Spark',
|
||||
desc: 'A tiny ember given life, crackling with barely contained energy.',
|
||||
role: 'combat',
|
||||
element: 'fire',
|
||||
rarity: 'common',
|
||||
abilities: [
|
||||
ABILITIES.damageBonus(2, 0.5),
|
||||
],
|
||||
baseStats: { power: 12, bond: 10 },
|
||||
unlockCondition: { type: 'floor', value: 5 },
|
||||
flavorText: 'It bounces excitedly, leaving scorch marks on everything it touches.',
|
||||
},
|
||||
|
||||
waterDroplet: {
|
||||
id: 'waterDroplet',
|
||||
name: 'Water Droplet',
|
||||
desc: 'A perfect sphere of living water that never seems to evaporate.',
|
||||
role: 'support',
|
||||
element: 'water',
|
||||
rarity: 'common',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(0.3, 0.1),
|
||||
ABILITIES.manaSiphon(2, 0.5),
|
||||
],
|
||||
baseStats: { power: 8, bond: 12 },
|
||||
unlockCondition: { type: 'floor', value: 3 },
|
||||
flavorText: 'Ripples spread across its surface with each spell you cast.',
|
||||
},
|
||||
|
||||
earthPebble: {
|
||||
id: 'earthPebble',
|
||||
name: 'Earth Pebble',
|
||||
desc: 'A small stone with a surprisingly friendly personality.',
|
||||
role: 'guardian',
|
||||
element: 'earth',
|
||||
rarity: 'common',
|
||||
abilities: [
|
||||
ABILITIES.guardianDamage(3, 0.8),
|
||||
],
|
||||
baseStats: { power: 15, bond: 8 },
|
||||
unlockCondition: { type: 'floor', value: 8 },
|
||||
flavorText: 'It occasionally rolls itself to a new position when bored.',
|
||||
},
|
||||
|
||||
// === UNCOMMON FAMILIARS (Tier 2) ===
|
||||
|
||||
flameImp: {
|
||||
id: 'flameImp',
|
||||
name: 'Flame Imp',
|
||||
desc: 'A mischievous fire spirit that delights in destruction.',
|
||||
role: 'combat',
|
||||
element: 'fire',
|
||||
rarity: 'uncommon',
|
||||
abilities: [
|
||||
ABILITIES.damageBonus(4, 0.8),
|
||||
ABILITIES.elementalBonus(3, 0.6),
|
||||
],
|
||||
baseStats: { power: 25, bond: 12 },
|
||||
unlockCondition: { type: 'floor', value: 15 },
|
||||
flavorText: 'It cackles with glee whenever you defeat an enemy.',
|
||||
},
|
||||
|
||||
windSylph: {
|
||||
id: 'windSylph',
|
||||
name: 'Wind Sylph',
|
||||
desc: 'An airy spirit that moves like a gentle breeze.',
|
||||
role: 'support',
|
||||
element: 'air',
|
||||
rarity: 'uncommon',
|
||||
abilities: [
|
||||
ABILITIES.castSpeed(3, 0.6),
|
||||
],
|
||||
baseStats: { power: 20, bond: 15 },
|
||||
unlockCondition: { type: 'floor', value: 12 },
|
||||
flavorText: 'Its laughter sounds like wind chimes in a storm.',
|
||||
},
|
||||
|
||||
manaSprite: {
|
||||
id: 'manaSprite',
|
||||
name: 'Mana Sprite',
|
||||
desc: 'A more evolved mana spirit with a playful nature.',
|
||||
role: 'mana',
|
||||
element: 'raw',
|
||||
rarity: 'uncommon',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(1, 0.2),
|
||||
ABILITIES.autoGather(2, 0.5),
|
||||
],
|
||||
baseStats: { power: 18, bond: 18 },
|
||||
unlockCondition: { type: 'mana', value: 1000 },
|
||||
flavorText: 'It sometimes tickles your ear with invisible hands.',
|
||||
},
|
||||
|
||||
crystalGolem: {
|
||||
id: 'crystalGolem',
|
||||
name: 'Crystal Golem',
|
||||
desc: 'A small construct made of crystallized mana.',
|
||||
role: 'guardian',
|
||||
element: 'crystal',
|
||||
rarity: 'uncommon',
|
||||
abilities: [
|
||||
ABILITIES.guardianDamage(5, 1),
|
||||
ABILITIES.barrierBreaker(8, 1.5),
|
||||
],
|
||||
baseStats: { power: 30, bond: 10 },
|
||||
unlockCondition: { type: 'floor', value: 20 },
|
||||
flavorText: 'Light refracts through its body in mesmerizing patterns.',
|
||||
},
|
||||
|
||||
// === RARE FAMILIARS (Tier 3) ===
|
||||
|
||||
phoenixHatchling: {
|
||||
id: 'phoenixHatchling',
|
||||
name: 'Phoenix Hatchling',
|
||||
desc: 'A young phoenix, still learning to control its flames.',
|
||||
role: 'combat',
|
||||
element: 'fire',
|
||||
rarity: 'rare',
|
||||
abilities: [
|
||||
ABILITIES.damageBonus(6, 1.2),
|
||||
ABILITIES.critDamage(15, 3),
|
||||
],
|
||||
baseStats: { power: 40, bond: 15 },
|
||||
unlockCondition: { type: 'floor', value: 30 },
|
||||
flavorText: 'Tiny flames dance around its feathers as it practices flying.',
|
||||
},
|
||||
|
||||
frostWisp: {
|
||||
id: 'frostWisp',
|
||||
name: 'Frost Wisp',
|
||||
desc: 'A spirit of eternal winter, beautiful and deadly.',
|
||||
role: 'combat',
|
||||
element: 'water',
|
||||
rarity: 'rare',
|
||||
abilities: [
|
||||
ABILITIES.elementalBonus(8, 1.5),
|
||||
ABILITIES.castSpeed(4, 0.8),
|
||||
],
|
||||
baseStats: { power: 35, bond: 12 },
|
||||
unlockCondition: { type: 'floor', value: 25 },
|
||||
flavorText: 'Frost patterns appear on surfaces wherever it lingers.',
|
||||
},
|
||||
|
||||
manaElemental: {
|
||||
id: 'manaElemental',
|
||||
name: 'Mana Elemental',
|
||||
desc: 'A concentrated form of pure magical energy.',
|
||||
role: 'mana',
|
||||
element: 'raw',
|
||||
rarity: 'rare',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(2, 0.4),
|
||||
ABILITIES.autoGather(5, 1),
|
||||
ABILITIES.autoConvert(2, 0.5),
|
||||
],
|
||||
baseStats: { power: 30, bond: 20 },
|
||||
unlockCondition: { type: 'mana', value: 5000 },
|
||||
flavorText: 'Reality seems to bend slightly around its fluctuating form.',
|
||||
},
|
||||
|
||||
shieldGuardian: {
|
||||
id: 'shieldGuardian',
|
||||
name: 'Stone Guardian',
|
||||
desc: 'A loyal protector carved from enchanted stone.',
|
||||
role: 'guardian',
|
||||
element: 'earth',
|
||||
rarity: 'rare',
|
||||
abilities: [
|
||||
ABILITIES.guardianDamage(8, 1.5),
|
||||
ABILITIES.barrierBreaker(12, 2),
|
||||
],
|
||||
baseStats: { power: 50, bond: 8 },
|
||||
unlockCondition: { type: 'floor', value: 35 },
|
||||
flavorText: 'It stands motionless for hours, then suddenly moves to strike.',
|
||||
},
|
||||
|
||||
// === EPIC FAMILIARS (Tier 4) ===
|
||||
|
||||
infernoDrake: {
|
||||
id: 'infernoDrake',
|
||||
name: 'Inferno Drake',
|
||||
desc: 'A small dragon wreathed in eternal flames.',
|
||||
role: 'combat',
|
||||
element: 'fire',
|
||||
rarity: 'epic',
|
||||
abilities: [
|
||||
ABILITIES.damageBonus(10, 2),
|
||||
ABILITIES.elementalBonus(12, 2),
|
||||
ABILITIES.critChance(3, 0.6),
|
||||
],
|
||||
baseStats: { power: 60, bond: 12 },
|
||||
unlockCondition: { type: 'floor', value: 50 },
|
||||
flavorText: 'Smoke occasionally drifts from its nostrils as it dreams of conquest.',
|
||||
},
|
||||
|
||||
starlightSerpent: {
|
||||
id: 'starlightSerpent',
|
||||
name: 'Starlight Serpent',
|
||||
desc: 'A serpentine creature formed from captured starlight.',
|
||||
role: 'support',
|
||||
element: 'stellar',
|
||||
rarity: 'epic',
|
||||
abilities: [
|
||||
ABILITIES.castSpeed(8, 1.5),
|
||||
ABILITIES.bonusGold(5, 1),
|
||||
ABILITIES.manaRegen(1.5, 0.3),
|
||||
],
|
||||
baseStats: { power: 45, bond: 25 },
|
||||
unlockCondition: { type: 'floor', value: 45 },
|
||||
flavorText: 'It traces constellations in the air with its glowing body.',
|
||||
},
|
||||
|
||||
voidWalker: {
|
||||
id: 'voidWalker',
|
||||
name: 'Void Walker',
|
||||
desc: 'A being that exists partially outside normal reality.',
|
||||
role: 'mana',
|
||||
element: 'void',
|
||||
rarity: 'epic',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(3, 0.6),
|
||||
ABILITIES.autoGather(10, 2),
|
||||
ABILITIES.maxManaBonus(50, 10),
|
||||
],
|
||||
baseStats: { power: 55, bond: 15 },
|
||||
unlockCondition: { type: 'floor', value: 55 },
|
||||
flavorText: 'It sometimes disappears entirely, only to reappear moments later.',
|
||||
},
|
||||
|
||||
ancientGolem: {
|
||||
id: 'ancientGolem',
|
||||
name: 'Ancient Golem',
|
||||
desc: 'A construct from a forgotten age, still following its prime directive.',
|
||||
role: 'guardian',
|
||||
element: 'earth',
|
||||
rarity: 'epic',
|
||||
abilities: [
|
||||
ABILITIES.guardianDamage(15, 3),
|
||||
ABILITIES.barrierBreaker(20, 4),
|
||||
ABILITIES.damageBonus(5, 1),
|
||||
],
|
||||
baseStats: { power: 80, bond: 6 },
|
||||
unlockCondition: { type: 'floor', value: 60 },
|
||||
flavorText: 'Ancient runes glow faintly across its weathered surface.',
|
||||
},
|
||||
|
||||
// === LEGENDARY FAMILIARS (Tier 5) ===
|
||||
|
||||
primordialPhoenix: {
|
||||
id: 'primordialPhoenix',
|
||||
name: 'Primordial Phoenix',
|
||||
desc: 'An ancient fire bird, reborn countless times through the ages.',
|
||||
role: 'combat',
|
||||
element: 'fire',
|
||||
rarity: 'legendary',
|
||||
abilities: [
|
||||
ABILITIES.damageBonus(15, 3),
|
||||
ABILITIES.elementalBonus(20, 4),
|
||||
ABILITIES.critDamage(30, 5),
|
||||
ABILITIES.critChance(5, 1),
|
||||
],
|
||||
baseStats: { power: 100, bond: 20 },
|
||||
unlockCondition: { type: 'pact', value: 25 }, // Guardian floor 25
|
||||
flavorText: 'Its eyes hold the wisdom of a thousand lifetimes.',
|
||||
},
|
||||
|
||||
leviathanSpawn: {
|
||||
id: 'leviathanSpawn',
|
||||
name: 'Leviathan Spawn',
|
||||
desc: 'The offspring of an ancient sea god, still growing into its power.',
|
||||
role: 'mana',
|
||||
element: 'water',
|
||||
rarity: 'legendary',
|
||||
abilities: [
|
||||
ABILITIES.manaRegen(5, 1),
|
||||
ABILITIES.autoGather(20, 4),
|
||||
ABILITIES.autoConvert(8, 1.5),
|
||||
ABILITIES.maxManaBonus(100, 20),
|
||||
],
|
||||
baseStats: { power: 90, bond: 18 },
|
||||
unlockCondition: { type: 'pact', value: 50 },
|
||||
flavorText: 'The air around it always smells of salt and deep ocean.',
|
||||
},
|
||||
|
||||
celestialGuardian: {
|
||||
id: 'celestialGuardian',
|
||||
name: 'Celestial Guardian',
|
||||
desc: 'A divine protector sent by powers beyond mortal comprehension.',
|
||||
role: 'guardian',
|
||||
element: 'light',
|
||||
rarity: 'legendary',
|
||||
abilities: [
|
||||
ABILITIES.guardianDamage(25, 5),
|
||||
ABILITIES.barrierBreaker(30, 6),
|
||||
ABILITIES.damageBonus(10, 2),
|
||||
ABILITIES.critChance(8, 1.5),
|
||||
],
|
||||
baseStats: { power: 120, bond: 12 },
|
||||
unlockCondition: { type: 'pact', value: 75 },
|
||||
flavorText: 'It radiates an aura of absolute judgment.',
|
||||
},
|
||||
|
||||
voidEmperor: {
|
||||
id: 'voidEmperor',
|
||||
name: 'Void Emperor',
|
||||
desc: 'A ruler from the spaces between dimensions, bound to your service.',
|
||||
role: 'support',
|
||||
element: 'void',
|
||||
rarity: 'legendary',
|
||||
abilities: [
|
||||
ABILITIES.castSpeed(15, 3),
|
||||
ABILITIES.bonusGold(15, 3),
|
||||
ABILITIES.manaRegen(4, 0.8),
|
||||
ABILITIES.critChance(8, 1.5),
|
||||
],
|
||||
baseStats: { power: 85, bond: 25 },
|
||||
unlockCondition: { type: 'floor', value: 90 },
|
||||
flavorText: 'It regards reality with the detached interest of a god.',
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Helper Functions ───────────────────────────────────────────────────────────
|
||||
|
||||
// Get XP required for next familiar level
|
||||
export function getFamiliarXpRequired(level: number): number {
|
||||
// Exponential scaling: 100 * 1.5^(level-1)
|
||||
return Math.floor(100 * Math.pow(1.5, level - 1));
|
||||
}
|
||||
|
||||
// Get bond required for next bond level (1-100)
|
||||
export function getBondRequired(currentBond: number): number {
|
||||
// Linear scaling, every 10 bond requires more time
|
||||
const bondTier = Math.floor(currentBond / 10);
|
||||
return 100 + bondTier * 50; // Base 100, +50 per tier
|
||||
}
|
||||
|
||||
// Calculate familiar's ability value at given level and ability level
|
||||
export function getFamiliarAbilityValue(
|
||||
ability: FamiliarAbility,
|
||||
familiarLevel: number,
|
||||
abilityLevel: number
|
||||
): number {
|
||||
// Base value + (familiar level bonus) + (ability level bonus)
|
||||
const familiarBonus = Math.floor(familiarLevel / 10) * ability.scalingPerLevel;
|
||||
const abilityBonus = (abilityLevel - 1) * ability.scalingPerLevel * 2;
|
||||
return ability.baseValue + familiarBonus + abilityBonus;
|
||||
}
|
||||
|
||||
// Get all familiars of a specific rarity
|
||||
export function getFamiliarsByRarity(rarity: FamiliarDef['rarity']): FamiliarDef[] {
|
||||
return Object.values(FAMILIARS_DEF).filter(f => f.rarity === rarity);
|
||||
}
|
||||
|
||||
// Get all familiars of a specific role
|
||||
export function getFamiliarsByRole(role: FamiliarRole): FamiliarDef[] {
|
||||
return Object.values(FAMILIARS_DEF).filter(f => f.role === role);
|
||||
}
|
||||
|
||||
// Check if player meets unlock condition for a familiar
|
||||
export function canUnlockFamiliar(
|
||||
familiar: FamiliarDef,
|
||||
maxFloor: number,
|
||||
signedPacts: number[],
|
||||
totalManaGathered: number,
|
||||
skillsLearned: number
|
||||
): boolean {
|
||||
if (!familiar.unlockCondition) return true;
|
||||
|
||||
const { type, value } = familiar.unlockCondition;
|
||||
|
||||
switch (type) {
|
||||
case 'floor':
|
||||
return maxFloor >= value;
|
||||
case 'pact':
|
||||
return signedPacts.includes(value);
|
||||
case 'mana':
|
||||
return totalManaGathered >= value;
|
||||
case 'study':
|
||||
return skillsLearned >= value;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Starting familiar (given to new players)
|
||||
export const STARTING_FAMILIAR = 'manaWisp';
|
||||
Reference in New Issue
Block a user