Update game UI, add 3D gear assets, backgrounds, icons, and audio enhancements

This commit is contained in:
Vishva
2026-09-26 15:38:52 +05:30
parent d68131d500
commit db6840b870
86 changed files with 497 additions and 570 deletions
+149 -91
View File
@@ -1,7 +1,7 @@
/**
* PPE SAFETY CHALLENGE - DYNAMIC 2D WORKER AVATAR SYSTEM
* Uses the step-by-step transparent character images from ppe_character_steps_transparent_png!
* Dynamically switches character states as safety gear is equipped.
* 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 {
@@ -18,7 +18,7 @@ class WorkerAvatar {
equip(itemId) {
this.equippedItems.add(itemId);
this.updateLayers();
this.updateLayers(itemId);
}
unequip(itemId) {
@@ -40,107 +40,165 @@ class WorkerAvatar {
x: relX,
y: relY,
eyeX: relX,
eyeY: relY - 130,
handX: relX + 55,
handY: relY + 30
eyeY: relY - 135,
handX: relX + 65,
handY: relY + 25
};
}
getStepImagePath() {
const hasHelmet = this.equippedItems.has('safety_helmet_grind') || this.equippedItems.has('safety_helmet_chem');
const hasGoggles = this.equippedItems.has('chem_splash_goggles') || this.equippedItems.has('safety_goggles_grind');
const hasFaceShield = this.equippedItems.has('face_shield_grind') || this.equippedItems.has('face_shield_chem');
const hasHearing = this.equippedItems.has('hearing_protection_grind') || this.equippedItems.has('hearing_protection_chem');
const hasLeatherGloves = this.equippedItems.has('leather_grinding_gloves');
const hasWorkGloves = this.equippedItems.has('work_gloves_grind') || this.equippedItems.has('standard_work_gloves');
const hasChemGloves = this.equippedItems.has('chem_resistant_gloves');
const hasVest = this.equippedItems.has('reflective_vest_grind');
const hasApron = this.equippedItems.has('chem_resistant_apron');
const hasCottonCoat = this.equippedItems.has('cotton_coat_chem');
const hasBoots = this.equippedItems.has('steel_toe_boots_grind') || this.equippedItems.has('chem_safety_shoes');
const hasMask = this.equippedItems.has('dust_mask_grind');
// 10. Full PPE with Mask
if (hasMask) {
return 'images/steps/10_full_ppe_with_mask.png';
}
// 9. Full Grinding Set with Boots
if (hasHelmet && (hasGoggles || hasFaceShield) && hasHearing && (hasLeatherGloves || hasChemGloves) && (hasVest || hasApron || hasBoots)) {
return 'images/steps/09_helmet_goggles_hearing_leather_gloves_vest_boots.png';
}
// 8. With Vest / Body Wear
if (hasHelmet && (hasGoggles || hasFaceShield) && hasHearing && (hasLeatherGloves || hasChemGloves) && (hasVest || hasApron || hasCottonCoat)) {
return 'images/steps/08_helmet_goggles_hearing_leather_gloves_vest.png';
}
// 7. With Leather / Chem Gloves
if (hasHelmet && (hasGoggles || hasFaceShield) && hasHearing && (hasLeatherGloves || hasChemGloves)) {
return 'images/steps/07_helmet_goggles_hearing_leather_gloves.png';
}
// 6. With Work Gloves
if (hasHelmet && (hasGoggles || hasFaceShield) && hasHearing && hasWorkGloves) {
return 'images/steps/06_helmet_goggles_hearing_work_gloves.png';
}
// 5. With Earmuffs / Hearing Protection
if (hasHelmet && (hasGoggles || hasFaceShield) && hasHearing) {
return 'images/steps/05_helmet_goggles_hearing.png';
}
// 4. With Face Shield
if (hasFaceShield || (hasHelmet && hasFaceShield)) {
return 'images/steps/04_helmet_goggles_face_shield.png';
}
// 3. With Goggles & Helmet
if (hasHelmet && hasGoggles) {
return 'images/steps/03_helmet_goggles.png';
}
// 2. Helmet Only
if (hasHelmet) {
return 'images/steps/02_helmet.png';
}
// Individual items
if (hasFaceShield) return 'images/steps/04_helmet_goggles_face_shield.png';
if (hasGoggles) return 'images/steps/03_helmet_goggles.png';
if (hasHearing) return 'images/steps/05_helmet_goggles_hearing.png';
if (hasLeatherGloves) return 'images/steps/07_helmet_goggles_hearing_leather_gloves.png';
if (hasWorkGloves) return 'images/steps/06_helmet_goggles_hearing_work_gloves.png';
// 1. Base Worker (No PPE)
return 'images/steps/01_no_ppe.png';
}
render() {
if (!this.container) return;
this.container.innerHTML = `
<div class="avatar-step-container" id="avatar-step-container">
<!-- Floor Contact Shadow -->
<div class="avatar-floor-shadow"></div>
<!-- Dynamic Character Step Image -->
<img src="images/steps/01_no_ppe.png" alt="Worker Character" class="avatar-step-img" id="avatar-step-img" />
</div>
<svg viewBox="0 0 682 1024" class="worker-svg" id="worker-avatar-svg" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="gearShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="4" stdDeviation="5" flood-color="#000000" flood-opacity="0.6"/>
</filter>
<radialGradient id="softFloorShadowGrad" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#000000" stop-opacity="0.65"/>
<stop offset="35%" stop-color="#000000" stop-opacity="0.4"/>
<stop offset="65%" stop-color="#000000" stop-opacity="0.18"/>
<stop offset="85%" stop-color="#000000" stop-opacity="0.05"/>
<stop offset="100%" stop-color="#000000" stop-opacity="0"/>
</radialGradient>
<radialGradient id="footContactShadowGrad" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#000000" stop-opacity="0.75"/>
<stop offset="40%" stop-color="#000000" stop-opacity="0.45"/>
<stop offset="75%" stop-color="#000000" stop-opacity="0.12"/>
<stop offset="100%" stop-color="#000000" stop-opacity="0"/>
</radialGradient>
<filter id="softFloorBlur" x="-30%" y="-30%" width="160%" height="160%">
<feGaussianBlur stdDeviation="5"/>
</filter>
</defs>
<!-- Realistic Soft Floor Contact & Ambient Occlusion Shadow -->
<g id="layer-floor-shadow" filter="url(#softFloorBlur)">
<!-- Broad Ambient Floor Shadow -->
<ellipse cx="347" cy="1008" rx="205" ry="22" fill="url(#softFloorShadowGrad)"/>
<!-- Left Foot Direct Contact Shadow -->
<ellipse cx="238" cy="1008" rx="72" ry="14" fill="url(#footContactShadowGrad)"/>
<!-- Right Foot Direct Contact Shadow -->
<ellipse cx="452" cy="1008" rx="72" ry="14" fill="url(#footContactShadowGrad)"/>
</g>
<!-- ====================================================
LAYER 1: REALISTIC 3D WORKER BASE CHARACTER IMAGE
==================================================== -->
<g id="layer-base-character">
<image href="images/worker_base.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- ====================================================
LAYER 2: MODULAR PPE EQUIPMENT (TOGGLED DYNAMICALLY)
==================================================== -->
<!-- 1. FEET: Safety Shoes (Steel-Toe Boots covering bare feet) -->
<g id="layer-gear-steel_toe_boots_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_safety_boots.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-chem_safety_shoes" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_safety_boots.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 2. HANDS: Leather Grinding / Heavy Work Gloves & Chemical Gloves -->
<g id="layer-gear-leather_grinding_gloves" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_leather_gloves.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-work_gloves_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_work_gloves.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-standard_work_gloves" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_work_gloves.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-chem_resistant_gloves" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_chem_gloves.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 3. BODY: Lab Coat, Aprons, Reflective Vest (Overlaps glove cuffs) -->
<g id="layer-gear-cotton_coat_chem" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_cotton_coat.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-chem_resistant_apron" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_chem_apron.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-fire_resistant_apron_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_fire_resistant_apron.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-fire_resistant_apron" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_fire_resistant_apron.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-reflective_vest_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_reflective_vest.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 4. MASK: Dust Mask (Grinding Distractor) -->
<g id="layer-gear-dust_mask_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_dust_mask.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 5. EYES: Safety Goggles (Clear Grinding Protective Glasses) -->
<g id="layer-gear-safety_goggles_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_safety_glasses.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-chem_splash_goggles" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_chem_splash_goggles.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 6. HEARING: Acoustic Earmuffs (Grinding & Chemical) -->
<g id="layer-gear-hearing_protection_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_earmuffs.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-hearing_protection_chem" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_earmuffs.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 7. HEAD: Safety Helmet (Yellow Hard Hat) -->
<g id="layer-gear-safety_helmet_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_safety_helmet.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-safety_helmet_chem" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_safety_helmet.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<!-- 8. FACE: Face Shield (Grinding & Chemical Visor) -->
<g id="layer-gear-face_shield_grind" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_face_shield.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
<g id="layer-gear-face_shield_chem" style="display: none;" filter="url(#gearShadow)">
<image href="images/gear/gear_3d_face_shield.png" x="0" y="0" width="682" height="1024" preserveAspectRatio="xMidYMid meet" />
</g>
</svg>
`;
this.updateLayers();
}
updateLayers() {
updateLayers(newlyEquippedId = null) {
if (!this.container) return;
const imgEl = document.getElementById('avatar-step-img');
if (imgEl) {
const targetSrc = this.getStepImagePath();
if (imgEl.getAttribute('src') !== targetSrc) {
imgEl.src = targetSrc;
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');
}
}
}
});
}
}