Stickman Kombat - MK Style
by SonicBear352342 lines82.2 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<title>Stickman Kombat - MK Style</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
body {
background: #0a0a0a;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
color: white;
overflow: hidden;
touch-action: none;
position: fixed;
width: 100%;
height: 100%;
}
#app {
width: 100%;
max-width: 420px;
height: 100vh;
max-height: 780px;
background: linear-gradient(145deg, #0f0f0f, #1a0a0a);
border-radius: 0px;
padding: 4px;
box-shadow: 0 20px 60px rgba(0,0,0,0.9);
position: relative;
overflow: hidden;
border: 2px solid #3a1a1a;
display: flex;
flex-direction: column;
touch-action: none;
}
@media (orientation: landscape) {
#app {
max-width: 100%;
max-height: 100vh;
height: 100vh;
border-radius: 0;
flex-direction: row;
padding: 4px;
}
.fight-container {
flex-direction: row !important;
flex-wrap: wrap !important;
}
#fightCanvas {
height: 100% !important;
width: 55% !important;
flex: 1 !important;
}
.fight-controls {
flex-direction: column !important;
width: 40% !important;
height: 100% !important;
position: relative !important;
bottom: auto !important;
left: auto !important;
right: auto !important;
padding: 6px !important;
display: flex !important;
justify-content: center !important;
gap: 4px !important;
flex-wrap: wrap !important;
}
.fight-controls .btn-row {
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
gap: 4px !important;
}
.fight-controls button {
min-width: 44px !important;
min-height: 36px !important;
font-size: 8px !important;
}
#joystickAreaP1, #joystickAreaP2 {
width: 80px !important;
height: 80px !important;
}
#joystickKnobP1, #joystickKnobP2 {
width: 32px !important;
height: 32px !important;
}
.move-list {
max-height: 80px !important;
font-size: 6px !important;
min-width: 60px !important;
}
}
@media (min-width: 421px) and (orientation: portrait) {
#app {
border-radius: 40px;
height: 780px;
}
}
#loadingScreen {
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at 50% 30%, #1a0a0a, #0a0a0a);
z-index: 100;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 0px;
animation: fadeIn 0.5s ease;
}
#loadingScreen .logo {
font-size: 60px;
animation: bounce 1s ease infinite;
}
#loadingScreen .title {
font-size: 32px;
font-weight: 900;
color: #ff4444;
text-shadow: 0 0 30px #ff0000, 0 0 60px #880000;
margin-top: 5px;
letter-spacing: 4px;
}
#loadingScreen .sub {
font-size: 14px;
color: #88dd88;
margin-top: 5px;
}
#loadingScreen .tap-text {
font-size: 12px;
color: #557755;
margin-top: 15px;
animation: pulse 1.5s ease infinite;
}
#loadingScreen .load-bar {
width: 200px;
height: 4px;
background: #1a1a1a;
border-radius: 4px;
margin-top: 10px;
overflow: hidden;
border: 1px solid #3a1a1a;
}
#loadingScreen .load-fill {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #ff4444, #ff8800);
border-radius: 4px;
transition: width 0.3s;
}
#loadingScreen .load-percent {
font-size: 12px;
color: #ff4444;
margin-top: 4px;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes bounce {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-15px) scale(1.05); }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.screen {
display: none;
flex-direction: column;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
padding: 5px;
background: linear-gradient(145deg, #0f0f0f, #1a0a0a);
overflow-y: auto;
}
.screen.active {
display: flex;
}
#homeScreen {
justify-content: center;
align-items: center;
gap: 3px;
background: radial-gradient(circle at 50% 30%, #1a0a0a, #0a0a0a);
}
#homeScreen .logo {
font-size: 32px;
font-weight: 900;
color: #ff4444;
text-shadow: 0 0 30px #ff0000, 0 0 60px #880000;
letter-spacing: 3px;
}
#homeScreen .sub {
font-size: 10px;
color: #88dd88;
letter-spacing: 4px;
margin-bottom: 8px;
}
.menu-btn {
background: linear-gradient(145deg, #2a1a1a, #1a0a0a);
border: 2px solid #4a2a2a;
color: white;
padding: 6px 16px;
border-radius: 60px;
font-size: 12px;
font-weight: bold;
width: 85%;
text-align: center;
margin: 2px 0;
cursor: pointer;
transition: 0.15s;
box-shadow: 0 2px 0 #0a0a0a;
letter-spacing: 1px;
touch-action: manipulation;
}
.menu-btn:active {
transform: translateY(2px);
box-shadow: none;
}
.menu-btn.red {
border-color: #ff4444;
background: linear-gradient(145deg, #3a1a1a, #1a0a0a);
}
.menu-btn.gold {
border-color: #ffdd44;
background: linear-gradient(145deg, #3a3a1a, #1a1a0a);
}
.menu-btn.blue {
border-color: #4444ff;
background: linear-gradient(145deg, #1a1a3a, #0a0a1a);
}
.small-btn {
padding: 2px 6px;
font-size: 7px;
width: auto;
}
.back-btn {
background: #2a1a1a;
border: none;
color: white;
padding: 2px 6px;
border-radius: 30px;
cursor: pointer;
font-size: 10px;
touch-action: manipulation;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3px;
background: #1a1a1a;
padding: 2px 5px;
border-radius: 30px;
border: 1px solid #3a1a1a;
}
.character-grid {
display: flex;
flex-wrap: wrap;
gap: 3px;
justify-content: center;
margin: 3px 0;
}
.character-card {
background: #1a1a1a;
border: 2px solid #2a2a2a;
border-radius: 8px;
padding: 4px 3px;
width: 56px;
text-align: center;
font-size: 6px;
cursor: pointer;
transition: 0.15s;
touch-action: manipulation;
}
.character-card:active {
transform: scale(0.95);
}
.character-card .char-icon {
font-size: 22px;
display: block;
}
.character-card .char-name {
font-size: 5px;
margin-top: 1px;
color: #ccddcc;
}
.character-card .char-stats {
font-size: 4px;
color: #88dd88;
}
.character-card.selected {
border-color: #ff4444;
background: #2a1a1a;
}
.character-card.boss {
border-color: #ffdd44;
background: #1a1a0a;
}
#fightScreen {
padding: 0;
background: #0a0a0a;
position: relative;
}
.fight-container {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
#fightCanvas {
width: 100%;
height: 100%;
background: #1a1a2a;
border-radius: 10px;
display: block;
touch-action: none;
cursor: pointer;
flex: 1;
}
.joystick-area {
position: absolute;
border-radius: 50%;
background: rgba(255,255,255,0.06);
border: 2px solid rgba(255,255,255,0.15);
touch-action: none;
z-index: 15;
display: block;
box-shadow: 0 0 30px rgba(0,0,0,0.4);
}
.joystick-area .joystick-knob {
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
pointer-events: none;
touch-action: none;
box-shadow: 0 0 20px rgba(255, 200, 0, 0.3);
transition: none;
}
#joystickAreaP1 {
bottom: 70px;
left: 8px;
width: 80px;
height: 80px;
}
#joystickAreaP1 .joystick-knob {
width: 30px;
height: 30px;
background: radial-gradient(circle, rgba(255, 220, 50, 0.9), rgba(255, 200, 0, 0.4));
border: 3px solid #ffdd44;
transform: translate(-50%, -50%);
}
#joystickAreaP2 {
bottom: 70px;
right: 8px;
width: 80px;
height: 80px;
}
#joystickAreaP2 .joystick-knob {
width: 30px;
height: 30px;
background: radial-gradient(circle, rgba(68, 200, 255, 0.9), rgba(68, 150, 255, 0.4));
border: 3px solid #44aaff;
transform: translate(-50%, -50%);
}
.fight-controls {
position: absolute;
bottom: 2px;
left: 0;
right: 0;
padding: 0 2px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 20;
flex-wrap: wrap;
}
.fight-controls .btn-row {
display: flex;
gap: 2px;
flex-wrap: wrap;
pointer-events: none;
}
.fight-controls button {
pointer-events: auto;
background: rgba(0,0,0,0.85);
border: 2px solid #4a2a2a;
color: white;
border-radius: 30px;
padding: 2px 6px;
font-size: 7px;
font-weight: bold;
backdrop-filter: blur(4px);
cursor: pointer;
touch-action: manipulation;
min-width: 28px;
min-height: 28px;
}
.fight-controls button:active {
transform: scale(0.9);
}
.fight-controls .attack-btn {
border-color: #ff4444;
background: rgba(255, 50, 50, 0.2);
}
.fight-controls .attack-btn:active {
background: rgba(255, 50, 50, 0.5);
}
.fight-controls .special-btn {
border-color: #ffdd44;
background: rgba(255, 200, 50, 0.2);
}
.fight-controls .special-btn:active {
background: rgba(255, 200, 50, 0.5);
}
.fight-controls .block-btn {
border-color: #44ff88;
background: rgba(68, 255, 136, 0.15);
}
.fight-controls .block-btn:active {
background: rgba(68, 255, 136, 0.4);
}
.fight-controls .p2-btn {
border-color: #44aaff;
background: rgba(68, 150, 255, 0.15);
}
.fight-controls .p2-btn:active {
background: rgba(68, 150, 255, 0.4);
}
.move-list {
position: absolute;
top: 5px;
right: 5px;
background: rgba(0,0,0,0.85);
border: 1px solid #4a2a2a;
border-radius: 8px;
padding: 4px 6px;
font-size: 6px;
color: #88dd88;
max-height: 70px;
overflow-y: auto;
z-index: 10;
min-width: 70px;
}
.move-list .move-title {
color: #ffdd44;
font-weight: bold;
font-size: 7px;
border-bottom: 1px solid #3a3a3a;
padding-bottom: 2px;
margin-bottom: 2px;
}
.move-list .move-item {
padding: 1px 0;
display: flex;
justify-content: space-between;
gap: 4px;
font-size: 6px;
}
.move-list .move-key {
color: #ff4444;
font-weight: bold;
}
.move-list .move-name {
color: #cccccc;
}
#winnerOverlay {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.85);
z-index: 30;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 10px;
animation: fadeIn 0.5s ease;
}
#winnerOverlay .winner-text {
font-size: 28px;
font-weight: bold;
color: #ffdd44;
text-shadow: 0 0 30px #ff8800;
text-align: center;
}
#winnerOverlay .winner-sub {
font-size: 14px;
color: #88dd88;
margin-top: 5px;
text-align: center;
}
#winnerOverlay .winner-quote {
font-size: 12px;
color: #ff4444;
margin-top: 3px;
font-style: italic;
text-align: center;
}
.tournament-bracket {
background: #1a1a1a;
border-radius: 8px;
padding: 6px;
margin: 3px 0;
border: 1px solid #3a1a1a;
}
.tournament-bracket .round {
display: flex;
justify-content: space-between;
padding: 2px 0;
border-bottom: 1px solid #2a2a2a;
font-size: 7px;
}
.tournament-bracket .round .winner {
color: #ffdd44;
}
.game-mode-select {
display: flex;
gap: 4px;
margin: 4px 0;
flex-wrap: wrap;
justify-content: center;
}
.game-mode-select .mode-btn {
padding: 4px 12px;
border-radius: 30px;
font-size: 9px;
font-weight: bold;
cursor: pointer;
border: 2px solid #4a2a2a;
background: #1a1a1a;
color: white;
touch-action: manipulation;
}
.game-mode-select .mode-btn.active {
border-color: #ffdd44;
background: #2a2a1a;
}
@media (max-width: 420px) {
#app {
border-radius: 0;
height: 100vh;
max-height: 100vh;
padding: 2px;
}
.menu-btn {
padding: 4px 10px;
font-size: 10px;
}
.fight-controls button {
padding: 1px 4px;
font-size: 6px;
min-width: 22px;
min-height: 22px;
}
.character-card {
width: 46px;
}
.character-card .char-icon {
font-size: 18px;
}
.move-list {
font-size: 5px;
max-height: 50px;
min-width: 55px;
padding: 3px 4px;
}
#loadingScreen .logo {
font-size: 40px;
}
#loadingScreen .title {
font-size: 24px;
}
#winnerOverlay .winner-text {
font-size: 22px;
}
#joystickAreaP1, #joystickAreaP2 {
width: 60px !important;
height: 60px !important;
}
#joystickAreaP1 .joystick-knob, #joystickAreaP2 .joystick-knob {
width: 24px !important;
height: 24px !important;
}
#joystickAreaP1 {
bottom: 55px !important;
left: 4px !important;
}
#joystickAreaP2 {
bottom: 55px !important;
right: 4px !important;
}
}
@media (max-height: 600px) {
.move-list {
max-height: 40px;
font-size: 5px;
min-width: 50px;
}
.fight-controls button {
min-width: 20px;
min-height: 20px;
font-size: 5px;
padding: 1px 3px;
}
#joystickAreaP1, #joystickAreaP2 {
width: 50px !important;
height: 50px !important;
}
#joystickAreaP1 .joystick-knob, #joystickAreaP2 .joystick-knob {
width: 20px !important;
height: 20px !important;
}
#joystickAreaP1 {
bottom: 45px !important;
}
#joystickAreaP2 {
bottom: 45px !important;
}
}
</style>
</head>
<body>
<div id="app">
<!-- LOADING SCREEN -->
<div id="loadingScreen">
<div class="logo">⚔️</div>
<div class="title">STICKMAN KOMBAT</div>
<div class="sub">Mortal Kombat Style</div>
<div class="load-bar">
<div class="load-fill" id="loadFill"></div>
</div>
<div class="load-percent" id="loadPercent">0%</div>
<div class="tap-text">👆 TAP TO START</div>
</div>
<!-- HOME SCREEN -->
<div id="homeScreen" class="screen">
<div class="logo">⚔️ STICKMAN KOMBAT</div>
<div class="sub">MORTAL KOMBAT STYLE</div>
<div style="display:flex; gap:2px; margin-bottom:4px; flex-wrap:wrap; justify-content:center;">
<span class="coin-display" style="border-color:#ff4444;">⚔️ FIGHT!</span>
</div>
<button class="menu-btn red" onclick="showScreen('characterSelectScreen')">▶ SELECT FIGHTERS</button>
<button class="menu-btn gold" onclick="startTournament()">🏆 TOURNAMENT</button>
<button class="menu-btn" onclick="startRandomFight()">⚡ RANDOM FIGHT</button>
<button class="menu-btn" onclick="showScreen('trainingScreen')">🥋 TRAINING</button>
<button class="menu-btn small-btn" onclick="showScreen('settingsScreen')">⚙️ SETTINGS</button>
<div style="margin-top:6px; font-size:6px; color:#557755;">"FINISH HIM!"</div>
</div>
<!-- CHARACTER SELECT -->
<div id="characterSelectScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">←</button>
<span style="font-size:10px;">👊 SELECT FIGHTERS</span>
<span style="font-size:8px; color:#88dd88;" id="selectStatus">Choose Player 1</span>
</div>
<div style="font-size:7px; color:#88dd88; text-align:center; margin-bottom:2px;">Tap a character to select</div>
<div class="character-grid" id="characterGrid"></div>
<!-- GAME MODE SELECT -->
<div class="game-mode-select">
<button class="mode-btn active" id="mode1vAI" onclick="setGameMode('1vAI')">👤 VS AI</button>
<button class="mode-btn" id="mode2P" onclick="setGameMode('2P')">👥 2 PLAYERS</button>
</div>
<div style="display:flex; gap:4px; margin-top:4px;">
<button class="menu-btn small-btn" style="width:48%;" onclick="selectPlayer(0)">👤 P1: <span id="p1Name">None</span></button>
<button class="menu-btn small-btn" style="width:48%;" onclick="selectPlayer(1)">👤 P2: <span id="p2Name">None</span></button>
</div>
<button class="menu-btn red" style="margin-top:4px;" onclick="startFight()">⚔️ FIGHT!</button>
<div style="font-size:6px; color:#557755; text-align:center; margin-top:2px;" id="modeHint">Player 1 = Left (Joystick) | Player 2 = AI</div>
</div>
<!-- FIGHT SCREEN -->
<div id="fightScreen" class="screen">
<div class="fight-container">
<div id="moveList" class="move-list">
<div class="move-title">⚔️ MOVES</div>
<div class="move-item"><span class="move-key">⬆⬇⬅➡</span><span class="move-name">Move</span></div>
<div class="move-item"><span class="move-key">👊</span><span class="move-name">Punch</span></div>
<div class="move-item"><span class="move-key">🦵</span><span class="move-name">Kick</span></div>
<div class="move-item"><span class="move-key">🛡️</span><span class="move-name">Block</span></div>
<div class="move-item"><span class="move-key">⭐1</span><span class="move-name">Special 1</span></div>
<div class="move-item"><span class="move-key">⭐2</span><span class="move-name">Special 2</span></div>
</div>
<canvas id="fightCanvas"></canvas>
<!-- JOYSTICKS -->
<div id="joystickAreaP1" class="joystick-area">
<div id="joystickKnobP1" class="joystick-knob"></div>
</div>
<div id="joystickAreaP2" class="joystick-area">
<div id="joystickKnobP2" class="joystick-knob"></div>
</div>
<div id="winnerOverlay">
<div class="winner-text" id="winnerText">🏆 WINNER!</div>
<div class="winner-sub" id="winnerSub">Great fight!</div>
<div class="winner-quote" id="winnerQuote">"Victory!"</div>
<button class="menu-btn small-btn" style="margin-top:10px;" onclick="closeWinner()">👊 CONTINUE</button>
</div>
<div class="fight-controls">
<div class="btn-row left-btns">
<button class="attack-btn" id="punchBtn" onmousedown="doPlayerAction('punch')" ontouchstart="doPlayerAction('punch')">👊</button>
<button class="attack-btn" id="kickBtn" onmousedown="doPlayerAction('kick')" ontouchstart="doPlayerAction('kick')">🦵</button>
<button class="block-btn" id="blockBtn" onmousedown="doPlayerAction('block')" ontouchstart="doPlayerAction('block')">🛡️</button>
<button class="special-btn" id="special1Btn" onmousedown="doPlayerAction('special1')" ontouchstart="doPlayerAction('special1')">⭐1</button>
<button class="special-btn" id="special2Btn" onmousedown="doPlayerAction('special2')" ontouchstart="doPlayerAction('special2')">⭐2</button>
</div>
<div class="btn-row right-btns">
<button class="danger-btn" onclick="quitFight()">🚪</button>
</div>
</div>
<!-- P2 Controls (visible in 2 player mode) -->
<div class="fight-controls p2-controls" style="position:absolute; top:60px; right:5px; z-index:15; display:none; flex-direction:column; gap:2px; pointer-events:none;" id="p2Controls">
<div class="btn-row" style="pointer-events:auto;">
<button class="p2-btn" id="p2PunchBtn" onmousedown="doP2Action('punch')" ontouchstart="doP2Action('punch')">👊</button>
<button class="p2-btn" id="p2KickBtn" onmousedown="doP2Action('kick')" ontouchstart="doP2Action('kick')">🦵</button>
<button class="p2-btn" id="p2BlockBtn" onmousedown="doP2Action('block')" ontouchstart="doP2Action('block')">🛡️</button>
<button class="p2-btn" id="p2Special1Btn" onmousedown="doP2Action('special1')" ontouchstart="doP2Action('special1')">⭐1</button>
<button class="p2-btn" id="p2Special2Btn" onmousedown="doP2Action('special2')" ontouchstart="doP2Action('special2')">⭐2</button>
</div>
</div>
</div>
</div>
<!-- TRAINING -->
<div id="trainingScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">←</button>
<span style="font-size:10px;">🥋 TRAINING</span>
<span></span>
</div>
<div style="font-size:8px; color:#88dd88; text-align:center; margin:4px 0;">Practice your moves against a dummy</div>
<button class="menu-btn small-btn" onclick="startTraining()">▶ START TRAINING</button>
<div style="margin-top:6px; font-size:7px; color:#557755; text-align:center; border:1px solid #2a2a2a; border-radius:8px; padding:6px;">
<div style="color:#ffdd44; font-weight:bold;">📋 MOVE LIST</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:2px; margin-top:3px; font-size:7px;">
<div><span style="color:#ff4444;">👊</span> Punch (10 dmg)</div>
<div><span style="color:#ff4444;">🦵</span> Kick (15 dmg)</div>
<div><span style="color:#ff4444;">🛡️</span> Block</div>
<div><span style="color:#ffdd44;">⭐1</span> Special 1 (25 dmg)</div>
<div><span style="color:#ffdd44;">⭐2</span> Special 2 (20 dmg)</div>
</div>
</div>
</div>
<!-- TOURNAMENT -->
<div id="tournamentScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">←</button>
<span style="font-size:10px;">🏆 TOURNAMENT</span>
<span id="tournamentRound" style="font-size:8px; color:#88dd88;">Round 1</span>
</div>
<div id="tournamentBracket" class="tournament-bracket"></div>
<button class="menu-btn gold" id="tournamentFightBtn" onclick="startTournamentFight()">⚔️ NEXT FIGHT</button>
<div style="font-size:6px; color:#557755; text-align:center; margin-top:4px;">Win all matches to face the FINAL BOSS: SHINNOK!</div>
</div>
<!-- SETTINGS -->
<div id="settingsScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">←</button>
<span style="font-size:10px;">⚙️ SETTINGS</span>
<span></span>
</div>
<div style="margin-top:8px; font-size:10px;">
<div>🎵 Sound: <span class="text-gold" id="soundSetting">ON</span></div>
<div>🎮 Controls: <span class="text-gold">Joystick + Touch</span></div>
<div>👥 Mode: <span class="text-gold" id="modeSetting">1 Player vs AI</span></div>
<button class="menu-btn small-btn" style="margin-top:4px;" onclick="toggleSound()">🔊 TOGGLE SOUND</button>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="showComingSoon('Online Multiplayer')">🌐 ONLINE MULTIPLAYER</button>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="showComingSoon('More Characters')">👊 MORE CHARACTERS</button>
</div>
<div style="margin-top:8px; font-size:7px; color:#557755; text-align:center;">
🎙️ Real voice lines for each character!
</div>
</div>
</div>
<script>
// ========== LOADING SCREEN ==========
let loadingProgress = 0;
const loadFill = document.getElementById('loadFill');
const loadPercent = document.getElementById('loadPercent');
const loadingScreen = document.getElementById('loadingScreen');
const loadInterval = setInterval(() => {
loadingProgress += Math.random() * 8 + 2;
if (loadingProgress > 100) loadingProgress = 100;
loadFill.style.width = loadingProgress + '%';
loadPercent.textContent = Math.floor(loadingProgress) + '%';
if (loadingProgress >= 100) {
clearInterval(loadInterval);
document.querySelector('.tap-text').style.display = 'block';
}
}, 100);
loadingScreen.addEventListener('click', function() {
if (loadingProgress >= 100) {
this.style.display = 'none';
document.getElementById('homeScreen').classList.add('active');
renderCharacters();
initTournament();
}
});
// ========== CHARACTER DATA ==========
const characters = [
{
id: 'scorpion',
name: 'Scorpion',
icon: '🔥',
color: '#ff6600',
health: 100,
speed: 1.2,
punch: 10,
kick: 15,
special1: { name: 'Fireball', damage: 25, key: '⭐1' },
special2: { name: 'Spear', damage: 20, key: '⭐2' },
quote: "GET OVER HERE!",
voice: "Get over here!"
},
{
id: 'subzero',
name: 'Sub-Zero',
icon: '❄️',
color: '#00ccff',
health: 100,
speed: 1.1,
punch: 10,
kick: 15,
special1: { name: 'Ice Blast', damage: 25, key: '⭐1' },
special2: { name: 'Slide', damage: 18, key: '⭐2' },
quote: "FREEZE!",
voice: "Freeze!"
},
{
id: 'liukang',
name: 'Liu Kang',
icon: '🐉',
color: '#ffdd00',
health: 95,
speed: 1.4,
punch: 8,
kick: 18,
special1: { name: 'Fire Kick', damage: 22, key: '⭐1' },
special2: { name: 'Dragon Punch', damage: 28, key: '⭐2' },
quote: "HWAA!",
voice: "Hwaa!"
},
{
id: 'raiden',
name: 'Raiden',
icon: '⚡',
color: '#8844ff',
health: 100,
speed: 1.0,
punch: 12,
kick: 12,
special1: { name: 'Lightning', damage: 30, key: '⭐1' },
special2: { name: 'Teleport', damage: 15, key: '⭐2' },
quote: "THUNDER STRIKES!",
voice: "Thunder strikes!"
},
{
id: 'sonya',
name: 'Sonya Blade',
icon: '💪',
color: '#ff44aa',
health: 90,
speed: 1.3,
punch: 12,
kick: 14,
special1: { name: 'Energy Ring', damage: 22, key: '⭐1' },
special2: { name: 'Leg Grab', damage: 20, key: '⭐2' },
quote: "YOU'RE MINE!",
voice: "You're mine!"
},
{
id: 'jax',
name: 'Jax Briggs',
icon: '🔩',
color: '#44dd88',
health: 110,
speed: 0.9,
punch: 15,
kick: 10,
special1: { name: 'Ground Pound', damage: 25, key: '⭐1' },
special2: { name: 'Dash Punch', damage: 22, key: '⭐2' },
quote: "BOOM!",
voice: "Boom!"
},
{
id: 'kunglao',
name: 'Kung Lao',
icon: '🎯',
color: '#ff8844',
health: 95,
speed: 1.3,
punch: 9,
kick: 16,
special1: { name: 'Hat Throw', damage: 24, key: '⭐1' },
special2: { name: 'Spin Kick', damage: 26, key: '⭐2' },
quote: "HAT TRICK!",
voice: "Hat trick!"
},
{
id: 'kitana',
name: 'Kitana',
icon: '🌊',
color: '#44ddff',
health: 90,
speed: 1.4,
punch: 8,
kick: 17,
special1: { name: 'Fan Throw', damage: 22, key: '⭐1' },
special2: { name: 'Fan Lift', damage: 20, key: '⭐2' },
quote: "FOR EDENIA!",
voice: "For Edenia!"
},
{
id: 'reptile',
name: 'Reptile',
icon: '🦎',
color: '#44ff44',
health: 95,
speed: 1.3,
punch: 10,
kick: 14,
special1: { name: 'Acid Spit', damage: 28, key: '⭐1' },
special2: { name: 'Invisibility', damage: 16, key: '⭐2' },
quote: "SSSSSS!",
voice: "Ssssss!"
},
{
id: 'mileena',
name: 'Mileena',
icon: '🗡️',
color: '#ff44ff',
health: 90,
speed: 1.4,
punch: 9,
kick: 16,
special1: { name: 'Sai Throw', damage: 24, key: '⭐1' },
special2: { name: 'Teleport Kick', damage: 22, key: '⭐2' },
quote: "TIME TO DIE!",
voice: "Time to die!"
},
{
id: 'baraka',
name: 'Baraka',
icon: '⚔️',
color: '#ff8844',
health: 105,
speed: 1.0,
punch: 14,
kick: 12,
special1: { name: 'Blade Spin', damage: 26, key: '⭐1' },
special2: { name: 'Leap Slash', damage: 24, key: '⭐2' },
quote: "TARKATA!",
voice: "Tarkata!"
},
{
id: 'noob',
name: 'Noob Saibot',
icon: '👻',
color: '#444444',
health: 95,
speed: 1.2,
punch: 11,
kick: 13,
special1: { name: 'Shadow Clone', damage: 22, key: '⭐1' },
special2: { name: 'Portal', damage: 20, key: '⭐2' },
quote: "DARKNESS!",
voice: "Darkness!"
},
{
id: 'sonicbear',
name: 'Sonic Bear 35',
icon: '🐻',
color: '#ff8800',
health: 120,
speed: 1.5,
punch: 12,
kick: 14,
special1: { name: 'Bear Slam', damage: 30, key: '⭐1' },
special2: { name: 'Sonic Roar', damage: 28, key: '⭐2' },
quote: "BEAR POWER!",
voice: "Bear power!"
},
{
id: 'ermac',
name: 'Ermac',
icon: '🔮',
color: '#44ff44',
health: 100,
speed: 1.1,
punch: 10,
kick: 14,
special1: { name: 'Force Push', damage: 24, key: '⭐1' },
special2: { name: 'Telekinetic', damage: 22, key: '⭐2' },
quote: "WE ARE MANY!",
voice: "We are many!"
},
{
id: 'shang',
name: 'Shang Tsung',
icon: '🐍',
color: '#44dd44',
health: 95,
speed: 1.2,
punch: 9,
kick: 15,
special1: { name: 'Soul Steal', damage: 25, key: '⭐1' },
special2: { name: 'Fire Skull', damage: 22, key: '⭐2' },
quote: "YOUR SOUL IS MINE!",
voice: "Your soul is mine!"
},
{
id: 'shinnok',
name: 'Shinnok',
icon: '👑',
color: '#ff00ff',
health: 150,
speed: 1.2,
punch: 15,
kick: 18,
special1: { name: 'Death Beam', damage: 35, key: '⭐1' },
special2: { name: 'Nether Portal', damage: 30, key: '⭐2' },
quote: "BOW TO YOUR GOD!",
voice: "Bow to your god!",
boss: true
}
];
// ========== GAME STATE ==========
let selectedCharacters = [null, null];
let player1Char = null;
let player2Char = null;
let p1Health = 100;
let p2Health = 100;
let p1MaxHealth = 100;
let p2MaxHealth = 100;
let p1X = 80;
let p2X = 320;
let p1Y = 320;
let p2Y = 320;
let p1State = 'idle';
let p2State = 'idle';
let p1Facing = 1;
let p2Facing = -1;
let p1Cooldown = 0;
let p2Cooldown = 0;
let p1Block = false;
let p2Block = false;
let p1SpecialCooldown = 0;
let p2SpecialCooldown = 0;
let fightActive = false;
let fightInterval = null;
let frameId = null;
let gameTime = 0;
let isTraining = false;
let soundEnabled = true;
let selectedPlayerIndex = 0;
let hitEffects = [];
let specialEffects = [];
let gameMode = '1vAI';
let is2Player = false;
// Joystick state
let joystickP1 = { x: 0, y: 0, active: false };
let joystickP2 = { x: 0, y: 0, active: false };
// Tournament
let tournamentPlayers = [];
let tournamentRound = 0;
let tournamentWinner = null;
let isTournament = false;
let currentTournamentMatch = 0;
// ========== RENDER CHARACTERS ==========
function renderCharacters() {
const grid = document.getElementById('characterGrid');
if (!grid) return;
grid.innerHTML = '';
characters.forEach((char, index) => {
const div = document.createElement('div');
div.className = 'character-card' + (char.boss ? ' boss' : '');
div.innerHTML = `<span class="char-icon">${char.icon}</span>
<div class="char-name">${char.name}</div>
<div class="char-stats">❤️${char.health} ⚡${char.speed}</div>`;
div.onclick = () => toggleSelectCharacter(index);
if (selectedCharacters.includes(char)) {
div.classList.add('selected');
}
grid.appendChild(div);
});
updateSelectStatus();
}
function toggleSelectCharacter(index) {
const char = characters[index];
const pos = selectedCharacters.indexOf(char);
if (pos !== -1) {
selectedCharacters[pos] = null;
} else {
if (selectedCharacters[0] === null) {
selectedCharacters[0] = char;
} else if (selectedCharacters[1] === null) {
selectedCharacters[1] = char;
} else {
selectedCharacters[1] = char;
}
}
selectedCharacters = selectedCharacters.filter(c => c !== null);
while (selectedCharacters.length < 2) {
selectedCharacters.push(null);
}
renderCharacters();
updateSelectStatus();
}
function updateSelectStatus() {
const status = document.getElementById('selectStatus');
const p1Name = document.getElementById('p1Name');
const p2Name = document.getElementById('p2Name');
if (status) {
const count = selectedCharacters.filter(c => c !== null).length;
status.textContent = count === 0 ? 'Choose Player 1' : count === 1 ? 'Choose Player 2' : 'Ready to FIGHT!';
status.style.color = count === 2 ? '#ffdd44' : '#88dd88';
}
if (p1Name) p1Name.textContent = selectedCharacters[0] ? selectedCharacters[0].name : 'None';
if (p2Name) p2Name.textContent = selectedCharacters[1] ? selectedCharacters[1].name : 'None';
const hint = document.getElementById('modeHint');
if (hint) {
hint.textContent = gameMode === '1vAI' ? 'Player 1 = Left (Joystick) | Player 2 = AI' : 'Player 1 = Left Joystick | Player 2 = Right Joystick';
}
}
function selectPlayer(num) {
selectedPlayerIndex = num;
renderCharacters();
}
function setGameMode(mode) {
gameMode = mode;
is2Player = mode === '2P';
document.querySelectorAll('.mode-btn').forEach(b => b.classList.remove('active'));
if (mode === '1vAI') {
document.getElementById('mode1vAI').classList.add('active');
document.getElementById('modeSetting').textContent = '1 Player vs AI';
document.getElementById('joystickAreaP2').style.display = 'none';
document.getElementById('p2Controls').style.display = 'none';
} else {
document.getElementById('mode2P').classList.add('active');
document.getElementById('modeSetting').textContent = '2 Players';
document.getElementById('joystickAreaP2').style.display = 'block';
document.getElementById('p2Controls').style.display = 'flex';
}
updateSelectStatus();
}
// ========== VOICE SYSTEM ==========
function speakVoice(text) {
if (!soundEnabled) return;
try {
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(text);
utterance.rate = 0.9;
utterance.pitch = 0.9;
utterance.volume = 1;
window.speechSynthesis.speak(utterance);
} catch(e) {}
}
function playCharacterVoice(char, isWinner) {
if (!char) return;
const voice = isWinner ? char.quote : char.voice || char.quote;
speakVoice(voice);
sayComment(`🎙️ ${char.name}: "${voice}"`, '🎙️');
}
// ========== COMMENTATOR ==========
let commentatorTimeout = null;
function sayComment(text, emoji = '🎙️') {
const box = document.getElementById('commentatorBox');
if (!box) return;
const textEl = document.getElementById('commentatorText');
if (!textEl) return;
textEl.textContent = text;
const emojiEl = box.querySelector('.emoji');
if (emojiEl) emojiEl.textContent = emoji;
box.style.opacity = '1';
box.style.transform = 'translateX(-50%) scale(1)';
clearTimeout(commentatorTimeout);
commentatorTimeout = setTimeout(() => {
box.style.opacity = '0.7';
box.style.transform = 'translateX(-50%) scale(0.98)';
}, 1500);
}
// ========== JOYSTICK SETUP ==========
function setupJoystick(id, knobId, joystickState) {
const area = document.getElementById(id);
const knob = document.getElementById(knobId);
if (!area || !knob) return;
const radius = area.offsetWidth / 2 - knob.offsetWidth / 2;
function handleMove(clientX, clientY) {
const rect = area.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
let dx = clientX - centerX;
let dy = clientY - centerY;
const dist = Math.sqrt(dx * dx + dy * dy);
const maxDist = rect.width / 2 - knob.offsetWidth / 2;
if (dist > maxDist && maxDist > 0) {
dx = (dx / dist) * maxDist;
dy = (dy / dist) * maxDist;
}
knob.style.transform = `translate(${dx}px, ${dy}px)`;
joystickState.x = maxDist > 0 ? dx / maxDist : 0;
joystickState.y = maxDist > 0 ? dy / maxDist : 0;
joystickState.active = true;
}
function handleEnd() {
knob.style.transform = 'translate(0, 0)';
joystickState.x = 0;
joystickState.y = 0;
joystickState.active = false;
}
// Remove old listeners by cloning
const newArea = area.cloneNode(true);
area.parentNode.replaceChild(newArea, area);
const newKnob = newArea.querySelector('.joystick-knob');
newArea.addEventListener('touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
newArea.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
newArea.addEventListener('touchend', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
newArea.addEventListener('touchcancel', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
let isDragging = false;
newArea.addEventListener('mousedown', (e) => {
isDragging = true;
handleMove(e.clientX, e.clientY);
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
handleMove(e.clientX, e.clientY);
}
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
handleEnd();
}
});
}
function movePlayerWithJoystick(x, y, isP2) {
if (!fightActive) return;
const speed = 2;
if (isP2) {
p2X += x * speed * (player2Char ? player2Char.speed || 1 : 1);
p2Y += y * speed * (player2Char ? player2Char.speed || 1 : 1);
} else {
p1X += x * speed * (player1Char ? player1Char.speed || 1 : 1);
p1Y += y * speed * (player1Char ? player1Char.speed || 1 : 1);
}
}
// ========== START FIGHT ==========
function startFight() {
if (!selectedCharacters[0] || !selectedCharacters[1]) {
alert('Please select 2 fighters!');
return;
}
player1Char = selectedCharacters[0];
player2Char = selectedCharacters[1];
p1MaxHealth = player1Char.health;
p2MaxHealth = player2Char.health;
p1Health = p1MaxHealth;
p2Health = p2MaxHealth;
p1X = 80;
p2X = 320;
p1Y = 320;
p2Y = 320;
p1State = 'idle';
p2State = 'idle';
p1Facing = 1;
p2Facing = -1;
p1Cooldown = 0;
p2Cooldown = 0;
p1Block = false;
p2Block = false;
p1SpecialCooldown = 0;
p2SpecialCooldown = 0;
isTraining = false;
isTournament = false;
showScreen('fightScreen');
initFightCanvas();
setupJoystick('joystickAreaP1', 'joystickKnobP1', joystickP1);
if (is2Player) {
setupJoystick('joystickAreaP2', 'joystickKnobP2', joystickP2);
document.getElementById('joystickAreaP2').style.display = 'block';
document.getElementById('p2Controls').style.display = 'flex';
} else {
document.getElementById('joystickAreaP2').style.display = 'none';
document.getElementById('p2Controls').style.display = 'none';
}
startFightLoop();
updateMoveList();
sayComment(`⚔️ ${player1Char.name} vs ${player2Char.name}!`, '⚔️');
playCharacterVoice(player1Char, false);
setTimeout(() => playCharacterVoice(player2Char, false), 800);
}
function startRandomFight() {
const shuffled = [...characters].sort(() => Math.random() - 0.5);
selectedCharacters[0] = shuffled[0] || characters[0];
selectedCharacters[1] = shuffled[1] || characters[1];
renderCharacters();
updateSelectStatus();
startFight();
}
function startTraining() {
isTraining = true;
isTournament = false;
player1Char = characters[0];
player2Char = characters[1];
p1MaxHealth = 999;
p2MaxHealth = 999;
p1Health = 999;
p2Health = 999;
p1X = 80;
p2X = 320;
p1Y = 320;
p2Y = 320;
p1State = 'idle';
p2State = 'idle';
p1Facing = 1;
p2Facing = -1;
p1Cooldown = 0;
p2Cooldown = 0;
p1Block = false;
p2Block = false;
p1SpecialCooldown = 0;
p2SpecialCooldown = 0;
showScreen('fightScreen');
initFightCanvas();
setupJoystick('joystickAreaP1', 'joystickKnobP1', joystickP1);
document.getElementById('joystickAreaP2').style.display = 'none';
document.getElementById('p2Controls').style.display = 'none';
startFightLoop();
sayComment('🥋 Training Mode - Practice your moves!', '🥋');
}
// ========== TOURNAMENT ==========
function initTournament() {
const shuffled = [...characters].sort(() => Math.random() - 0.5);
const nonBoss = shuffled.filter(c => !c.boss);
tournamentPlayers = nonBoss.slice(0, 8);
tournamentRound = 0;
tournamentWinner = null;
currentTournamentMatch = 0;
updateTournamentUI();
}
function updateTournamentUI() {
const bracket = document.getElementById('tournamentBracket');
if (!bracket) return;
let html = `<div style="color:#ffdd44; font-weight:bold; font-size:9px; text-align:center;">TOURNAMENT BRACKET</div>`;
const remaining = tournamentPlayers.length;
if (remaining === 0) {
html += `<div style="text-align:center; color:#ffdd44; padding:10px;">🏆 ${tournamentWinner ? tournamentWinner.name : 'No winner'} WINS!</div>`;
} else {
html += `<div style="font-size:7px; color:#88dd88; text-align:center;">${remaining} fighters remaining</div>`;
tournamentPlayers.forEach((p, i) => {
const isCurrent = i === currentTournamentMatch && p;
html += `<div class="round" style="${isCurrent ? 'background:#2a1a1a;' : ''}">
<span>${p ? p.icon + ' ' + p.name : 'BYE'}</span>
<span class="${isCurrent ? 'winner' : ''}">${isCurrent ? '▶ FIGHTING' : p ? '⬜' : '⬜'}</span>
</div>`;
});
}
bracket.innerHTML = html;
document.getElementById('tournamentRound').textContent = `Round ${tournamentRound + 1}`;
}
function startTournament() {
showScreen('tournamentScreen');
initTournament();
document.getElementById('tournamentFightBtn').textContent = '⚔️ NEXT FIGHT';
updateTournamentUI();
}
function startTournamentFight() {
if (tournamentPlayers.length < 2) {
alert('🏆 Tournament complete!');
return;
}
const p1 = tournamentPlayers[0];
const p2 = tournamentPlayers[1] || tournamentPlayers[0];
if (!p1 || !p2) {
alert('Not enough players for tournament!');
return;
}
selectedCharacters[0] = p1;
selectedCharacters[1] = p2;
startFight();
isTournament = true;
sayComment(`🏆 Tournament Match: ${p1.name} vs ${p2.name}!`, '🏆');
}
function handleTournamentResult(winner) {
const loser = tournamentPlayers.find(p => p !== winner);
if (loser) {
tournamentPlayers = tournamentPlayers.filter(p => p !== loser);
}
currentTournamentMatch++;
updateTournamentUI();
if (tournamentPlayers.length === 1) {
tournamentWinner = tournamentPlayers[0];
sayComment(`🏆 ${tournamentWinner.name} WINS THE TOURNAMENT!`, '🏆');
playCharacterVoice(tournamentWinner, true);
document.getElementById('tournamentFightBtn').textContent = '🏆 TOURNAMENT COMPLETE';
updateTournamentUI();
setTimeout(() => {
showWinner(tournamentWinner, null, true);
}, 500);
} else if (tournamentPlayers.length === 2 && tournamentRound < 3) {
tournamentRound++;
document.getElementById('tournamentFightBtn').textContent = '⚔️ FINAL FIGHT!';
updateTournamentUI();
} else {
document.getElementById('tournamentFightBtn').textContent = '⚔️ NEXT FIGHT';
updateTournamentUI();
}
}
// ========== FIGHT CANVAS ==========
function initFightCanvas() {
const canvas = document.getElementById('fightCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
}
function startFightLoop() {
fightActive = true;
if (fightInterval) clearInterval(fightInterval);
if (frameId) cancelAnimationFrame(frameId);
fightInterval = setInterval(() => {
gameTime++;
// Apply joystick movement
if (joystickP1.active) {
movePlayerWithJoystick(joystickP1.x, joystickP1.y, false);
}
if (is2Player && joystickP2.active) {
movePlayerWithJoystick(joystickP2.x, joystickP2.y, true);
}
if (!isTraining && (p1Health <= 0 || p2Health <= 0)) {
fightActive = false;
clearInterval(fightInterval);
const winner = p1Health > 0 ? player1Char : player2Char;
const loser = p1Health > 0 ? player2Char : player1Char;
playCharacterVoice(winner, true);
if (isTournament) {
handleTournamentResult(winner);
} else {
showWinner(winner, loser);
}
}
updateFight();
drawFight();
}, 50);
function animate() {
if (!fightActive && !isTraining) return;
drawFight();
frameId = requestAnimationFrame(animate);
}
animate();
}
function updateFight() {
if (p1Cooldown > 0) p1Cooldown--;
if (p2Cooldown > 0) p2Cooldown--;
if (p1SpecialCooldown > 0) p1SpecialCooldown--;
if (p2SpecialCooldown > 0) p2SpecialCooldown--;
// AI for P2 when in 1vAI mode
if (!isTraining && !isTournament && !is2Player) {
updateAI();
}
p1X = Math.max(30, Math.min(390, p1X));
p2X = Math.max(30, Math.min(390, p2X));
p1Y = Math.max(260, Math.min(420, p1Y));
p2Y = Math.max(260, Math.min(420, p2Y));
if (p1X < p2X) {
p1Facing = 1;
p2Facing = -1;
} else {
p1Facing = -1;
p2Facing = 1;
}
}
// ========== AI ==========
function updateAI() {
const dist = Math.abs(p1X - p2X);
const action = Math.random();
if (dist > 80) {
if (p2X < p1X) p2X += 1.5 * (player2Char ? player2Char.speed || 1 : 1);
else p2X -= 1.5 * (player2Char ? player2Char.speed || 1 : 1);
} else if (dist < 50 && action < 0.55) {
if (p2Cooldown === 0) {
if (action < 0.15 && p2SpecialCooldown === 0) {
doAIAction('special1');
} else if (action < 0.3 && p2SpecialCooldown === 0) {
doAIAction('special2');
} else if (action < 0.42) {
doAIAction('kick');
} else {
doAIAction('punch');
}
}
} else if (action < 0.25) {
p2X += (Math.random() - 0.5) * 3 * (player2Char ? player2Char.speed || 1 : 1);
}
p2Block = Math.random() < 0.08;
}
function doAIAction(action) {
if (p2Cooldown > 0) return;
const dist = Math.abs(p1X - p2X);
if (action === 'punch' && dist < 60) {
p2Cooldown = 15;
const damage = player2Char ? player2Char.punch || 10 : 10;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
setTimeout(() => { p1State = 'idle'; }, 300);
addHitEffect(p2X - 20, p1Y);
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
}
} else if (action === 'kick' && dist < 70) {
p2Cooldown = 20;
const damage = player2Char ? player2Char.kick || 15 : 15;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 10 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 300);
addHitEffect(p2X - 20, p1Y);
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
}
} else if (action === 'special1' && dist < 100 && p2SpecialCooldown === 0) {
p2SpecialCooldown = 30;
p2Cooldown = 25;
const damage = player2Char ? player2Char.special1.damage || 25 : 25;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 20 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 400);
addHitEffect(p2X - 30, p1Y - 20);
addSpecialEffect(p1X, p1Y, player2Char ? player2Char.color || '#ff4444' : '#ff4444');
sayComment(`⭐ ${player2Char ? player2Char.special1.name : 'Special'}!`, '⭐');
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
}
} else if (action === 'special2' && dist < 90 && p2SpecialCooldown === 0) {
p2SpecialCooldown = 30;
p2Cooldown = 25;
const damage = player2Char ? player2Char.special2.damage || 20 : 20;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 15 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 400);
addHitEffect(p2X - 30, p1Y - 10);
addSpecialEffect(p1X, p1Y - 20, '#ff8800');
sayComment(`⭐ ${player2Char ? player2Char.special2.name : 'Special'}!`, '⭐');
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
}
}
}
// ========== PLAYER 1 CONTROLS ==========
function doPlayerAction(action) {
if (!fightActive) return;
if (p1Cooldown > 0) return;
const dist = Math.abs(p1X - p2X);
if (action === 'punch' && dist < 60) {
p1Cooldown = 15;
const damage = player1Char ? player1Char.punch || 10 : 10;
if (!p2Block) {
p2Health -= damage;
p2State = 'hit';
p2X += 10 * p2Facing;
setTimeout(() => { p2State = 'idle'; }, 300);
addHitEffect(p1X + 20, p2Y);
sayComment('👊 Punch!', '💥');
} else {
p2State = 'block';
setTimeout(() => { p2State = 'idle'; }, 200);
sayComment('🛡️ Blocked!', '🛡️');
}
} else if (action === 'kick' && dist < 70) {
p1Cooldown = 20;
const damage = player1Char ? player1Char.kick || 15 : 15;
if (!p2Block) {
p2Health -= damage;
p2State = 'hit';
p2X += 15 * p2Facing;
setTimeout(() => { p2State = 'idle'; }, 300);
addHitEffect(p1X + 20, p2Y - 10);
sayComment('🦵 Kick!', '💥');
} else {
p2State = 'block';
setTimeout(() => { p2State = 'idle'; }, 200);
sayComment('🛡️ Blocked!', '🛡️');
}
} else if (action === 'block') {
p1Block = true;
setTimeout(() => { p1Block = false; }, 300);
sayComment('🛡️ Blocking!', '🛡️');
} else if (action === 'special1' && dist < 100 && p1SpecialCooldown === 0) {
p1SpecialCooldown = 30;
p1Cooldown = 25;
const damage = player1Char ? player1Char.special1.damage || 25 : 25;
if (!p2Block) {
p2Health -= damage;
p2State = 'hit';
p2X += 20 * p2Facing;
setTimeout(() => { p2State = 'idle'; }, 400);
addHitEffect(p1X + 30, p2Y - 20);
addSpecialEffect(p2X, p2Y, player1Char ? player1Char.color || '#ffdd44' : '#ffdd44');
sayComment(`⭐ ${player1Char ? player1Char.special1.name : 'Special'}!`, '⭐');
playCharacterVoice(player1Char, false);
} else {
p2State = 'block';
setTimeout(() => { p2State = 'idle'; }, 200);
sayComment('🛡️ Blocked!', '🛡️');
}
} else if (action === 'special2' && dist < 90 && p1SpecialCooldown === 0) {
p1SpecialCooldown = 30;
p1Cooldown = 25;
const damage = player1Char ? player1Char.special2.damage || 20 : 20;
if (!p2Block) {
p2Health -= damage;
p2State = 'hit';
p2X += 25 * p2Facing;
setTimeout(() => { p2State = 'idle'; }, 400);
addHitEffect(p1X + 30, p2Y - 10);
addSpecialEffect(p2X, p2Y - 20, '#ff8800');
sayComment(`⭐ ${player1Char ? player1Char.special2.name : 'Special'}!`, '⭐');
playCharacterVoice(player1Char, false);
} else {
p2State = 'block';
setTimeout(() => { p2State = 'idle'; }, 200);
sayComment('🛡️ Blocked!', '🛡️');
}
} else {
if (action.includes('special')) {
sayComment('Too far!', '❌');
}
}
}
// ========== PLAYER 2 CONTROLS (2 Player Mode) ==========
function doP2Action(action) {
if (!fightActive || !is2Player) return;
if (p2Cooldown > 0) return;
const dist = Math.abs(p1X - p2X);
if (action === 'punch' && dist < 60) {
p2Cooldown = 15;
const damage = player2Char ? player2Char.punch || 10 : 10;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 10 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 300);
addHitEffect(p2X - 20, p1Y);
sayComment('👊 P2 Punch!', '💥');
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
sayComment('🛡️ P1 Blocked!', '🛡️');
}
} else if (action === 'kick' && dist < 70) {
p2Cooldown = 20;
const damage = player2Char ? player2Char.kick || 15 : 15;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 15 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 300);
addHitEffect(p2X - 20, p1Y - 10);
sayComment('🦵 P2 Kick!', '💥');
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
sayComment('🛡️ P1 Blocked!', '🛡️');
}
} else if (action === 'block') {
p2Block = true;
setTimeout(() => { p2Block = false; }, 300);
sayComment('🛡️ P2 Blocking!', '🛡️');
} else if (action === 'special1' && dist < 100 && p2SpecialCooldown === 0) {
p2SpecialCooldown = 30;
p2Cooldown = 25;
const damage = player2Char ? player2Char.special1.damage || 25 : 25;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 20 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 400);
addHitEffect(p2X - 30, p1Y - 20);
addSpecialEffect(p1X, p1Y, player2Char ? player2Char.color || '#ff4444' : '#ff4444');
sayComment(`⭐ P2 ${player2Char ? player2Char.special1.name : 'Special'}!`, '⭐');
playCharacterVoice(player2Char, false);
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
sayComment('🛡️ P1 Blocked!', '🛡️');
}
} else if (action === 'special2' && dist < 90 && p2SpecialCooldown === 0) {
p2SpecialCooldown = 30;
p2Cooldown = 25;
const damage = player2Char ? player2Char.special2.damage || 20 : 20;
if (!p1Block) {
p1Health -= damage;
p1State = 'hit';
p1X += 15 * p1Facing;
setTimeout(() => { p1State = 'idle'; }, 400);
addHitEffect(p2X - 30, p1Y - 10);
addSpecialEffect(p1X, p1Y - 20, '#ff8800');
sayComment(`⭐ P2 ${player2Char ? player2Char.special2.name : 'Special'}!`, '⭐');
playCharacterVoice(player2Char, false);
} else {
p1State = 'block';
setTimeout(() => { p1State = 'idle'; }, 200);
sayComment('🛡️ P1 Blocked!', '🛡️');
}
}
}
// ========== EFFECTS ==========
function addHitEffect(x, y) {
hitEffects.push({ x, y, timer: 10 });
if (hitEffects.length > 10) hitEffects.shift();
}
function addSpecialEffect(x, y, color) {
specialEffects.push({ x, y, color, timer: 20, size: 30 });
if (specialEffects.length > 5) specialEffects.shift();
}
// ========== DRAW FIGHT ==========
function drawFight() {
const canvas = document.getElementById('fightCanvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const W = canvas.width || 400;
const H = canvas.height || 700;
// Background
const gradient = ctx.createLinearGradient(0, 0, 0, H);
gradient.addColorStop(0, '#1a0a2a');
gradient.addColorStop(0.5, '#0a1a2a');
gradient.addColorStop(1, '#0a0a1a');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, W, H);
// Floor
ctx.fillStyle = 'rgba(30,20,40,0.5)';
ctx.fillRect(0, H-50, W, 50);
ctx.strokeStyle = 'rgba(100,80,120,0.3)';
ctx.lineWidth = 1;
for (let i = 0; i < W; i += 40) {
ctx.beginPath();
ctx.moveTo(i, H-50);
ctx.lineTo(i + 20, H);
ctx.stroke();
}
// Health bars
const barWidth = W * 0.35;
const barHeight = 14;
const barY = 15;
// P1 Health
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(10, barY, barWidth, barHeight);
const p1HealthPercent = Math.max(0, p1Health / p1MaxHealth);
const p1Color = p1HealthPercent > 0.5 ? '#44ff44' : p1HealthPercent > 0.25 ? '#ffdd44' : '#ff4444';
ctx.fillStyle = p1Color;
ctx.fillRect(12, barY + 2, (barWidth - 4) * p1HealthPercent, barHeight - 4);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 9px sans-serif';
ctx.textAlign = 'left';
ctx.fillText(player1Char ? player1Char.icon + ' ' + player1Char.name : 'P1', 12, barY + 11);
ctx.textAlign = 'right';
ctx.fillText(Math.round(p1Health) + '/' + p1MaxHealth, 10 + barWidth - 4, barY + 11);
ctx.textAlign = 'left';
// P2 Health
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(W - 10 - barWidth, barY, barWidth, barHeight);
const p2HealthPercent = Math.max(0, p2Health / p2MaxHealth);
const p2Color = p2HealthPercent > 0.5 ? '#44ff44' : p2HealthPercent > 0.25 ? '#ffdd44' : '#ff4444';
ctx.fillStyle = p2Color;
ctx.fillRect(W - 12 - barWidth + 2, barY + 2, (barWidth - 4) * p2HealthPercent, barHeight - 4);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 9px sans-serif';
ctx.textAlign = 'right';
ctx.fillText(player2Char ? player2Char.icon + ' ' + player2Char.name : 'P2', W - 12, barY + 11);
ctx.textAlign = 'left';
ctx.fillText(Math.round(p2Health) + '/' + p2MaxHealth, W - 12 - barWidth + 4, barY + 11);
// VS text
ctx.fillStyle = '#ff4444';
ctx.font = 'bold 14px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('VS', W/2, barY + 12);
ctx.textAlign = 'left';
// Draw players
if (player1Char) {
drawFighter(ctx, p1X, p1Y, player1Char.color || '#ffdd44', p1Facing, p1State, p1Block, p1Health, player1Char.icon, player1Char.name);
}
if (player2Char) {
drawFighter(ctx, p2X, p2Y, player2Char.color || '#ff6666', p2Facing, p2State, p2Block, p2Health, player2Char.icon, player2Char.name);
}
// Effects
hitEffects = hitEffects.filter(e => {
e.timer--;
const alpha = e.timer / 10;
ctx.fillStyle = `rgba(255,255,255,${alpha * 0.8})`;
ctx.beginPath();
ctx.arc(e.x, e.y, 10 * (1 - e.timer / 10), 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = `rgba(255,200,50,${alpha * 0.5})`;
ctx.beginPath();
ctx.arc(e.x, e.y, 15 * (1 - e.timer / 10), 0, Math.PI * 2);
ctx.fill();
return e.timer > 0;
});
specialEffects = specialEffects.filter(e => {
e.timer--;
const alpha = e.timer / 20;
const size = e.size * (1 + (1 - e.timer / 20) * 2);
ctx.strokeStyle = e.color || '#ffdd44';
ctx.globalAlpha = alpha * 0.8;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(e.x, e.y, size, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath();
ctx.arc(e.x, e.y, size * 0.6, 0, Math.PI * 2);
ctx.stroke();
ctx.globalAlpha = 1;
return e.timer > 0;
});
// Cooldown indicators
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.font = '6px sans-serif';
ctx.textAlign = 'left';
const cdText1 = p1SpecialCooldown > 0 ? `⭐ ${Math.ceil(p1SpecialCooldown/5)}s` : '⭐ READY';
ctx.fillText(cdText1, 10, barY + barHeight + 12);
const cdText2 = p2SpecialCooldown > 0 ? `⭐ ${Math.ceil(p2SpecialCooldown/5)}s` : '⭐ READY';
ctx.textAlign = 'right';
ctx.fillText(cdText2, W - 10, barY + barHeight + 12);
ctx.textAlign = 'left';
// Mode indicator
if (isTraining) {
ctx.fillStyle = '#44ff88';
ctx.font = '8px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('🥋 TRAINING MODE', W/2, H - 10);
ctx.textAlign = 'left';
}
if (isTournament) {
ctx.fillStyle = '#ffdd44';
ctx.font = '7px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(`🏆 TOURNAMENT - Round ${tournamentRound + 1}`, W/2, H - 10);
ctx.textAlign = 'left';
}
if (is2Player) {
ctx.fillStyle = '#44aaff';
ctx.font = '7px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('👥 2 PLAYER MODE', W/2, H - 20);
ctx.textAlign = 'left';
}
}
function drawFighter(ctx, x, y, color, facing, state, blocking, health, icon, name) {
ctx.shadowBlur = 0;
const dir = facing || 1;
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.beginPath();
ctx.ellipse(x, y + 28, 15, 4, 0, 0, Math.PI * 2);
ctx.fill();
if (health < 30) {
ctx.shadowColor = 'rgba(255,0,0,0.3)';
ctx.shadowBlur = 20;
}
if (blocking) {
ctx.strokeStyle = 'rgba(68,255,136,0.4)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(x + dir * 10, y - 10, 20, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = 'rgba(68,255,136,0.1)';
ctx.fill();
}
ctx.strokeStyle = color;
ctx.lineWidth = 2.5;
ctx.beginPath();
ctx.arc(x + dir * 2, y - 14, 9, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = color;
ctx.fillRect(x + dir * 5, y - 16, 2, 2);
ctx.fillRect(x + dir * 8, y - 16, 2, 2);
ctx.beginPath();
ctx.moveTo(x + dir * 2, y - 5);
ctx.lineTo(x + dir * 2, y + 16);
ctx.stroke();
let armOffset = 0;
let legOffset = 0;
if (state === 'hit') {
armOffset = 10;
} else if (state === 'block') {
armOffset = -5;
} else {
armOffset = Math.sin(gameTime / 20) * 2;
legOffset = Math.sin(gameTime / 25) * 1;
}
ctx.beginPath();
const legSwing = state === 'hit' ? 6 : legOffset;
ctx.moveTo(x + dir * 2, y + 16);
ctx.lineTo(x + dir * 2 - 5 + legSwing, y + 28);
ctx.moveTo(x + dir * 2, y + 16);
ctx.lineTo(x + dir * 2 + 5 - legSwing, y + 28);
ctx.stroke();
let punchExtension = 0;
if (state === 'hit') punchExtension = 12;
else if (blocking) punchExtension = -5;
ctx.beginPath();
ctx.moveTo(x + dir * 2, y + 3);
ctx.lineTo(x + dir * 2 + dir * (8 + punchExtension) + armOffset, y - 4);
ctx.moveTo(x + dir * 2, y + 3);
ctx.lineTo(x + dir * 2 + dir * (-5 + armOffset), y - 4);
ctx.stroke();
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '6px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(icon + ' ' + name, x + dir * 2, y - 30);
ctx.textAlign = 'left';
ctx.shadowBlur = 0;
}
// ========== WINNER ==========
function showWinner(winner, loser, isTournamentWin = false) {
const overlay = document.getElementById('winnerOverlay');
const winnerText = document.getElementById('winnerText');
const winnerSub = document.getElementById('winnerSub');
const winnerQuote = document.getElementById('winnerQuote');
if (!winner) {
winnerText.textContent = '🤝 DRAW!';
winnerSub.textContent = 'Both fighters are down!';
winnerQuote.textContent = '';
} else {
const winText = isTournamentWin ? `🏆 TOURNAMENT CHAMPION!` : `🏆 ${winner.icon} ${winner.name} WINS!`;
winnerText.textContent = winText;
winnerSub.textContent = `"${winner.quote || 'Victory!'}"`;
winnerQuote.textContent = isTournamentWin ? `🌟 ${winner.name} is the ULTIMATE CHAMPION!` : `💀 ${loser ? loser.name : 'Opponent'} has been defeated!`;
playCharacterVoice(winner, true);
}
overlay.style.display = 'flex';
createConfetti();
}
function createConfetti() {
const overlay = document.getElementById('winnerOverlay');
const colors = ['#ff4444', '#ffdd44', '#44ff44', '#4444ff', '#ff44ff', '#44ffff'];
for (let i = 0; i < 30; i++) {
const confetti = document.createElement('div');
confetti.style.cssText = `
position: absolute;
width: ${Math.random() * 6 + 3}px;
height: ${Math.random() * 6 + 3}px;
background: ${colors[Math.floor(Math.random() * colors.length)]};
left: ${Math.random() * 100}%;
top: -10px;
border-radius: ${Math.random() > 0.5 ? '50%' : '2px'};
animation: confettiFall ${Math.random() * 2 + 2}s linear forwards;
animation-delay: ${Math.random() * 2}s;
z-index: 31;
`;
overlay.appendChild(confetti);
}
setTimeout(() => {
overlay.querySelectorAll('.confetti').forEach(c => c.remove());
}, 4000);
}
function closeWinner() {
document.getElementById('winnerOverlay').style.display = 'none';
if (isTournament) {
updateTournamentUI();
showScreen('tournamentScreen');
} else {
showScreen('homeScreen');
}
}
function quitFight() {
fightActive = false;
if (fightInterval) clearInterval(fightInterval);
if (frameId) cancelAnimationFrame(frameId);
document.getElementById('winnerOverlay').style.display = 'none';
if (isTournament) {
showScreen('tournamentScreen');
} else {
showScreen('homeScreen');
}
}
// ========== UPDATE MOVE LIST ==========
function updateMoveList() {
const moveList = document.getElementById('moveList');
if (!moveList || !player1Char) return;
let html = `<div class="move-title">⚔️ ${player1Char.name}'s MOVES</div>`;
html += `<div class="move-item"><span class="move-key">⬆⬇⬅➡</span><span class="move-name">Move (Joystick)</span></div>`;
html += `<div class="move-item"><span class="move-key">👊</span><span class="move-name">Punch (${player1Char.punch} dmg)</span></div>`;
html += `<div class="move-item"><span class="move-key">🦵</span><span class="move-name">Kick (${player1Char.kick} dmg)</span></div>`;
html += `<div class="move-item"><span class="move-key">🛡️</span><span class="move-name">Block</span></div>`;
html += `<div class="move-item"><span class="move-key">⭐1</span><span class="move-name">${player1Char.special1.name} (${player1Char.special1.damage} dmg)</span></div>`;
html += `<div class="move-item"><span class="move-key">⭐2</span><span class="move-name">${player1Char.special2.name} (${player1Char.special2.damage} dmg)</span></div>`;
if (player1Char.boss) {
html += `<div class="move-item" style="color:#ffdd44;">👑 BOSS CHARACTER!</div>`;
}
if (is2Player) {
html += `<div class="move-item" style="color:#44aaff;">👥 P2 uses Right Joystick!</div>`;
}
moveList.innerHTML = html;
}
// ========== UI HELPERS ==========
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
const target = document.getElementById(id);
if (target) target.classList.add('active');
if (id === 'characterSelectScreen') {
renderCharacters();
updateSelectStatus();
}
if (id === 'fightScreen') {
setTimeout(() => {
const canvas = document.getElementById('fightCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
updateMoveList();
setupJoystick('joystickAreaP1', 'joystickKnobP1', joystickP1);
if (is2Player) {
setupJoystick('joystickAreaP2', 'joystickKnobP2', joystickP2);
document.getElementById('joystickAreaP2').style.display = 'block';
document.getElementById('p2Controls').style.display = 'flex';
} else {
document.getElementById('joystickAreaP2').style.display = 'none';
document.getElementById('p2Controls').style.display = 'none';
}
}, 100);
}
if (id === 'settingsScreen') {
document.getElementById('soundSetting').textContent = soundEnabled ? 'ON' : 'OFF';
}
if (id === 'tournamentScreen') {
updateTournamentUI();
}
}
function toggleSound() {
soundEnabled = !soundEnabled;
document.getElementById('soundSetting').textContent = soundEnabled ? 'ON' : 'OFF';
if (soundEnabled) {
sayComment('🔊 Sound on!', '🔊');
}
}
function showComingSoon(feature) {
alert(`🔜 ${feature} coming soon!\nStay tuned for updates!`);
}
// ========== INIT ==========
renderCharacters();
updateSelectStatus();
initTournament();
setGameMode('1vAI');
// Add confetti keyframe
const style = document.createElement('style');
style.textContent = `
@keyframes confettiFall {
0% { transform: translateY(-100px) rotate(0deg) scale(1); opacity: 1; }
100% { transform: translateY(700px) rotate(720deg) scale(0.3); opacity: 0; }
}
`;
document.head.appendChild(style);
// Add commentator box
const fightScreen = document.getElementById('fightScreen');
if (fightScreen) {
const commentatorBox = document.createElement('div');
commentatorBox.id = 'commentatorBox';
commentatorBox.style.cssText = `
position: absolute;
bottom: 60px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.85);
border: 2px solid #ffdd44;
border-radius: 14px;
padding: 3px 12px;
font-size: 10px;
font-weight: bold;
color: #ffdd44;
text-align: center;
max-width: 80%;
z-index: 15;
pointer-events: none;
transition: all 0.3s;
box-shadow: 0 0 30px rgba(255, 200, 0, 0.2);
min-height: 24px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.7;
`;
commentatorBox.innerHTML = `<span class="emoji">🎙️</span> <span id="commentatorText">FIGHT!</span>`;
fightScreen.querySelector('.fight-container').appendChild(commentatorBox);
}
function handleResize() {
const canvas = document.getElementById('fightCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
// Re-setup joysticks
setupJoystick('joystickAreaP1', 'joystickKnobP1', joystickP1);
if (is2Player) {
setupJoystick('joystickAreaP2', 'joystickKnobP2', joystickP2);
}
}
window.addEventListener('resize', handleResize);
window.addEventListener('orientationchange', () => {
setTimeout(handleResize, 400);
});
document.addEventListener('DOMContentLoaded', () => {
setTimeout(handleResize, 300);
});
</script>
</body>
</html>Game Source: Stickman Kombat - MK Style
Creator: SonicBear35
Libraries: none
Complexity: complex (2342 lines, 82.2 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: stickman-kombat-sonicbear35" to link back to the original. Then publish at arcadelab.ai/publish.