feat(pet): гардероб — выбор аксессуаров + новые украшения
Аксессуары больше не навешиваются авто по уровню — теперь разблокируются и НАДЕВАЮТСЯ по выбору (один на слот). Новые: шапочка выпускника, наушники, бабочка (бесплатные — доступны даже при 0 XP). Сохранены цилиндр/корона/очки/ звезда с прежними порогами; дефолт повторяет старый вид (без сюрпризов). Бэкенд: миграция pet_equipped, каталог ACCESSORY_CATALOG + /api/pet/equip (валидация разблокировки и слотов). Рендер аксессуаров строго по equipped — в обеих копиях (pet.html и pet-sprite.js для дашборда). UI гардероба на /pet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -141,13 +141,34 @@
|
||||
<circle cx="97" cy="84" r="2.8" fill="${dark}" opacity=".45"/>
|
||||
<circle cx="92" cy="83" r="2.8" fill="${dark}" opacity=".45"/>`;
|
||||
|
||||
/* ── Accessories ── */
|
||||
/* ── Accessories (гардероб: строго по equipped-списку, без авто по уровню) ── */
|
||||
let accSvg = '';
|
||||
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"/>
|
||||
<rect x="78" y="38" width="11" height="17" rx="4.5" fill="#2a3340"/>
|
||||
<rect x="24" y="41" width="5" height="11" rx="2.5" fill="${col}"/>
|
||||
<rect x="81" y="41" width="5" height="11" rx="2.5" fill="${col}"/>`;
|
||||
}
|
||||
if (accessories.includes('grad')) {
|
||||
accSvg += `<path d="M44,25 Q55,30 66,25 L66,30 Q55,35 44,30 Z" fill="#2a3340"/>
|
||||
<path d="M28,21 L55,13 L82,21 L55,29 Z" fill="#1f2733"/>
|
||||
<line x1="55" y1="21" x2="78" y2="22" stroke="#F9C74F" stroke-width="1.3"/>
|
||||
<line x1="78" y1="22" x2="78" y2="33" stroke="#F9C74F" stroke-width="1.3"/>
|
||||
<circle cx="78" cy="35" r="2.6" fill="#F9C74F"/>`;
|
||||
}
|
||||
if (accessories.includes('hat')) {
|
||||
accSvg += `<rect x="36" y="22" width="38" height="6" rx="3" fill="#2a2a2a"/>
|
||||
<rect x="42" y="6" width="26" height="17" rx="4" fill="#1a1a1a"/>
|
||||
<rect x="42" y="6" width="26" height="5" rx="2" fill="#333" opacity=".6"/>`;
|
||||
}
|
||||
if (accessories.includes('crown')) {
|
||||
accSvg += `<path d="M33,26 L41,10 L55,22 L69,10 L77,26 L78,32 L32,32 Z" fill="#F9C74F"/>
|
||||
<rect x="32" y="28" width="46" height="6" rx="2" fill="#F9C74F"/>
|
||||
<circle cx="41" cy="11" r="4" fill="#F94144"/>
|
||||
<circle cx="55" cy="23" r="4" fill="#06D6E0"/>
|
||||
<circle cx="69" cy="11" r="4" fill="#9B5DE5"/>`;
|
||||
}
|
||||
if (accessories.includes('glasses')) {
|
||||
accSvg += `<circle cx="${eyeX1}" cy="${eyeY}" r="14" fill="none" stroke="rgba(255,255,255,.65)" stroke-width="2"/>
|
||||
<circle cx="${eyeX2}" cy="${eyeY}" r="14" fill="none" stroke="rgba(255,255,255,.65)" stroke-width="2"/>
|
||||
@@ -155,14 +176,12 @@
|
||||
<line x1="19" y1="${eyeY-3}" x2="26" y2="${eyeY}" stroke="rgba(255,255,255,.45)" stroke-width="1.5"/>
|
||||
<line x1="91" y1="${eyeY-3}" x2="84" y2="${eyeY}" stroke="rgba(255,255,255,.45)" stroke-width="1.5"/>`;
|
||||
}
|
||||
if (accessories.includes('crown') || level >= 5) {
|
||||
accSvg += `<path d="M33,26 L41,10 L55,22 L69,10 L77,26 L78,32 L32,32 Z" fill="#F9C74F"/>
|
||||
<rect x="32" y="28" width="46" height="6" rx="2" fill="#F9C74F"/>
|
||||
<circle cx="41" cy="11" r="4" fill="#F94144"/>
|
||||
<circle cx="55" cy="23" r="4" fill="#06D6E0"/>
|
||||
<circle cx="69" cy="11" r="4" fill="#9B5DE5"/>`;
|
||||
if (accessories.includes('bowtie')) {
|
||||
accSvg += `<path d="M55,85 L44,80 L44,90 Z" fill="${dark}"/>
|
||||
<path d="M55,85 L66,80 L66,90 Z" fill="${dark}"/>
|
||||
<rect x="52" y="82" width="6" height="6" rx="2" fill="${light}"/>`;
|
||||
}
|
||||
if (accessories.includes('star') && level < 5) {
|
||||
if (accessories.includes('star')) {
|
||||
accSvg += `<polygon points="98,18 100,24 106,24 101,28 103,34 98,30 93,34 95,28 90,24 96,24" fill="#F9C74F"/>`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user