/** * PPE SAFETY CHALLENGE - REALISTIC 3D WORKER AVATAR SYSTEM * Uses the exact 3D realistic character image provided by the user (images/worker_base.png), * with precision anatomical PPE overlays for both Grinding and Chemical scenarios. */ class WorkerAvatar { constructor(containerId) { this.container = document.getElementById(containerId); this.equippedItems = new Set(); this.render(); } setEquipped(itemIds) { this.equippedItems = new Set(itemIds); this.updateLayers(); } equip(itemId) { this.equippedItems.add(itemId); this.updateLayers(itemId); } unequip(itemId) { this.equippedItems.delete(itemId); this.updateLayers(); } has(itemId) { return this.equippedItems.has(itemId); } getAvatarCenterCoordinates() { if (!this.container) return { x: 170, y: 220, eyeX: 170, eyeY: 110, handX: 230, handY: 260 }; const rect = this.container.getBoundingClientRect(); const parentRect = this.container.parentElement.getBoundingClientRect(); const relX = rect.left - parentRect.left + (rect.width * 0.5); const relY = rect.top - parentRect.top + (rect.height * 0.5); return { x: relX, y: relY, eyeX: relX, eyeY: relY - 135, handX: relX + 65, handY: relY + 25 }; } render() { if (!this.container) return; this.container.innerHTML = ` `; this.updateLayers(); } updateLayers(newlyEquippedId = null) { if (!this.container) return; const allGearIds = [ 'safety_helmet_chem', 'safety_helmet_grind', 'chem_splash_goggles', 'safety_goggles_grind', 'face_shield_chem', 'face_shield_grind', 'tinted_sunglasses', 'dust_mask_grind', 'hearing_protection_chem', 'hearing_protection_grind', 'chem_resistant_gloves', 'standard_work_gloves', 'work_gloves_grind', 'leather_grinding_gloves', 'disposable_latex_gloves', 'chem_resistant_apron', 'cotton_coat_chem', 'flame_resistant_jacket', 'reflective_vest_grind', 'fire_resistant_apron_grind', 'fire_resistant_apron', 'chem_safety_shoes', 'steel_toe_boots_grind', 'running_sneakers' ]; allGearIds.forEach(gearId => { const el = document.getElementById(`layer-gear-${gearId}`); if (el) { const isEquipped = this.equippedItems.has(gearId); el.style.display = isEquipped ? 'block' : 'none'; if (isEquipped && gearId === newlyEquippedId) { el.classList.remove('gear-pop-glow'); void el.offsetWidth; el.classList.add('gear-pop-glow'); } } }); } }