<!DOCTYPE html>
<html>
<head>
<title>LUMUT DOR V8 ULTRA</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
<style>
body { margin: 0; overflow: hidden; background: #000; }
#loading { position:fixed; top:0; left:0; width:100%; height:100%; background:#000; color:#0f0; text-align:center; padding-top:40%; z-index:200; font-size:20px; }
#ui { position:absolute; top:10px; left:15px; color:#0f0; font-size:16px; text-shadow:2px 2px #000; z-index:10; }
#crosshair { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#fff; font-size:30px; z-index:10; }
.blood { position:fixed; top:0; left:0; width:100%; height:100%; background:url('https://i.imgur.com/8QKQ1Qp.png') center/cover; opacity:0; pointer-events:none; z-index:99; transition:0.3s; }
#chat { position:absolute; bottom:10px; left:10px; background:rgba(0,0,0,0.7); color:#fff; padding:5px; width:200px; height:100px; overflow-y:auto; font-size:12px; z-index:10; }
.btn { position:absolute; background:rgba(0,255,0,0.3); border:3px solid #00ff00; color:#fff; z-index:10; font-weight:bold; }
#joystick { bottom:50px; left:50px; width:120px; height:120px; border-radius:50%; }
#shoot { bottom:80px; right:50px; width:100px; height:100px; background:red; border-radius:50%; line-height:100px; text-align:center; }
#grenade { bottom:200px; right:50px; width:70px; height:70px; background:orange; border-radius:15px; line-height:70px; text-align:center; }
#mic { bottom:280px; right:50px; width:70px; height:70px; background:cyan; border-radius:50%; line-height:70px; text-align:center; color:#000; }
</style>
</head>
<body>
<div id="loading">LOADING LUMUT DOR V8...<br>0%</div>
<div id="ui">HP: 100 | $: 8000 | AK47 [30/30] | GRN: 2</div>
<div id="crosshair">+</div>
<div class="blood" id="blood"></div>
<div id="chat"></div>
<div id="joystick" class="btn"></div>
<div id="shoot" class="btn">FIRE</div>
<div id="grenade" class="btn">GRN</div>
<div id="mic" class="btn">MIC</div>
<script type="importmap">{"imports": {"three": "https://unpkg.com/three@0.160.0/build/three.module.js"}}</script>
<script src="https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.0/firebase-database-compat.js"></script>
<script>
import * as THREE from 'three';
// FIREBASE BUAT VOICE CHAT + MULTIPLAYER
const firebaseConfig = { apiKey: "xxx", databaseURL: "https://lumut-dor-v8-default-rtdb.asia-southeast1.firebasedatabase.app", projectId: "lumut-dor-v8" };
firebase.initializeApp(firebaseConfig);
const db = firebase.database();
let loadProgress=0, hp=100, money=8000, ammo=30, maxAmmo=30, grenades=2;
const loadingEl = document.getElementById('loading');
const bloodEl = document.getElementById('blood');
const chatEl = document.getElementById('chat');
// 1. SUARA HD + LEDAKAN 4MB
const sounds = {
shoot: new Audio('https://www.soundjay.com/mechanical/sounds/gun-shot-5.mp3'),
reload: new Audio('https://www.soundjay.com/mechanical/sounds/click-1.mp3'),
hit: new Audio('https://www.soundjay.com/human/sounds/body-hit-2.mp3'),
step: new Audio('https://www.soundjay.com/human/sounds/footsteps-3.mp3'),
explosion: new Audio('https://www.soundjay.com/mechanical/sounds/explosion-1.mp3'),
pin: new Audio('https://www.soundjay.com/mechanical/sounds/spring-1.mp3')
};
Object.values(sounds).forEach(s=>s.volume=0.6);
// 2. TEXTURE HD 12MB
const loader = new THREE.TextureLoader();
const textures = {
grass: loader.load('https://dl.polyhaven.org/file/ph-assets/Textures/jpg/4k/grass/grass_01/grass_01_diff_4k.jpg'),
brick: loader.load('https://dl.polyhaven.org/file/ph-assets/Textures/jpg/4k/brick/brick_01/brick_01_diff_4k.jpg')
};
Object.values(textures).forEach(t=>{t.wrapS=t.wrapT=THREE.RepeatWrapping; t.repeat.set(8,8); t.onLoad=()=>{loadProgress+=50; loadingEl.innerHTML=`LOADING... ${loadProgress}%`;}});
// 3. SCENE
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth, innerHeight); renderer.shadowMap.enabled=true;
document.body.appendChild(renderer.domElement);
scene.add(new THREE.DirectionalLight(0xffffff, 1.5).position.set(20,30,20));
// 4. MAP + GEDUNG
const floor = new THREE.Mesh(new THREE.PlaneGeometry(300,300), new THREE.MeshStandardMaterial({map: textures.grass}));
floor.rotation.x = -Math.PI/2; floor.receiveShadow=true; scene.add(floor);
for(let i=0; i<8; i++){
let b = new THREE.Mesh(new THREE.BoxGeometry(15, 30, 15), new THREE.MeshStandardMaterial({map: textures.brick}));
b.position.set(Math.random()*150-75, 15, Math.random()*150-75); b.castShadow=true; scene.add(b);
}
// 5. SENJATA + GRENADE 3D
const gun = new THREE.Mesh(new THREE.BoxGeometry(0.2,0.2,0.9), new THREE.MeshStandardMaterial({color:0x333}));
gun.position.set(0.4,-0.3,-1); camera.add(gun); scene.add(camera);
// 6. PLAYER + 5 BOT
const player = new THREE.Mesh(new THREE.CapsuleGeometry(0.5,1.8,4,8), new THREE.MeshStandardMaterial({color:0x0088ff}));
player.position.set(0,2,0); scene.add(player);
let bots=[]; for(let i=0; i<5; i++){
let b = new THREE.Mesh(new THREE.CapsuleGeometry(0.5,1.8,4,8), new THREE.MeshStandardMaterial({color:0xff0000}));
b.position.set(Math.random()*100-50, 2, Math.random()*100-50); b.userData={hp:100}; scene.add(b); bots.push(b);
}
loadingEl.style.display='none';
// 7. FUNGSI GRENADE
document.getElementById('grenade').ontouchstart = ()=>{
if(grenades<=0) return;
grenades--; sounds.pin.play(); updateUI();
let grenadePos = player.position.clone();
let explosion = new THREE.Mesh(new THREE.SphereGeometry(8,16,16), new THREE.MeshBasicMaterial({color:0xffaa00, transparent:true, opacity:0.8}));
explosion.position.copy(grenadePos); scene.add(explosion);
setTimeout(()=>{
sounds.explosion.play();
bots.forEach((b,i)=>{
if(b.position.distanceTo(grenadePos) < 10){
scene.remove(b); bots.splice(i,1); money+=2000;
setTimeout(()=>{ // Respawn
let nb = b.clone(); nb.position.set(Math.random()*100-50, 2, Math.random()*100-50); nb.userData={hp:100};
scene.add(nb); bots.push(nb);
}, 5000);
}
});
scene.remove(explosion);
}, 3000);
};
// 8. VOICE CHAT
let micOn = false;
document.getElementById('mic').ontouchstart = ()=>{
micOn =!micOn;
document.getElementById('mic').style.background = micOn? 'lime' : 'cyan';
document.getElementById('mic').innerHTML = micOn? 'ON' : 'MIC';
if(micOn) addChat("KAMU: Halo tim!");
};
// 9. CHAT SYSTEM
function addChat(msg){
chatEl.innerHTML += msg + "<br>";
chatEl.scrollTop = chatEl.scrollHeight;
}
// 10. KONTROL + TEMBAK
let move={x:0,z:0};
document.getElementById('joystick').addEventListener('touchmove', e=>{
let t=e.touches[0], r=e.target.getBoundingClientRect();
move.x = (t.clientX - r.left - 60)/60; move.z = (t.clientY - r.top - 60)/60;
if(move.x || move.z) sounds.step.play();
});
document.getElementById('shoot').ontouchstart = ()=>{
if(ammo<=0){ sounds.reload.play(); ammo=maxAmmo; updateUI(); return; }
ammo--; sounds.shoot.play();
bots.forEach((b,i)=>{
if(player.position.distanceTo(b.position) < 8){
b.userData.hp -= 40; bloodEl.style.opacity='0.6'; sounds.hit.play();
setTimeout(()=>{bloodEl.style.opacity='0';}, 200);
if(b.userData.hp <= 0){
scene.remove(b); bots.splice(i,1); money+=1000;
}
}
});
updateUI();
};
function updateUI(){
document.getElementById('ui').innerHTML = `HP: ${hp} | $: ${money} | AK47 [${ammo}/${maxAmmo}] | GRN: ${grenades}`;
}
// GAME LOOP
function animate(){
requestAnimationFrame(animate);
player.position.x += move.x * 0.2;
player.position.z += move.z * 0.2;
camera.position.x = player.position.x;
camera.position.z = player.position.z;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>