Meta Description" name="description" />
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>TWOM Complex - Zenrin</title>
<style>
body { margin:0; padding:0; background:#000; font-family:Arial; overflow:hidden; }
canvas { display:block; margin:0 auto; background:#0a3d0a; }
#ui {
position: absolute; bottom: 0; left: 0; width: 100%;
background: rgba(0,0,0,0.75); color: white; padding: 8px; font-size: 13px;
}
.btn {
background:#222; color:white; border:none; padding:10px 12px;
margin:2px; border-radius:6px; font-size:15px;
}
#log { height:90px; overflow-y:scroll; background:rgba(0,0,0,0.6); padding:5px; margin:5px 0; }
</style>
</head>
<body>
<canvas id="game" width="850" height="520"></canvas>
<div id="ui">
<div><strong>Zenrin</strong> | Lv.<span id="level">1</span> | EXP <span id="exp">0</span>/100 |
HP <span id="hp">320</span>/320 | MP <span id="mp">150</span>/150 | Gold <span id="gold">120</span></div>
<button class="btn" onclick="useSkill(1)">βοΈ Slash</button>
<button class="btn" onclick="useSkill(2)">π₯ Power Strike</button>
<button class="btn" onclick="useSkill(3)">π‘οΈ Taunt</button>
<button class="btn" onclick="useSkill(4)">π₯ Fire Slash</button>
<button class="btn" onclick="showInventory()">π Inventory</button>
<div id="log"></div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
let player = {
x: 400, y: 250,
hp: 320, maxHp: 320,
mp: 150, maxMp: 150,
level: 1, exp: 0, expToNext: 100,
atk: 38, gold: 120
};
let monsters = [
{x:200,y:150,hp:140,maxHp:140,name:"Green Slime",color:"#00ff88",exp:25,alive:true},
{x:650,y:180,hp:180,maxHp:180,name:"Goblin Warrior",color:"#ff5500",exp:35,alive:true},
{x:350,y:380,hp:110,maxHp:110,name:"Forest Wolf",color:"#888888",exp:20,alive:true},
{x:550,y:320,hp:220,maxHp:220,name:"Orc",color:"#aa5500",exp:45,alive:true}
];
let inventory = ["Potion HP x3", "Wooden Sword"];
let quest = { name: "Bunuh 5 Monster", progress: 0, goal: 5, reward: 80 };
let logMessages = [];
let damageTexts = [];
function addLog(msg) {
logMessages.push(msg);
if (logMessages.length > 6) logMessages.shift();
document.getElementById('log').innerHTML = logMessages.join('<br>');
}
function addDamage(x, y, dmg) {
damageTexts.push({x, y, dmg, life: 40});
}
let keys = {};
window.addEventListener('keydown', e => keys[e.key.toLowerCase()] = true);
window.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);
// Touch support
let touchX = 0, touchY = 0;
canvas.addEventListener('touchmove', e => {
let dx = (e.touches[0].clientX - touchX) * 0.08;
let dy = (e.touches[0].clientY - touchY) * 0.08;
player.x += dx; player.y += dy;
touchX = e.touches[0].clientX;
touchY = e.touches[0].clientY;
});
function useSkill(skill) {
if (player.mp < 25) { addLog("β MP tidak cukup!"); return; }
player.mp -= 25;
const range = skill === 2 ? 200 : 160;
monsters.forEach(m => {
if (m.alive && Math.hypot(m.x - player.x, m.y - player.y) < range) {
let dmg = player.atk;
if (skill === 2) dmg = Math.floor(player.atk * 2.2);
if (skill === 4) dmg = Math.floor(player.atk * 1.6);
m.hp -= dmg;
addDamage(m.x, m.y-30, dmg);
if (m.hp <= 0 && m.alive) {
m.alive = false;
player.exp += m.exp;
player.gold += Math.floor(Math.random()*15 + 10);
quest.progress++;
addLog(`β
\( {m.name} mati! + \){m.exp} EXP`);
}
}
});
if (skill === 3) addLog("π‘οΈ Taunt digunakan!");
if (skill === 4) addLog("π₯ Fire Slash!");
}
function showInventory() {
let text = "π Inventory:\n";
inventory.forEach(item => text += "β’ " + item + "\n");
text += "\nQuest: " + quest.name + " (" + quest.progress + "/" + quest.goal + ")";
alert(text);
}
function update() {
// Movement
if (keys['w']) player.y -= 5;
if (keys['s']) player.y += 5;
if (keys['a']) player.x -= 5;
if (keys['d']) player.x += 5;
player.x = Math.max(40, Math.min(810, player.x));
player.y = Math.max(40, Math.min(480, player.y));
// Monster AI
monsters.forEach(m => {
if (m.alive) {
let dist = Math.hypot(m.x - player.x, m.y - player.y);
if (dist < 55) player.hp -= 1.8;
if (dist > 45) {
m.x += (player.x - m.x) * 0.025;
m.y += (player.y - m.y) * 0.025;
}
}
});
// Level Up
if (player.exp >= player.expToNext) {
player.level++;
player.exp = 0;
player.expToNext = Math.floor(player.expToNext * 1.6);
player.maxHp += 45;
player.hp = player.maxHp;
player.atk += 6;
addLog(`π LEVEL UP! Sekarang Level ${player.level}`);
}
// Regen
if (player.hp < player.maxHp) player.hp += 0.4;
if (player.mp < player.maxMp) player.mp += 0.6;
// Update damage texts
damageTexts = damageTexts.filter(d => {
d.life--;
d.y -= 0.8;
return d.life > 0;
});
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#0a3d0a";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw Monsters
monsters.forEach(m => {
if (m.alive) {
ctx.fillStyle = m.color;
ctx.beginPath();
ctx.arc(m.x, m.y, 28, 0, Math.PI*2);
ctx.fill();
// HP Bar
let hpPercent = m.hp / m.maxHp;
ctx.fillStyle = "red";
ctx.fillRect(m.x-28, m.y-45, 56, 7);
ctx.fillStyle = "lime";
ctx.fillRect(m.x-28, m.y-45, 56 * hpPercent, 7);
}
});
// Draw Player
ctx.fillStyle = "#00aaff";
ctx.fillRect(player.x-22, player.y-35, 44, 55);
ctx.fillStyle = "#ffdd88";
ctx.fillRect(player.x-15, player.y-48, 30, 22);
// Damage Numbers
ctx.fillStyle = "yellow";
ctx.font = "bold 18px Arial";
damageTexts.forEach(d => {
ctx.globalAlpha = d.life / 40;
ctx.fillText("-" + d.dmg, d.x, d.y);
});
ctx.globalAlpha = 1;
// Update UI
document.getElementById('level').textContent = player.level;
document.getElementById('exp').textContent = player.exp;
document.getElementById('hp').textContent = Math.floor(player.hp);
document.getElementById('mp').textContent = Math.floor(player.mp);
document.getElementById('gold').textContent = player.gold;
}
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
addLog("π Selamat datang di TWOM Complex!");
addLog("WASD / Geser layar = Gerak");
addLog("Bunuh monster untuk quest!");
gameLoop();
</script>
</body>
</html>1
1
9KB
9KB
128.0ms
200.0ms
128.0ms