'use strict'; /* * PetSprite — единый источник модели питомца для /pet и /dashboard. * Канонические PET_PALETTES + shadeColor + renderPetSVG. pet.html и * dashboard.html используют window.PetSprite.render(...) — без дублей. */ (function () { const PET_PALETTES = { purple:'#9B5DE5', cyan:'#06D6E0', gold:'#F9C74F', red:'#F94144', green:'#38D95A', blue:'#4A90D9', pink:'#F15BB5', orange:'#FB8B24', teal:'#0CA5B8', lime:'#7FB800', indigo:'#5E60CE', }; function shadeColor(hex, pct) { const n = parseInt(hex.slice(1), 16); const r = Math.min(255,Math.max(0,(n>>16)+pct)); const g = Math.min(255,Math.max(0,((n>>8)&0xff)+pct)); const b = Math.min(255,Math.max(0,(n&0xff)+pct)); return `rgb(${r},${g},${b})`; } function renderPetSVG(level, mood, accessories = [], colorKey = 'purple', streak = 0, pattern = 'none') { const col = PET_PALETTES[colorKey] || '#9B5DE5'; const dark = shadeColor(col, -45); const light = shadeColor(col, 52); const uid = `pg${level}${mood[0]}${colorKey[0]}`; const bodyPath = 'M55,22 C70,22 86,37 87,56 C89,75 78,94 55,97 C32,94 21,75 23,56 C24,37 40,22 55,22 Z'; const eyeY = 52, eyeX1 = 40, eyeX2 = 70; /* ── Eyebrows ── */ let eyebrows = ''; if (mood !== 'sleeping') { if (mood === 'ecstatic') { eyebrows = ` `; } else if (mood === 'sad' || mood === 'hungry') { eyebrows = ` `; } else { eyebrows = ` `; } } /* ── Eyes ── */ let eyeGroups = '', cheeks = '', extras = ''; if (mood === 'sleeping') { eyeGroups = ` `; } else { const ry1 = mood === 'ecstatic' ? 13 : mood === 'happy' ? 12 : 10.5; const prx = mood === 'ecstatic' ? 7 : mood === 'happy' ? 6.5 : 5.5; const pry = mood === 'ecstatic' ? 8 : mood === 'happy' ? 7.5 : 6.5; const pOff = (mood === 'sad' || mood === 'hungry') ? 3 : 2; eyeGroups = ` `; } /* ── Nose ── */ const nose = mood !== 'sleeping' ? `` : ''; /* ── Mouth + cheeks ── */ let mouth = ''; if (mood === 'sleeping') { mouth = ``; } else if (mood === 'ecstatic') { mouth = ``; cheeks = ` `; } else if (mood === 'happy') { mouth = ``; cheeks = ` `; } else if (mood === 'sad' || mood === 'hungry') { mouth = ``; if (mood === 'hungry') extras = ``; } else { mouth = ``; } /* ── Animated tail (all levels) ── */ const tail = ` `; /* ── Ears (level 2+) ── */ let ears = ''; if (level >= 2) { ears = ` `; } /* ── Antennae (level 3+) ── */ let antennae = ''; if (level >= 3) { antennae = ` `; } /* ── Wings with flutter (level 4+) ── */ let wings = ''; if (level >= 4) { wings = ` `; } /* ── Paws with fingers ── */ const paws = ` `; /* ── Accessories (гардероб: строго по equipped-списку, без авто по уровню) ── */ let accSvg = ''; if (accessories.includes('party')) { accSvg += ` `; } if (accessories.includes('sunglasses')) { accSvg += ` `; } if (accessories.includes('scarf')) { accSvg += ` `; } if (accessories.includes('flower')) { accSvg += ``; } if (accessories.includes('beanie')) { accSvg += ` `; } if (accessories.includes('halo')) { accSvg += ` `; } if (accessories.includes('monocle')) { accSvg += ` `; } if (accessories.includes('medal')) { accSvg += ` `; } if (accessories.includes('earrings')) { accSvg += ` `; } if (accessories.includes('wand')) { accSvg += ` `; } if (accessories.includes('balloon')) { accSvg += ` `; } if (accessories.includes('headphones')) { accSvg += ` `; } if (accessories.includes('grad')) { accSvg += ` `; } if (accessories.includes('hat')) { accSvg += ` `; } if (accessories.includes('crown')) { accSvg += ` `; } if (accessories.includes('glasses')) { accSvg += ` `; } if (accessories.includes('bowtie')) { accSvg += ` `; } if (accessories.includes('star')) { accSvg += ``; } /* ── Aura ring (level 4+) ── */ let aura = ''; if (level >= 4) { aura = ` `; } /* ── B3 Rainbow collar (streak ≥ 7) ── */ let rainbowCollar = ''; if (streak >= 7) { rainbowCollar = ` `; } /* ── Orbital particles (level 5+) ── */ let orbitals = ''; if (level >= 5) { const oData = [ { start: 0, dur: 2.8, r: 46, size: 4, fill: col, op: .85 }, { start: 120, dur: 3.6, r: 43, size: 3, fill: light, op: .7 }, { start: 240, dur: 2.2, r: 48, size: 3.5, fill: 'white', op: .6 }, ]; // Extra orbitals for level 6+ if (level >= 6) { oData.push( { start: 60, dur: 1.9, r: 51, size: 2.5, fill: light, op: .65 }, { start: 180, dur: 4.1, r: 40, size: 2, fill: col, op: .55 }, { start: 300, dur: 3.0, r: 54, size: 3, fill: 'white', op: .5 }, ); } // Even more for level 8 if (level >= 8) { oData.push( { start: 45, dur: 1.5, r: 56, size: 3.5, fill: '#FFD700', op: .9 }, { start: 225, dur: 2.4, r: 38, size: 2.5, fill: '#FFD700', op: .75 }, ); } orbitals = oData.map(o => ` `).join('\n'); } /* ── Second aura ring (level 6+) ── */ if (level >= 6) { aura += ` `; } /* ── Crystal halo (level 7+) ── */ let halo = ''; if (level >= 7) { halo = ` `; } /* ── Second wing pair (level 7+) ── */ if (level >= 7) { wings += ` `; } /* ── Third aura + body shimmer (level 8) ── */ let shimmer = ''; if (level >= 8) { aura += ` `; shimmer = ``; } // Узор тела (клипуется по силуэту) let patternSvg = ''; if (pattern && pattern !== 'none') { let pin = ''; if (pattern === 'spots') pin = ``; else if (pattern === 'stripes') pin = `${[-10,8,26,44,62,80,98].map(x => ``).join('')}`; else if (pattern === 'galaxy') pin = ``; else if (pattern === 'gradient') pin = ``; else if (pattern === 'hearts') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => ``).join(''); else if (pattern === 'stars') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => ``).join(''); else if (pattern === 'checker') pin = Array.from({ length: 42 }, (_, i) => { const c = i % 6, r = (i / 6) | 0; return ((r + c) % 2) ? '' : ``; }).join(''); patternSvg = `${pin}`; } return ` ${aura} ${halo} ${tail} ${wings} ${ears} ${antennae} ${paws} ${patternSvg} ${shimmer} ${cheeks}${eyebrows}${eyeGroups}${nose}${mouth}${extras} ${rainbowCollar} ${accSvg} ${orbitals} `; } var MOOD_RU = { ecstatic: 'в восторге', happy: 'в духе', neutral: 'бодр', sad: 'скучает', hungry: 'голоден', sleeping: 'спит', }; window.PetSprite = { PALETTES: PET_PALETTES, shade: shadeColor, render: renderPetSVG, moodLabel: function (m) { return MOOD_RU[m] || 'бодр'; }, }; })();