// Economy, Sun, Coin Drops & Crazy Dave's Shop System window.EconomySystem = class EconomySystem { constructor() { this.sun = 50; this.suns = []; this.coins = []; this.skySunTimer = 0; this.skySunInterval = 8.5; this.isNight = false; this.isConveyor = false; // For Wall-nut bowling mini-game this.isIZombie = false; // Total coins & upgrades persistent storage this.reloadProfileData(); // Full Card Registry this.allCards = [ { id: 'sunflower', name: 'Подсолнух', cost: 50, cooldown: 7.5, timer: 0 }, { id: 'peashooter', name: 'Горохострел', cost: 100, cooldown: 7.5, timer: 0 }, { id: 'potatomine', name: 'Мина', cost: 25, cooldown: 18.0, timer: 0 }, { id: 'wallnut', name: 'Стеноорех', cost: 50, cooldown: 20.0, timer: 0 }, { id: 'repeater', name: 'Повторитель', cost: 200, cooldown: 7.5, timer: 0 }, { id: 'snowpea', name: 'Ледяной', cost: 175, cooldown: 10.0, timer: 0 }, { id: 'chomper', name: 'Зубастик', cost: 150, cooldown: 10.0, timer: 0 }, { id: 'cherrybomb', name: 'Вишня', cost: 150, cooldown: 25.0, timer: 0 }, { id: 'jalapeno', name: 'Халапеньо', cost: 125, cooldown: 30.0, timer: 0 }, { id: 'sunshroom', name: 'Солнцегриб', cost: 25, cooldown: 7.5, timer: 0 }, { id: 'fumeshroom', name: 'Дымогриб', cost: 75, cooldown: 7.5, timer: 0 }, { id: 'lilypad', name: 'Кувшинка', cost: 25, cooldown: 7.5, timer: 0 }, { id: 'gravebuster', name: 'Могилоед', cost: 75, cooldown: 15.0, timer: 0 }, { id: 'flowerpot', name: 'Горшок', cost: 25, cooldown: 7.5, timer: 0 }, { id: 'cabbagepult', name: 'Капуста', cost: 100, cooldown: 7.5, timer: 0 }, { id: 'melonpult', name: 'Арбуз', cost: 300, cooldown: 15.0, timer: 0 } ]; this.selectedCard = null; this.animTime = 0; this.setDeckForLevel(1, 'day'); } reloadProfileData() { if (window.PvZAuth) { const uData = window.PvZAuth.getUserData(); this.totalCoins = uData.coins !== undefined ? uData.coins : 250; this.upgrades = uData.upgrades || { extraSlot: false, hasRake: false }; } else { this.totalCoins = parseInt(localStorage.getItem('pvz_coins') || '250', 10); this.upgrades = { extraSlot: localStorage.getItem('pvz_upg_slot') === 'true', hasRake: localStorage.getItem('pvz_upg_rake') === 'true' }; } } saveProfileData() { localStorage.setItem('pvz_coins', this.totalCoins.toString()); localStorage.setItem('pvz_upg_slot', this.upgrades.extraSlot ? 'true' : 'false'); localStorage.setItem('pvz_upg_rake', this.upgrades.hasRake ? 'true' : 'false'); if (window.PvZAuth && !window.PvZAuth.isGuest()) { window.PvZAuth.saveUserData({ coins: this.totalCoins, upgrades: this.upgrades }); } } setDeckForLevel(level = 1, biome = 'day') { this.isNight = biome === 'night'; this.isConveyor = false; this.isIZombie = false; // Card slots count (5 default, 6 with Dave's extra slot upgrade) const slotCount = this.upgrades.extraSlot ? 6 : 5; // Choose relevant deck based on biome and progression let availableIds = []; if (biome === 'roof') { availableIds = ['flowerpot', 'cabbagepult', 'melonpult', 'wallnut', 'jalapeno', 'potatomine']; } else if (biome === 'fog') { availableIds = ['sunshroom', 'fumeshroom', 'lilypad', 'cabbagepult', 'wallnut', 'snowpea']; } else if (biome === 'night') { availableIds = ['sunshroom', 'fumeshroom', 'potatomine', 'wallnut', 'gravebuster', 'hypnoshroom']; } else if (biome === 'pool') { availableIds = ['sunflower', 'peashooter', 'lilypad', 'wallnut', 'repeater', 'snowpea']; } else { if (level === 1) availableIds = ['sunflower', 'peashooter', 'potatomine', 'wallnut', 'cherrybomb']; else if (level === 2) availableIds = ['sunflower', 'peashooter', 'repeater', 'wallnut', 'jalapeno']; else availableIds = ['sunflower', 'peashooter', 'snowpea', 'chomper', 'wallnut', 'jalapeno']; } this.cards = this.allCards.filter(c => availableIds.includes(c.id)).slice(0, slotCount); } setBossDeck() { this.isConveyor = true; this.isIZombie = false; this.cards = [ { id: 'flowerpot', name: 'Горшок', cost: 0, cooldown: 3.5, timer: 0 }, { id: 'cabbagepult', name: 'Капуста', cost: 0, cooldown: 5.0, timer: 0 }, { id: 'melonpult', name: 'Арбуз', cost: 0, cooldown: 10.0, timer: 0 }, { id: 'jalapeno', name: 'Халапеньо', cost: 0, cooldown: 14.0, timer: 0 }, { id: 'snowpea', name: 'Ледяной', cost: 0, cooldown: 8.0, timer: 0 } ]; } setConveyorDeck() { this.isConveyor = true; this.isIZombie = false; this.cards = [ { id: 'bowling_nut', name: 'Орех-шар', cost: 0, cooldown: 4.0, timer: 0 }, { id: 'bowling_cherry', name: 'Взрывной', cost: 0, cooldown: 12.0, timer: 0 } ]; } setIZombieDeck() { this.isConveyor = false; this.isIZombie = true; this.isNight = true; this.sun = 200; this.cards = [ { id: 'z_normal', name: 'Обычный', cost: 50, cooldown: 2.0, timer: 0 }, { id: 'z_conehead', name: 'Конус', cost: 75, cooldown: 3.0, timer: 0 }, { id: 'z_polevaulter', name: 'С шестом', cost: 75, cooldown: 4.0, timer: 0 }, { id: 'z_buckethead', name: 'Ведро', cost: 125, cooldown: 5.0, timer: 0 }, { id: 'z_football', name: 'Футболист', cost: 175, cooldown: 6.0, timer: 0 } ]; } reset() { let baseSun = this.isConveyor ? 0 : (this.isIZombie ? 200 : 50); if (!this.isConveyor && !this.isIZombie && this.workshop) { baseSun += this.workshop.getPerkLevel('startSun') * 50; } this.sun = baseSun; this.suns = []; this.coins = []; this.skySunTimer = 0; this.selectedCard = null; this.cards.forEach(c => c.timer = 0); } addSun(amount) { this.sun += amount; if (this.engine && this.engine.achievements) { this.engine.achievements.setProgress('sun_tycoon', this.sun); } } canAfford(cost) { return this.isConveyor || this.sun >= cost; } spendSun(cost) { if (this.isConveyor) return true; if (this.sun >= cost) { this.sun -= cost; return true; } return false; } addCoins(amount) { this.totalCoins += amount; this.saveProfileData(); } buyUpgrade(type) { if (type === 'extraSlot' && this.totalCoins >= 500 && !this.upgrades.extraSlot) { this.addCoins(-500); this.upgrades.extraSlot = true; this.saveProfileData(); this.setDeckForLevel(1, this.isNight ? 'night' : 'day'); return true; } else if (type === 'rake' && this.totalCoins >= 150 && !this.upgrades.hasRake) { this.addCoins(-150); this.upgrades.hasRake = true; this.saveProfileData(); return true; } return false; } spawnSun(x, y, value = 25, isFalling = false, targetY = null) { this.suns.push({ x, y, targetY: targetY !== null ? targetY : y, value, isFalling, fallSpeed: 90, radius: 26, life: 13.0, collecting: false, toRemove: false, pulse: Math.random() * 5 }); } spawnCoin(x, y, type = 'silver') { const val = type === 'diamond' ? 200 : (type === 'gold' ? 50 : 10); this.coins.push({ x, y, type, value: val, radius: 16, life: 12.0, collecting: false, toRemove: false, pulse: Math.random() * 5 }); } update(dt) { this.animTime += dt; // Cooldown timers with fastCool perk bonus const fastCoolLvl = this.workshop ? this.workshop.getPerkLevel('fastCool') : 0; const cooldownMultiplier = 1 + fastCoolLvl * 0.15; for (const card of this.cards) { if (card.timer > 0) { card.timer = Math.max(0, card.timer - dt * cooldownMultiplier); } } // Sky sun spawner (disabled at night and in conveyor mode) if (!this.isNight && !this.isConveyor) { this.skySunTimer += dt; if (this.skySunTimer >= this.skySunInterval) { this.skySunTimer = 0; const spawnX = 140 + Math.random() * 640; const targetY = 140 + Math.random() * 380; this.spawnSun(spawnX, 40, 25, true, targetY); } } // Active suns for (const s of this.suns) { s.pulse += dt * 4; if (s.collecting) { const targetX = 50; const targetY = 45; const dx = targetX - s.x; const dy = targetY - s.y; const dist = Math.hypot(dx, dy); if (dist < 15) { this.addSun(s.value); s.toRemove = true; } else { s.x += (dx / dist) * 750 * dt; s.y += (dy / dist) * 750 * dt; } } else { if (s.isFalling && s.y < s.targetY) { s.y += s.fallSpeed * dt; } s.life -= dt; if (s.life <= 0) s.toRemove = true; } } this.suns = this.suns.filter(s => !s.toRemove); // Active coins for (const c of this.coins) { c.pulse += dt * 5; if (c.collecting) { const targetX = 850; const targetY = 45; const dx = targetX - c.x; const dy = targetY - c.y; const dist = Math.hypot(dx, dy); if (dist < 15) { this.addCoins(c.value); c.toRemove = true; } else { c.x += (dx / dist) * 750 * dt; c.y += (dy / dist) * 750 * dt; } } else { c.life -= dt; if (c.life <= 0) c.toRemove = true; } } this.coins = this.coins.filter(c => !c.toRemove); } handleClick(mouseX, mouseY) { // 0. Workshop Floating Loot if (this.workshop) { for (let i = this.workshop.floatingLoot.length - 1; i >= 0; i--) { const loot = this.workshop.floatingLoot[i]; if (!loot.collected && Math.hypot(mouseX - loot.x, mouseY - loot.y) <= 30) { this.workshop.collectLoot(loot); return { handled: true, action: 'loot_collected' }; } } } // 1. Suns for (let i = this.suns.length - 1; i >= 0; i--) { const s = this.suns[i]; if (!s.collecting && Math.hypot(mouseX - s.x, mouseY - s.y) <= s.radius + 14) { s.collecting = true; if (window.PvZAudio) window.PvZAudio.playSun(); if (this.workshop) { this.sunCount = (this.sunCount || 0) + 1; if (this.sunCount >= 8) { this.sunCount = 0; this.workshop.addMaterial('sunEssence', 1); } } return { handled: true, action: 'sun_collected' }; } } // 2. Coins for (let i = this.coins.length - 1; i >= 0; i--) { const c = this.coins[i]; if (!c.collecting && Math.hypot(mouseX - c.x, mouseY - c.y) <= c.radius + 14) { c.collecting = true; if (window.PvZAudio) window.PvZAudio.playCoin(); return { handled: true, action: 'coin_collected' }; } } // 3. Seed Cards const cardStartX = 105; const cardY = 8; const cardW = 66; const cardH = 72; const spacing = 72; for (let i = 0; i < this.cards.length; i++) { const card = this.cards[i]; const cx = cardStartX + i * spacing; if (mouseX >= cx && mouseX <= cx + cardW && mouseY >= cardY && mouseY <= cardY + cardH) { if (this.canAfford(card.cost) && card.timer <= 0) { this.selectedCard = (this.selectedCard === card.id) ? null : card.id; } return { handled: true, action: 'card_selected' }; } } // 4. Shovel const shovelX = cardStartX + this.cards.length * spacing + 12; if (mouseX >= shovelX && mouseX <= shovelX + 54 && mouseY >= cardY && mouseY <= cardY + cardH) { this.selectedCard = (this.selectedCard === 'shovel') ? null : 'shovel'; return { handled: true, action: 'shovel_selected' }; } return { handled: false }; } startCooldown(cardId) { const card = this.cards.find(c => c.id === cardId); if (card) { card.timer = card.cooldown; } } draw(ctx) { // HUD Bar Background ctx.fillStyle = this.isNight ? '#1a100c' : '#2c1810'; ctx.fillRect(0, 0, 900, 90); ctx.fillStyle = this.isNight ? '#2a1810' : '#422817'; ctx.fillRect(0, 0, 900, 86); // 1. Sun Bank Box (or Conveyor indicator) if (!this.isConveyor) { ctx.fillStyle = '#e0c080'; ctx.beginPath(); ctx.roundRect(10, 8, 85, 72, 8); ctx.fill(); ctx.strokeStyle = '#6d4c41'; ctx.lineWidth = 3; ctx.stroke(); this.drawSunGraphic(ctx, 36, 34, 16, 0, 1); ctx.fillStyle = '#000'; ctx.font = 'bold 18px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(this.sun, 52, 66); } else { // Conveyor belt indicator ctx.fillStyle = '#616161'; ctx.beginPath(); ctx.roundRect(10, 8, 85, 72, 8); ctx.fill(); ctx.fillStyle = '#fff'; ctx.font = 'bold 12px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('КОНВЕЙЕР', 52, 48); } // 2. Draw Cards const cardStartX = 105; const cardY = 8; const cardW = 66; const cardH = 72; const spacing = 72; for (let i = 0; i < this.cards.length; i++) { const card = this.cards[i]; const cx = cardStartX + i * spacing; const isSelected = this.selectedCard === card.id; const affordable = this.canAfford(card.cost); const ready = card.timer <= 0; ctx.fillStyle = isSelected ? '#fff9c4' : (affordable && ready ? '#fff8e1' : '#b0bec5'); ctx.beginPath(); ctx.roundRect(cx, cardY, cardW, cardH, 6); ctx.fill(); ctx.strokeStyle = isSelected ? '#ffeb3b' : (affordable && ready ? '#8d6e63' : '#546e7a'); ctx.lineWidth = isSelected ? 3 : 2; ctx.stroke(); this.drawCardThumbnail(ctx, card.id, cx + cardW / 2, cardY + 28); if (this.workshop) { const lvl = this.workshop.getPlantLevel(card.id); if (lvl > 1) { ctx.fillStyle = lvl === 3 ? '#e65100' : '#f57f17'; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'right'; ctx.fillText(lvl === 3 ? '★★★' : '★★', cx + cardW - 4, cardY + 11); } } ctx.fillStyle = '#263238'; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(card.name, cx + cardW / 2, cardY + 54); if (!this.isConveyor) { ctx.fillStyle = affordable ? '#1b5e20' : '#b71c1c'; ctx.font = 'bold 11px sans-serif'; ctx.fillText(card.cost, cx + cardW / 2, cardY + 68); } else { ctx.fillStyle = '#1b5e20'; ctx.font = 'bold 10px sans-serif'; ctx.fillText('БЕСПЛАТНО', cx + cardW / 2, cardY + 68); } if (card.timer > 0) { const cdRatio = card.timer / card.cooldown; ctx.fillStyle = 'rgba(0, 0, 0, 0.55)'; ctx.beginPath(); ctx.rect(cx, cardY, cardW, cardH * cdRatio); ctx.fill(); ctx.fillStyle = '#ffffff'; ctx.font = 'bold 13px sans-serif'; ctx.fillText(Math.ceil(card.timer), cx + cardW / 2, cardY + cardH / 2 + 5); } } // 3. Shovel const shovelX = cardStartX + this.cards.length * spacing + 12; const isShovelSelected = this.selectedCard === 'shovel'; ctx.fillStyle = isShovelSelected ? '#ffcdd2' : '#efebe9'; ctx.beginPath(); ctx.roundRect(shovelX, cardY, 54, cardH, 6); ctx.fill(); ctx.strokeStyle = isShovelSelected ? '#d32f2f' : '#8d6e63'; ctx.lineWidth = isShovelSelected ? 3 : 2; ctx.stroke(); this.drawShovelGraphic(ctx, shovelX + 27, cardY + 36); ctx.fillStyle = '#37474f'; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('Лопата', shovelX + 27, cardY + 66); // 4. Coin Bag / Wallet in Top Right ctx.fillStyle = '#ffe082'; ctx.beginPath(); ctx.roundRect(595, 20, 80, 26, 4); ctx.fill(); ctx.strokeStyle = '#ff8f00'; ctx.lineWidth = 1.5; ctx.stroke(); // Coin icon ctx.fillStyle = '#ffd700'; ctx.beginPath(); ctx.arc(608, 33, 7, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#3e2723'; ctx.font = 'bold 12px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(`💰 ${this.totalCoins}`, 645, 38); // 5. Active Suns for (const s of this.suns) { const alpha = Math.min(1, s.life / 1.5); this.drawSunGraphic(ctx, s.x, s.y, s.radius, s.pulse, alpha); } // 6. Active Coins for (const c of this.coins) { this.drawCoinGraphic(ctx, c.x, c.y, c.radius, c.type, c.pulse); } } drawSunGraphic(ctx, x, y, radius, pulseAngle, alpha = 1) { ctx.save(); ctx.globalAlpha = alpha; ctx.translate(x, y); const numRays = 12; ctx.fillStyle = '#fbc02d'; for (let i = 0; i < numRays; i++) { ctx.save(); ctx.rotate(pulseAngle + (i * Math.PI * 2) / numRays); ctx.beginPath(); ctx.moveTo(-radius * 0.25, -radius * 0.8); ctx.lineTo(0, -radius * 1.35); ctx.lineTo(radius * 0.25, -radius * 0.8); ctx.closePath(); ctx.fill(); ctx.restore(); } const grad = ctx.createRadialGradient(0, 0, radius * 0.3, 0, 0, radius); grad.addColorStop(0, '#fffde7'); grad.addColorStop(0.5, '#fff176'); grad.addColorStop(1, '#fbc02d'); ctx.fillStyle = grad; ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } drawCoinGraphic(ctx, x, y, radius, type, pulse) { ctx.save(); ctx.translate(x, y); const spin = Math.sin(pulse * 3); ctx.scale(spin, 1); if (type === 'gold') { ctx.fillStyle = '#ffd700'; ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = '#b78103'; ctx.lineWidth = 2; ctx.stroke(); ctx.fillStyle = '#b78103'; ctx.font = 'bold 12px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('$', 0, 4); } else if (type === 'diamond') { ctx.fillStyle = '#80deea'; ctx.beginPath(); ctx.moveTo(0, -radius); ctx.lineTo(radius, 0); ctx.lineTo(0, radius); ctx.lineTo(-radius, 0); ctx.closePath(); ctx.fill(); } else { // Silver ctx.fillStyle = '#e0e0e0'; ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = '#757575'; ctx.lineWidth = 2; ctx.stroke(); } ctx.restore(); } drawCardThumbnail(ctx, type, x, y) { ctx.save(); ctx.translate(x, y); ctx.scale(0.52, 0.52); if (type === 'sunflower') { ctx.fillStyle = '#fbc02d'; for (let i = 0; i < 8; i++) { ctx.save(); ctx.rotate((i * Math.PI * 2) / 8); ctx.beginPath(); ctx.ellipse(0, -18, 6, 12, 0, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } ctx.fillStyle = '#5d4037'; ctx.beginPath(); ctx.arc(0, 0, 14, 0, Math.PI * 2); ctx.fill(); } else if (type === 'peashooter' || type === 'snowpea' || type === 'repeater') { const col = type === 'snowpea' ? '#29b6f6' : (type === 'repeater' ? '#2e7d32' : '#4caf50'); ctx.fillStyle = col; ctx.beginPath(); ctx.arc(0, 0, 16, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.ellipse(14, 0, 8, 10, 0, 0, Math.PI * 2); ctx.fill(); } else if (type === 'wallnut' || type === 'bowling_nut') { ctx.fillStyle = '#8d6e63'; ctx.beginPath(); ctx.ellipse(0, 0, 16, 22, 0, 0, Math.PI * 2); ctx.fill(); } else if (type === 'cherrybomb' || type === 'bowling_cherry') { ctx.fillStyle = '#d32f2f'; ctx.beginPath(); ctx.arc(-9, 4, 12, 0, Math.PI * 2); ctx.arc(9, 4, 12, 0, Math.PI * 2); ctx.fill(); } else if (type === 'potatomine') { ctx.fillStyle = '#a1887f'; ctx.beginPath(); ctx.ellipse(0, 6, 16, 12, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#f44336'; ctx.beginPath(); ctx.arc(0, -6, 4, 0, Math.PI * 2); ctx.fill(); } else if (type === 'chomper') { ctx.fillStyle = '#7b1fa2'; ctx.beginPath(); ctx.arc(0, 0, 18, 0, Math.PI * 2); ctx.fill(); } else if (type === 'jalapeno') { ctx.fillStyle = '#d50000'; ctx.beginPath(); ctx.ellipse(0, 0, 10, 20, 0, 0, Math.PI * 2); ctx.fill(); } else if (type === 'sunshroom') { ctx.fillStyle = '#fbc02d'; ctx.beginPath(); ctx.arc(0, 0, 14, Math.PI, 0); ctx.fill(); } else if (type === 'fumeshroom') { ctx.fillStyle = '#8e24aa'; ctx.beginPath(); ctx.arc(0, 0, 16, Math.PI, 0); ctx.fill(); } else if (type === 'lilypad') { ctx.fillStyle = '#2e7d32'; ctx.beginPath(); ctx.ellipse(0, 0, 20, 10, 0, 0, Math.PI * 2); ctx.fill(); } else if (type === 'gravebuster') { ctx.strokeStyle = '#33691e'; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc(0, 0, 14, 0, Math.PI * 2); ctx.stroke(); } else if (type === 'flowerpot') { ctx.fillStyle = '#bf360c'; ctx.beginPath(); ctx.moveTo(-14, 4); ctx.lineTo(14, 4); ctx.lineTo(10, 16); ctx.lineTo(-10, 16); ctx.closePath(); ctx.fill(); ctx.fillStyle = '#d84315'; ctx.fillRect(-16, 0, 32, 5); } else if (type === 'cabbagepult') { ctx.fillStyle = '#8d6e63'; ctx.fillRect(-12, 6, 24, 6); ctx.fillStyle = '#81c784'; ctx.beginPath(); ctx.arc(4, -4, 11, 0, Math.PI * 2); ctx.fill(); } else if (type === 'melonpult') { ctx.fillStyle = '#5d4037'; ctx.fillRect(-14, 6, 28, 8); ctx.fillStyle = '#2e7d32'; ctx.beginPath(); ctx.ellipse(4, -4, 14, 11, 0, 0, Math.PI * 2); ctx.fill(); } else if (type && type.startsWith('z_')) { ctx.fillStyle = '#809973'; ctx.beginPath(); ctx.roundRect(-12, -14, 24, 26, [8, 8, 4, 4]); ctx.fill(); ctx.fillStyle = '#fff9c4'; ctx.beginPath(); ctx.arc(-5, -4, 4, 0, Math.PI * 2); ctx.arc(5, -4, 4, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#000'; ctx.beginPath(); ctx.arc(-5, -4, 1.5, 0, Math.PI * 2); ctx.arc(5, -4, 1.5, 0, Math.PI * 2); ctx.fill(); if (type === 'z_conehead') { ctx.fillStyle = '#ff6d00'; ctx.beginPath(); ctx.moveTo(-10, -12); ctx.lineTo(10, -12); ctx.lineTo(0, -30); ctx.closePath(); ctx.fill(); } else if (type === 'z_buckethead') { ctx.fillStyle = '#90a4ae'; ctx.beginPath(); ctx.roundRect(-12, -26, 24, 16, 4); ctx.fill(); } else if (type === 'z_football') { ctx.fillStyle = '#b71c1c'; ctx.beginPath(); ctx.arc(0, -10, 15, Math.PI, 0); ctx.fill(); } } ctx.restore(); } drawShovelGraphic(ctx, x, y) { ctx.save(); ctx.translate(x, y); ctx.rotate(0.35); ctx.strokeStyle = '#8d6e63'; ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(0, -16); ctx.lineTo(0, 8); ctx.stroke(); ctx.fillStyle = '#90a4ae'; ctx.beginPath(); ctx.moveTo(-9, 8); ctx.lineTo(9, 8); ctx.lineTo(6, 20); ctx.lineTo(0, 24); ctx.lineTo(-6, 20); ctx.closePath(); ctx.fill(); ctx.restore(); } };