feat(pet): большое наполнение кастомизации контентом
Цвета 6→11 (розовый/оранжевый/бирюза/лайм/индиго). Узоры 5→8 (сердечки/звёздочки/клетка). Аксессуары 11→18 + новая зона «В лапах» (бини, нимб, монокль, медаль, серёжки, палочка, шарик). Разблокировка за учёбу: нимб (8 достижений), медаль (30 тестов). Фоны 7→11 (класс/лаборатория/зима/радуга) с градиентами и частицами. Новая вкладка «Образы» — 4 готовых набора (Учёный/Волшебник/Чемпион/Милашка) применяют аксессуары+узор+цвет одним кликом. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
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) {
|
||||
@@ -163,6 +165,38 @@
|
||||
if (accessories.includes('flower')) {
|
||||
accSvg += `<g transform="translate(82,30)"><circle cx="0" cy="-5" r="3.2" fill="#FF8FB1"/><circle cx="5" cy="-1" r="3.2" fill="#FF8FB1"/><circle cx="3" cy="5" r="3.2" fill="#FF8FB1"/><circle cx="-3" cy="5" r="3.2" fill="#FF8FB1"/><circle cx="-5" cy="-1" r="3.2" fill="#FF8FB1"/><circle cx="0" cy="0" r="2.6" fill="#F9C74F"/></g>`;
|
||||
}
|
||||
if (accessories.includes('beanie')) {
|
||||
accSvg += `<path d="M30,30 Q30,11 55,11 Q80,11 80,30 Z" fill="${col}"/>
|
||||
<rect x="28" y="27" width="54" height="6" rx="3" fill="${light}" opacity=".6"/>
|
||||
<circle cx="55" cy="10" r="4" fill="${light}"/>`;
|
||||
}
|
||||
if (accessories.includes('halo')) {
|
||||
accSvg += `<ellipse cx="55" cy="9" rx="17" ry="5" fill="none" stroke="#FCD667" stroke-width="3"/>
|
||||
<ellipse cx="55" cy="9" rx="17" ry="5" fill="none" stroke="#fff" stroke-width="1" opacity=".5"/>`;
|
||||
}
|
||||
if (accessories.includes('monocle')) {
|
||||
accSvg += `<circle cx="70" cy="52" r="13" fill="rgba(255,255,255,.1)" stroke="#FCD667" stroke-width="2"/>
|
||||
<path d="M70,65 Q66,75 59,79" stroke="#FCD667" stroke-width="1.4" fill="none"/>`;
|
||||
}
|
||||
if (accessories.includes('medal')) {
|
||||
accSvg += `<path d="M50,76 L48,86 L55,82 L62,86 L60,76 Z" fill="#e0335e"/>
|
||||
<circle cx="55" cy="89" r="6" fill="#FCD667" stroke="#d4920a" stroke-width="1.2"/>
|
||||
<path d="M52.4,89 l2,2 3.6,-4.2" stroke="#7a5a00" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`;
|
||||
}
|
||||
if (accessories.includes('earrings')) {
|
||||
accSvg += `<line x1="30" y1="44" x2="30" y2="46.5" stroke="#FCD667" stroke-width="1.2"/><circle cx="30" cy="48.5" r="2.5" fill="#FCD667"/>
|
||||
<line x1="80" y1="44" x2="80" y2="46.5" stroke="#FCD667" stroke-width="1.2"/><circle cx="80" cy="48.5" r="2.5" fill="#FCD667"/>`;
|
||||
}
|
||||
if (accessories.includes('wand')) {
|
||||
accSvg += `<line x1="92" y1="92" x2="104" y2="66" stroke="#9b6a2f" stroke-width="2.4" stroke-linecap="round"/>
|
||||
<path d="M104,60 l1.5,3.4 3.7,.3 -2.8,2.5 .9,3.6 -3.3,-2 -3.3,2 .9,-3.6 -2.8,-2.5 3.7,-.3 Z" fill="#FCD667"/>`;
|
||||
}
|
||||
if (accessories.includes('balloon')) {
|
||||
accSvg += `<line x1="14" y1="78" x2="12" y2="40" stroke="rgba(150,150,160,.55)" stroke-width="1"/>
|
||||
<ellipse cx="12" cy="32" rx="9" ry="11" fill="#F15BB5"/>
|
||||
<ellipse cx="9" cy="28" rx="2.4" ry="3" fill="#fff" opacity=".45"/>
|
||||
<path d="M12,43 l-2.4,3.4 4.8,0 Z" fill="#F15BB5"/>`;
|
||||
}
|
||||
if (accessories.includes('headphones')) {
|
||||
accSvg += `<path d="M27,42 Q55,6 83,42" fill="none" stroke="#2a3340" stroke-width="4" stroke-linecap="round"/>
|
||||
<rect x="21" y="38" width="11" height="17" rx="4.5" fill="#2a3340"/>
|
||||
@@ -317,6 +351,9 @@
|
||||
else if (pattern === 'stripes') pin = `<g transform="rotate(20 55 60)">${[-10,8,26,44,62,80,98].map(x => `<rect x="${x}" y="-10" width="9" height="140" fill="${dark}" opacity=".16"/>`).join('')}</g>`;
|
||||
else if (pattern === 'galaxy') pin = `<ellipse cx="48" cy="52" rx="36" ry="42" fill="#1a0a3a" opacity=".42"/><circle cx="40" cy="44" r="1.4" fill="#fff"/><circle cx="66" cy="38" r="1.1" fill="#fff"/><circle cx="58" cy="64" r="1.5" fill="#fff"/><circle cx="36" cy="70" r="1" fill="#fff"/><circle cx="74" cy="60" r="1.2" fill="#fff"/><circle cx="52" cy="82" r="1" fill="#fff"/><circle cx="68" cy="74" r="1.3" fill="#cba6ff"/>`;
|
||||
else if (pattern === 'gradient') pin = `<rect x="16" y="18" width="78" height="82" fill="url(#${uid}pg)"/>`;
|
||||
else if (pattern === 'hearts') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => `<path d="M0,-1.6 C-2.2,-4.8 -6.4,-1.6 0,3.4 C6.4,-1.6 2.2,-4.8 0,-1.6 Z" transform="translate(${p[0]},${p[1]}) scale(1.5)" fill="${dark}" opacity=".22"/>`).join('');
|
||||
else if (pattern === 'stars') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => `<path d="M0,-4 L1.2,-1.2 4,-1.2 1.8,.7 2.6,3.6 0,1.7 -2.6,3.6 -1.8,.7 -4,-1.2 -1.2,-1.2 Z" transform="translate(${p[0]},${p[1]})" fill="${light}" opacity=".5"/>`).join('');
|
||||
else if (pattern === 'checker') pin = Array.from({ length: 42 }, (_, i) => { const c = i % 6, r = (i / 6) | 0; return ((r + c) % 2) ? '' : `<rect x="${20 + c * 12}" y="${18 + r * 12}" width="12" height="12" fill="${dark}" opacity=".13"/>`; }).join('');
|
||||
patternSvg = `<clipPath id="${uid}clip"><path d="${bodyPath}"/></clipPath><g clip-path="url(#${uid}clip)">${pin}</g>`;
|
||||
}
|
||||
|
||||
|
||||
+123
-6
@@ -289,6 +289,10 @@
|
||||
.pet-scene.bg-aurora { background:radial-gradient(ellipse at 30% 25%,rgba(56,217,140,.6) 0%,transparent 42%),radial-gradient(ellipse at 70% 30%,rgba(120,90,255,.55) 0%,transparent 44%),radial-gradient(ellipse at 50% 92%,rgba(6,214,180,.4) 0%,transparent 52%),linear-gradient(170deg,#02040f,#04122a,#0a0426) !important; }
|
||||
.pet-scene.bg-candy { background:radial-gradient(ellipse at 30% 25%,rgba(255,170,210,.7) 0%,transparent 46%),radial-gradient(ellipse at 75% 70%,rgba(150,200,255,.6) 0%,transparent 46%),linear-gradient(170deg,#3a2540,#52324f,#3a2848) !important; }
|
||||
.pet-scene.bg-sakura { background:radial-gradient(ellipse at 50% 100%,rgba(255,140,190,.7) 0%,transparent 52%),radial-gradient(ellipse at 25% 30%,rgba(255,180,210,.45) 0%,transparent 42%),linear-gradient(170deg,#1a0a14,#2e1226,#241026) !important; }
|
||||
.pet-scene.bg-class { background:radial-gradient(ellipse at 50% 16%,rgba(255,220,150,.32) 0%,transparent 46%),radial-gradient(ellipse at 50% 100%,rgba(56,140,90,.45) 0%,transparent 52%),linear-gradient(170deg,#16241c,#1e3327,#16261d) !important; }
|
||||
.pet-scene.bg-lab { background:radial-gradient(ellipse at 30% 28%,rgba(6,214,224,.45) 0%,transparent 44%),radial-gradient(ellipse at 72% 72%,rgba(56,217,90,.35) 0%,transparent 44%),linear-gradient(170deg,#06121e,#0a1c2c,#08202f) !important; }
|
||||
.pet-scene.bg-winter { background:radial-gradient(ellipse at 50% 100%,rgba(180,220,255,.5) 0%,transparent 55%),radial-gradient(ellipse at 30% 25%,rgba(220,235,255,.35) 0%,transparent 42%),linear-gradient(170deg,#0a1430,#13243f,#1a2c4a) !important; }
|
||||
.pet-scene.bg-rainbow{ background:linear-gradient(160deg,rgba(249,65,68,.34),rgba(249,199,79,.34) 28%,rgba(56,217,90,.32) 52%,rgba(6,214,224,.34) 74%,rgba(155,93,229,.36)),#0e1020 !important; }
|
||||
|
||||
/* B2 — BgFX particle container + keyframes */
|
||||
.pet-bgfx { position:absolute; inset:0; pointer-events:none; overflow:hidden; border-radius:50%; z-index:1; }
|
||||
@@ -368,9 +372,9 @@
|
||||
.pc-head-ico svg { width:17px; height:17px; }
|
||||
.pc-head-title { font-family:'Unbounded',sans-serif; font-size:.92rem; font-weight:800; line-height:1.1; }
|
||||
.pc-head-sub { font-size:.68rem; color:var(--text-3); margin-top:2px; }
|
||||
.pc-tabs { display:flex; gap:4px; padding:4px; background:rgba(15,23,42,.06); border-radius:13px; margin-bottom:16px; }
|
||||
.pc-tab { flex:1; display:inline-flex; align-items:center; justify-content:center; gap:6px; padding:9px 6px; border:none;
|
||||
border-radius:9px; background:transparent; color:var(--text-2); font:700 .76rem 'Manrope',sans-serif; cursor:pointer; transition:all .18s; }
|
||||
.pc-tabs { display:flex; flex-wrap:wrap; gap:4px; padding:4px; background:rgba(15,23,42,.06); border-radius:13px; margin-bottom:16px; }
|
||||
.pc-tab { flex:1 1 84px; display:inline-flex; align-items:center; justify-content:center; gap:5px; padding:9px 5px; border:none;
|
||||
border-radius:9px; background:transparent; color:var(--text-2); font:700 .74rem 'Manrope',sans-serif; cursor:pointer; transition:all .18s; white-space:nowrap; }
|
||||
.pc-tab svg { width:14px; height:14px; }
|
||||
.pc-tab:hover { color:var(--text); background:rgba(15,23,42,.05); }
|
||||
.pc-tab.active { background:linear-gradient(135deg,#9B5DE5,#7b4fd0); color:#fff; box-shadow:0 5px 16px rgba(155,93,229,.45); }
|
||||
@@ -426,6 +430,9 @@
|
||||
.pc-swatch-dot.pat-stripes { background:repeating-linear-gradient(45deg,#9B5DE5 0 5px,#5a2da0 5px 9px); }
|
||||
.pc-swatch-dot.pat-gradient{ background:linear-gradient(180deg,#c9a6ec,#4a2398); }
|
||||
.pc-swatch-dot.pat-galaxy { background:radial-gradient(circle at 62% 38%,#1a0a3a 50%,#9B5DE5); }
|
||||
.pc-swatch-dot.pat-hearts { background:radial-gradient(circle at 35% 40%,#5a2da0 2.5px,transparent 2.7px),radial-gradient(circle at 68% 62%,#5a2da0 2.5px,transparent 2.7px),#9B5DE5; }
|
||||
.pc-swatch-dot.pat-stars { background:radial-gradient(circle at 38% 38%,#fff 1.8px,transparent 2px),radial-gradient(circle at 66% 66%,#fff 1.8px,transparent 2px),#9B5DE5; }
|
||||
.pc-swatch-dot.pat-checker { background:repeating-conic-gradient(#9B5DE5 0% 25%,#5a2da0 0% 50%) 50% / 16px 16px; }
|
||||
|
||||
/* Фон — превью-карточки крупнее */
|
||||
.pc-bg-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(124px,1fr)); gap:11px; }
|
||||
@@ -434,6 +441,14 @@
|
||||
.pc-bg-grid .pet-bg-card.active { box-shadow:0 0 0 2px var(--violet), 0 8px 22px rgba(155,93,229,.4); }
|
||||
.pc-bg-grid .pet-bg-preview { height:78px; }
|
||||
|
||||
/* Образы (наборы) */
|
||||
.pc-sets-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:10px; }
|
||||
.pc-set { display:flex; flex-direction:column; gap:3px; align-items:flex-start; padding:12px 14px; border-radius:14px;
|
||||
border:1.5px solid var(--border-h); background:rgba(15,23,42,.03); cursor:pointer; transition:all .16s; text-align:left; }
|
||||
.pc-set:hover { border-color:var(--violet); transform:translateY(-2px); box-shadow:0 6px 18px rgba(155,93,229,.2); }
|
||||
.pc-set-name { font:800 .84rem 'Unbounded',sans-serif; color:var(--text); }
|
||||
.pc-set-sub { font-size:.66rem; color:var(--text-3); }
|
||||
|
||||
@media(max-width:768px) {
|
||||
.pet-hero { grid-template-columns:1fr; }
|
||||
.pet-bottom { grid-template-columns:1fr; }
|
||||
@@ -666,6 +681,7 @@
|
||||
<button class="pc-tab" data-tab="color" type="button"><i data-lucide="droplet"></i> Цвет</button>
|
||||
<button class="pc-tab" data-tab="pattern" type="button"><i data-lucide="grid-2x2"></i> Узор</button>
|
||||
<button class="pc-tab" data-tab="bg" type="button"><i data-lucide="image"></i> Фон</button>
|
||||
<button class="pc-tab" data-tab="sets" type="button"><i data-lucide="wand-2"></i> Образы</button>
|
||||
</div>
|
||||
<div class="pc-panel" id="pc-acc">
|
||||
<div class="pc-hint">Нажми, чтобы надеть или снять. Заблокированные открываются за достижения. По одному предмету на зону.</div>
|
||||
@@ -683,6 +699,10 @@
|
||||
<div class="pc-hint">Фон сцены. <span id="pc-bg-coins"></span></div>
|
||||
<div class="pc-bg-grid" id="pc-bg-grid"></div>
|
||||
</div>
|
||||
<div class="pc-panel" id="pc-sets" style="display:none">
|
||||
<div class="pc-hint">Готовые образы — применяют аксессуары, узор и цвет одним кликом. Заблокированные предметы пропускаются.</div>
|
||||
<div class="pc-sets-grid" id="pc-sets-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -713,10 +733,13 @@ const EVO_STAGES = ['','Яйцо','Малыш','Подросток','Взрос
|
||||
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',
|
||||
};
|
||||
const PALETTE_LABELS = {
|
||||
purple:'Фиолетовый', cyan:'Голубой', gold:'Золотой',
|
||||
red:'Красный', green:'Зелёный', blue:'Синий',
|
||||
pink:'Розовый', orange:'Оранжевый', teal:'Бирюзовый', lime:'Лаймовый', indigo:'Индиго',
|
||||
};
|
||||
const MOOD_LABELS = {
|
||||
ecstatic:['Восторг!', 'mood-ecstatic-badge'],
|
||||
@@ -922,6 +945,36 @@ function applyBgFX(bgId) {
|
||||
d.style.cssText = `position:absolute;left:${rnd(2,94)}%;top:-12px;width:${s}px;height:${(s*.8).toFixed(1)}px;border-radius:60% 0 60% 0;background:rgba(255,160,200,.85);--px:${rndI(-18,18)}px;animation:bgPetal ${rnd(3,6)}s ${rnd(0,5)}s linear infinite`;
|
||||
c.appendChild(d);
|
||||
}
|
||||
} else if (bgId === 'class') {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const d = document.createElement('div');
|
||||
const s = rnd(1.5, 3);
|
||||
d.style.cssText = `position:absolute;left:${rnd(5,92)}%;top:${rnd(5,80)}%;width:${s}px;height:${s}px;border-radius:50%;background:rgba(255,230,170,.8);animation:bgStarTwink ${rnd(2,4)}s ${rnd(0,4)}s ease-in-out infinite`;
|
||||
c.appendChild(d);
|
||||
}
|
||||
} else if (bgId === 'lab') {
|
||||
for (let i = 0; i < 11; i++) {
|
||||
const d = document.createElement('div');
|
||||
const s = rnd(4, 13);
|
||||
const col = Math.random() > .5 ? 'rgba(6,214,224,.8)' : 'rgba(56,217,90,.75)';
|
||||
d.style.cssText = `position:absolute;left:${rnd(8,88)}%;bottom:-15px;width:${s}px;height:${s}px;border-radius:50%;border:1.5px solid ${col};animation:bgBubble ${rnd(2.5,5)}s ${rnd(0,6)}s ease-out infinite`;
|
||||
c.appendChild(d);
|
||||
}
|
||||
} else if (bgId === 'winter') {
|
||||
for (let i = 0; i < 18; i++) {
|
||||
const d = document.createElement('div');
|
||||
const s = rnd(2.5, 5);
|
||||
d.style.cssText = `position:absolute;left:${rnd(2,95)}%;top:-10px;width:${s}px;height:${s}px;border-radius:50%;background:rgba(255,255,255,.9);--px:${rndI(-14,14)}px;animation:bgPetal ${rnd(3.5,7)}s ${rnd(0,5)}s linear infinite`;
|
||||
c.appendChild(d);
|
||||
}
|
||||
} else if (bgId === 'rainbow') {
|
||||
const cols = ['#F94144','#F9C74F','#38D95A','#06D6E0','#9B5DE5'];
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const d = document.createElement('div');
|
||||
const s = rnd(2, 4);
|
||||
d.style.cssText = `position:absolute;left:${rnd(4,93)}%;top:${rnd(4,86)}%;width:${s}px;height:${s}px;border-radius:50%;background:${cols[i % cols.length]};box-shadow:0 0 5px ${cols[i % cols.length]};animation:bgStarTwink ${rnd(1.3,3.2)}s ${rnd(0,4)}s ease-in-out infinite`;
|
||||
c.appendChild(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,8 +1043,12 @@ const BG_PREVIEWS = {
|
||||
aurora: 'radial-gradient(ellipse at 35% 25%,rgba(56,217,140,.85) 0%,transparent 50%),radial-gradient(ellipse at 70% 35%,rgba(120,90,255,.7) 0%,transparent 50%),linear-gradient(155deg,#02040f,#0a0426)',
|
||||
candy: 'radial-gradient(ellipse at 30% 25%,rgba(255,170,210,.9) 0%,transparent 55%),radial-gradient(ellipse at 75% 75%,rgba(150,200,255,.8) 0%,transparent 55%),linear-gradient(155deg,#3a2540,#3a2848)',
|
||||
sakura: 'radial-gradient(ellipse at 50% 100%,rgba(255,140,190,.9) 0%,transparent 55%),linear-gradient(155deg,#1a0a14,#241026)',
|
||||
class: 'radial-gradient(ellipse at 50% 18%,rgba(255,220,150,.5) 0%,transparent 50%),linear-gradient(155deg,#16241c,#16261d)',
|
||||
lab: 'radial-gradient(ellipse at 32% 30%,rgba(6,214,224,.75) 0%,transparent 50%),radial-gradient(ellipse at 72% 72%,rgba(56,217,90,.6) 0%,transparent 50%),linear-gradient(155deg,#06121e,#08202f)',
|
||||
winter: 'radial-gradient(ellipse at 50% 100%,rgba(180,220,255,.85) 0%,transparent 55%),linear-gradient(155deg,#0a1430,#1a2c4a)',
|
||||
rainbow: 'linear-gradient(160deg,#f94144,#f9c74f 30%,#38d95a 55%,#06d6e0 78%,#9b5de5)',
|
||||
};
|
||||
const BG_NAMES = { default:'Стандарт', space:'Космос', forest:'Лес', aqua:'Океан', sunset:'Закат', aurora:'Сияние', candy:'Леденец', sakura:'Сакура' };
|
||||
const BG_NAMES = { default:'Стандарт', space:'Космос', forest:'Лес', aqua:'Океан', sunset:'Закат', aurora:'Сияние', candy:'Леденец', sakura:'Сакура', class:'Класс', lab:'Лаборатория', winter:'Зима', rainbow:'Радуга' };
|
||||
|
||||
async function openPetShop() {
|
||||
const data = await LS.api('/api/pet/shop').catch(() => null);
|
||||
@@ -1077,7 +1134,9 @@ function setupCustomizeTabs() {
|
||||
document.getElementById('pc-color').style.display = which === 'color' ? '' : 'none';
|
||||
document.getElementById('pc-pattern').style.display = which === 'pattern' ? '' : 'none';
|
||||
document.getElementById('pc-bg').style.display = which === 'bg' ? '' : 'none';
|
||||
document.getElementById('pc-sets').style.display = which === 'sets' ? '' : 'none';
|
||||
if (which === 'bg') renderBgPicker();
|
||||
if (which === 'sets') renderSets();
|
||||
}));
|
||||
const ov = document.getElementById('wardrobe-modal');
|
||||
if (ov) ov.addEventListener('click', e => { if (e.target === ov) closeWardrobe(); });
|
||||
@@ -1378,7 +1437,7 @@ const LOCK_ICO = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" st
|
||||
const CHECK_ICO = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||
const ICO_SHUFFLE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 3h5v5"/><path d="M4 20 21 3"/><path d="M21 16v5h-5"/><path d="m15 15 6 6"/><path d="M4 4l5 5"/></svg>';
|
||||
const ICO_ERASE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4.3-4.3a1 1 0 0 1 0-1.4L13 5l6 6-9 9"/><path d="M22 21H7"/></svg>';
|
||||
const ZONE_LABELS = { head:'Голова', face:'Лицо', neck:'Шея', ears:'Уши', accent:'Акцент' };
|
||||
const ZONE_LABELS = { head:'Голова', face:'Лицо', neck:'Шея', ears:'Уши', hands:'В лапах', accent:'Акцент' };
|
||||
|
||||
/* ── Гардеробная: модалка + живое превью ── */
|
||||
function petSvgHTML() {
|
||||
@@ -1424,7 +1483,7 @@ function renderWardrobe(items) {
|
||||
<button type="button" class="wr-btn" id="wr-random">${ICO_SHUFFLE}Случайный образ</button>
|
||||
<button type="button" class="wr-btn" id="wr-clear">${ICO_ERASE}Снять всё</button>
|
||||
</span></div>`;
|
||||
['head','face','neck','ears','accent'].forEach(z => {
|
||||
['head','face','neck','ears','hands','accent'].forEach(z => {
|
||||
const zi = items.filter(i => i.slot === z);
|
||||
if (!zi.length) return;
|
||||
html += `<div class="wr-zone"><div class="wr-zone-lbl">${ZONE_LABELS[z]||z}</div><div class="wr-chips">${zi.map(wearChip).join('')}</div></div>`;
|
||||
@@ -1482,6 +1541,29 @@ async function applyPattern(id) {
|
||||
renderPatternPicker(_petData.patterns || [], id);
|
||||
}
|
||||
|
||||
/* ── Готовые образы (наборы) ── */
|
||||
const OUTFIT_SETS = [
|
||||
{ id:'scientist', name:'Учёный', acc:['grad','glasses','medal'], pattern:'none', color:'cyan' },
|
||||
{ id:'wizard', name:'Волшебник', acc:['party','wand'], pattern:'galaxy', color:'indigo' },
|
||||
{ id:'champion', name:'Чемпион', acc:['crown','star','medal'], pattern:'gradient', color:'gold' },
|
||||
{ id:'cutie', name:'Милашка', acc:['flower','bowtie','balloon'],pattern:'hearts', color:'pink' },
|
||||
];
|
||||
function renderSets() {
|
||||
const el = document.getElementById('pc-sets-grid'); if (!el) return;
|
||||
el.innerHTML = OUTFIT_SETS.map(s => `<button type="button" class="pc-set" data-set="${s.id}">
|
||||
<span class="pc-set-name">${escHtml(s.name)}</span>
|
||||
<span class="pc-set-sub">${s.acc.length} предмета · ${PALETTE_LABELS[s.color] || s.color}</span></button>`).join('');
|
||||
el.querySelectorAll('.pc-set').forEach(b => b.addEventListener('click', () => applySet(b.dataset.set)));
|
||||
}
|
||||
async function applySet(id) {
|
||||
const set = OUTFIT_SETS.find(s => s.id === id); if (!set || !_petData) return;
|
||||
const unlocked = new Set((_petData.wardrobe || []).filter(w => !w.locked).map(w => w.id));
|
||||
await setEquipped(set.acc.filter(a => unlocked.has(a)));
|
||||
if (set.color && _petData.petColor !== set.color) await selectColor(set.color);
|
||||
if (set.pattern && _petData.petPattern !== set.pattern) await applyPattern(set.pattern);
|
||||
LS.toast?.('Образ «' + set.name + '» применён', 'success');
|
||||
}
|
||||
|
||||
/* ── Petting ── */
|
||||
async function petThePet() {
|
||||
if (_petCooldown) return;
|
||||
@@ -1921,6 +2003,38 @@ function renderPetSVG(level, mood, accessories = [], colorKey = 'purple', streak
|
||||
if (accessories.includes('flower')) {
|
||||
accSvg += `<g transform="translate(82,30)"><circle cx="0" cy="-5" r="3.2" fill="#FF8FB1"/><circle cx="5" cy="-1" r="3.2" fill="#FF8FB1"/><circle cx="3" cy="5" r="3.2" fill="#FF8FB1"/><circle cx="-3" cy="5" r="3.2" fill="#FF8FB1"/><circle cx="-5" cy="-1" r="3.2" fill="#FF8FB1"/><circle cx="0" cy="0" r="2.6" fill="#F9C74F"/></g>`;
|
||||
}
|
||||
if (accessories.includes('beanie')) {
|
||||
accSvg += `<path d="M30,30 Q30,11 55,11 Q80,11 80,30 Z" fill="${col}"/>
|
||||
<rect x="28" y="27" width="54" height="6" rx="3" fill="${light}" opacity=".6"/>
|
||||
<circle cx="55" cy="10" r="4" fill="${light}"/>`;
|
||||
}
|
||||
if (accessories.includes('halo')) {
|
||||
accSvg += `<ellipse cx="55" cy="9" rx="17" ry="5" fill="none" stroke="#FCD667" stroke-width="3"/>
|
||||
<ellipse cx="55" cy="9" rx="17" ry="5" fill="none" stroke="#fff" stroke-width="1" opacity=".5"/>`;
|
||||
}
|
||||
if (accessories.includes('monocle')) {
|
||||
accSvg += `<circle cx="70" cy="52" r="13" fill="rgba(255,255,255,.1)" stroke="#FCD667" stroke-width="2"/>
|
||||
<path d="M70,65 Q66,75 59,79" stroke="#FCD667" stroke-width="1.4" fill="none"/>`;
|
||||
}
|
||||
if (accessories.includes('medal')) {
|
||||
accSvg += `<path d="M50,76 L48,86 L55,82 L62,86 L60,76 Z" fill="#e0335e"/>
|
||||
<circle cx="55" cy="89" r="6" fill="#FCD667" stroke="#d4920a" stroke-width="1.2"/>
|
||||
<path d="M52.4,89 l2,2 3.6,-4.2" stroke="#7a5a00" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`;
|
||||
}
|
||||
if (accessories.includes('earrings')) {
|
||||
accSvg += `<line x1="30" y1="44" x2="30" y2="46.5" stroke="#FCD667" stroke-width="1.2"/><circle cx="30" cy="48.5" r="2.5" fill="#FCD667"/>
|
||||
<line x1="80" y1="44" x2="80" y2="46.5" stroke="#FCD667" stroke-width="1.2"/><circle cx="80" cy="48.5" r="2.5" fill="#FCD667"/>`;
|
||||
}
|
||||
if (accessories.includes('wand')) {
|
||||
accSvg += `<line x1="92" y1="92" x2="104" y2="66" stroke="#9b6a2f" stroke-width="2.4" stroke-linecap="round"/>
|
||||
<path d="M104,60 l1.5,3.4 3.7,.3 -2.8,2.5 .9,3.6 -3.3,-2 -3.3,2 .9,-3.6 -2.8,-2.5 3.7,-.3 Z" fill="#FCD667"/>`;
|
||||
}
|
||||
if (accessories.includes('balloon')) {
|
||||
accSvg += `<line x1="14" y1="78" x2="12" y2="40" stroke="rgba(150,150,160,.55)" stroke-width="1"/>
|
||||
<ellipse cx="12" cy="32" rx="9" ry="11" fill="#F15BB5"/>
|
||||
<ellipse cx="9" cy="28" rx="2.4" ry="3" fill="#fff" opacity=".45"/>
|
||||
<path d="M12,43 l-2.4,3.4 4.8,0 Z" fill="#F15BB5"/>`;
|
||||
}
|
||||
if (accessories.includes('headphones')) {
|
||||
accSvg += `<path d="M27,42 Q55,6 83,42" fill="none" stroke="#2a3340" stroke-width="4" stroke-linecap="round"/>
|
||||
<rect x="21" y="38" width="11" height="17" rx="4.5" fill="#2a3340"/>
|
||||
@@ -2075,6 +2189,9 @@ function renderPetSVG(level, mood, accessories = [], colorKey = 'purple', streak
|
||||
else if (pattern === 'stripes') pin = `<g transform="rotate(20 55 60)">${[-10,8,26,44,62,80,98].map(x => `<rect x="${x}" y="-10" width="9" height="140" fill="${dark}" opacity=".16"/>`).join('')}</g>`;
|
||||
else if (pattern === 'galaxy') pin = `<ellipse cx="48" cy="52" rx="36" ry="42" fill="#1a0a3a" opacity=".42"/><circle cx="40" cy="44" r="1.4" fill="#fff"/><circle cx="66" cy="38" r="1.1" fill="#fff"/><circle cx="58" cy="64" r="1.5" fill="#fff"/><circle cx="36" cy="70" r="1" fill="#fff"/><circle cx="74" cy="60" r="1.2" fill="#fff"/><circle cx="52" cy="82" r="1" fill="#fff"/><circle cx="68" cy="74" r="1.3" fill="#cba6ff"/>`;
|
||||
else if (pattern === 'gradient') pin = `<rect x="16" y="18" width="78" height="82" fill="url(#${uid}pg)"/>`;
|
||||
else if (pattern === 'hearts') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => `<path d="M0,-1.6 C-2.2,-4.8 -6.4,-1.6 0,3.4 C6.4,-1.6 2.2,-4.8 0,-1.6 Z" transform="translate(${p[0]},${p[1]}) scale(1.5)" fill="${dark}" opacity=".22"/>`).join('');
|
||||
else if (pattern === 'stars') pin = [[40,44],[68,40],[57,70],[36,73],[76,63],[52,33]].map(p => `<path d="M0,-4 L1.2,-1.2 4,-1.2 1.8,.7 2.6,3.6 0,1.7 -2.6,3.6 -1.8,.7 -4,-1.2 -1.2,-1.2 Z" transform="translate(${p[0]},${p[1]})" fill="${light}" opacity=".5"/>`).join('');
|
||||
else if (pattern === 'checker') pin = Array.from({ length: 42 }, (_, i) => { const c = i % 6, r = (i / 6) | 0; return ((r + c) % 2) ? '' : `<rect x="${20 + c * 12}" y="${18 + r * 12}" width="12" height="12" fill="${dark}" opacity=".13"/>`; }).join('');
|
||||
patternSvg = `<clipPath id="${uid}clip"><path d="${bodyPath}"/></clipPath><g clip-path="url(#${uid}clip)">${pin}</g>`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user