Dream League Soccer
by SonicBear353420 lines131.3 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>Dream League Soccer</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
body {
background: #0a1a0a;
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, #0f2a0f, #1a3a1a);
border-radius: 0px;
padding: 4px;
box-shadow: 0 20px 60px rgba(0,0,0,0.9);
position: relative;
overflow: hidden;
border: 2px solid #3a7a3a;
display: flex;
flex-direction: column;
touch-action: none;
}
/* LANDSCAPE MODE - FULL SUPPORT */
@media (orientation: landscape) {
#app {
max-width: 100%;
max-height: 100vh;
height: 100vh;
border-radius: 0;
flex-direction: row;
padding: 4px;
}
.match-container {
flex-direction: row !important;
flex-wrap: wrap !important;
}
#matchCanvas {
height: 100% !important;
width: 55% !important;
flex: 1 !important;
}
.match-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;
}
.match-controls .left-btns,
.match-controls .right-btns {
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
gap: 4px !important;
}
.match-controls button {
min-width: 42px !important;
min-height: 34px !important;
font-size: 8px !important;
}
#commentatorBox {
top: 8px !important;
font-size: 10px !important;
padding: 3px 8px !important;
min-height: 20px !important;
}
#joystickArea {
width: 90px !important;
height: 90px !important;
bottom: 15px !important;
left: 8px !important;
}
#joystickKnob {
width: 34px !important;
height: 34px !important;
}
.menu-btn {
width: 42% !important;
font-size: 9px !important;
padding: 3px 8px !important;
}
.small-btn {
width: auto !important;
}
#homeScreen .logo {
font-size: 24px !important;
}
}
@media (min-width: 421px) and (orientation: portrait) {
#app {
border-radius: 40px;
height: 780px;
}
}
/* LOADING SCREEN */
#loadingScreen {
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at 50% 30%, #1a4a1a, #0a1a0a);
z-index: 100;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 0px;
animation: fadeIn 0.5s ease;
}
#loadingScreen .bear {
font-size: 80px;
animation: bounce 1s ease infinite;
}
#loadingScreen .bear-text {
font-size: 28px;
font-weight: bold;
color: #ffdd44;
text-shadow: 0 0 30px #ffaa00, 0 0 60px #ff8800;
margin-top: 5px;
}
#loadingScreen .bear-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-info {
font-size: 9px;
color: #3a5a3a;
margin-top: 8px;
text-align: center;
max-width: 80%;
}
#loadingScreen .load-bar {
width: 200px;
height: 4px;
background: #1a3a1a;
border-radius: 4px;
margin-top: 10px;
overflow: hidden;
border: 1px solid #3a7a3a;
}
#loadingScreen .load-fill {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #ffdd44, #ff8800);
border-radius: 4px;
transition: width 0.3s;
}
#loadingScreen .load-percent {
font-size: 12px;
color: #ffdd44;
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, #0f2a0f, #1a3a1a);
overflow-y: auto;
}
.screen.active {
display: flex;
}
#homeScreen {
justify-content: center;
align-items: center;
gap: 2px;
background: radial-gradient(circle at 50% 30%, #1a4a1a, #0a1a0a);
}
#homeScreen .logo {
font-size: 28px;
font-weight: 900;
color: #ffdd44;
text-shadow: 0 0 30px #ffaa00, 0 0 60px #ff8800;
letter-spacing: 2px;
}
#homeScreen .sub {
font-size: 8px;
color: #aaddaa;
letter-spacing: 3px;
margin-bottom: 4px;
}
.menu-btn {
background: linear-gradient(145deg, #2a6a2a, #1a4a1a);
border: 2px solid #4a9a4a;
color: white;
padding: 5px 14px;
border-radius: 60px;
font-size: 11px;
font-weight: bold;
width: 85%;
text-align: center;
margin: 1px 0;
cursor: pointer;
transition: 0.15s;
box-shadow: 0 2px 0 #0a2a0a;
letter-spacing: 1px;
touch-action: manipulation;
}
.menu-btn:active {
transform: translateY(2px);
box-shadow: none;
}
.small-btn {
padding: 2px 6px;
font-size: 7px;
width: auto;
}
.coin-display {
background: #1a3a1a;
padding: 2px 5px;
border-radius: 30px;
border: 1px solid #ffdd44;
color: #ffdd44;
font-weight: bold;
font-size: 9px;
}
.back-btn {
background: #2a4a2a;
border: none;
color: white;
padding: 2px 5px;
border-radius: 30px;
cursor: pointer;
font-size: 9px;
touch-action: manipulation;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3px;
background: #1a3a1a;
padding: 2px 5px;
border-radius: 30px;
border: 1px solid #3a7a3a;
}
.team-grid {
display: flex;
flex-wrap: wrap;
gap: 2px;
justify-content: center;
margin: 2px 0;
}
.team-card {
background: #1a3a1a;
border: 2px solid #2a5a2a;
border-radius: 8px;
padding: 2px 2px;
width: 40px;
text-align: center;
font-size: 5px;
cursor: pointer;
transition: 0.15s;
touch-action: manipulation;
}
.team-card:active {
transform: scale(0.95);
}
.team-card .crest {
font-size: 12px;
display: block;
}
.team-card .name {
font-size: 4px;
margin-top: 1px;
color: #ccddcc;
}
#matchScreen {
padding: 0;
background: #0a1a0a;
position: relative;
}
.match-container {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
#matchCanvas {
width: 100%;
height: 100%;
background: #2d8a2d;
border-radius: 10px;
display: block;
touch-action: none;
cursor: pointer;
flex: 1;
}
.match-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;
}
.match-controls button {
pointer-events: auto;
background: rgba(0,0,0,0.8);
border: 2px solid #4a9a4a;
color: white;
border-radius: 30px;
padding: 2px 5px;
font-size: 7px;
font-weight: bold;
backdrop-filter: blur(4px);
cursor: pointer;
touch-action: manipulation;
min-width: 24px;
min-height: 24px;
}
.match-controls button:active {
transform: scale(0.9);
}
.match-controls .right-btns {
display: flex;
gap: 2px;
flex-wrap: wrap;
}
.match-controls .left-btns {
display: flex;
gap: 2px;
flex-wrap: wrap;
}
.action-btn {
background: rgba(255, 200, 0, 0.25) !important;
border-color: #ffdd44 !important;
font-size: 8px !important;
padding: 2px 6px !important;
min-width: 30px !important;
min-height: 26px !important;
}
.action-btn:active {
background: rgba(255, 200, 0, 0.6) !important;
}
.knock-btn {
background: rgba(0, 200, 255, 0.25) !important;
border-color: #00ccff !important;
}
.knock-btn:active {
background: rgba(0, 200, 255, 0.6) !important;
}
.danger-btn {
border-color: #ff4444 !important;
background: rgba(255, 50, 50, 0.25) !important;
}
.danger-btn:active {
background: rgba(255, 50, 50, 0.6) !important;
}
.tactic-btn {
border-color: #44ff88 !important;
background: rgba(68, 255, 136, 0.15) !important;
font-size: 6px !important;
padding: 1px 3px !important;
min-width: 22px !important;
min-height: 20px !important;
}
.tactic-btn.active {
background: rgba(68, 255, 136, 0.4) !important;
}
#commentatorBox {
position: absolute;
top: 35px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.85);
border: 2px solid #ffdd44;
border-radius: 14px;
padding: 3px 10px;
font-size: 10px;
font-weight: bold;
color: #ffdd44;
text-align: center;
max-width: 85%;
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;
}
#commentatorBox .emoji {
margin-right: 3px;
font-size: 10px;
}
#joystickArea {
position: absolute;
bottom: 55px;
left: 6px;
width: 80px;
height: 80px;
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);
}
#joystickKnob {
position: absolute;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 220, 50, 0.9), rgba(255, 200, 0, 0.4));
border: 3px solid #ffdd44;
transform: translate(-50%, -50%);
pointer-events: none;
touch-action: none;
box-shadow: 0 0 20px rgba(255, 200, 0, 0.3);
transition: none;
}
#subOverlay {
display: none;
position: absolute;
bottom: 45px;
left: 4px;
right: 4px;
background: rgba(0,0,0,0.95);
padding: 4px;
border-radius: 10px;
border: 2px solid #4a9a4a;
max-height: 110px;
overflow-y: auto;
z-index: 25;
}
#subOverlay .sub-header {
display: flex;
justify-content: space-between;
color: #ffdd44;
font-weight: bold;
margin-bottom: 2px;
font-size: 9px;
}
#subList {
display: flex;
flex-wrap: wrap;
gap: 2px;
}
#subList button {
background: #1a3a1a;
border: 1px solid #4a9a4a;
color: white;
padding: 1px 4px;
border-radius: 10px;
font-size: 6px;
cursor: pointer;
touch-action: manipulation;
flex: 1 0 auto;
min-width: 45px;
text-align: center;
}
#subList button:active {
background: #2a5a2a;
}
.health-bar {
display: inline-block;
width: 14px;
height: 3px;
border-radius: 2px;
background: #4a9a4a;
margin-left: 2px;
}
.health-bar.low {
background: #ff4444;
}
.health-bar.medium {
background: #ffdd44;
}
#celebrationOverlay {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.8);
z-index: 30;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 10px;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.8); }
to { opacity: 1; transform: scale(1); }
}
#celebrationOverlay .trophy {
font-size: 50px;
animation: bounce 1s ease infinite;
}
#celebrationOverlay .win-text {
font-size: 18px;
font-weight: bold;
color: #ffdd44;
text-shadow: 0 0 30px #ffaa00;
margin-top: 5px;
text-align: center;
}
#celebrationOverlay .win-sub {
font-size: 11px;
color: #88dd88;
margin-top: 3px;
text-align: center;
}
@keyframes bounce {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-12px) scale(1.1); }
}
.confetti {
position: absolute;
width: 5px;
height: 5px;
border-radius: 2px;
animation: confettiFall linear forwards;
z-index: 31;
}
@keyframes confettiFall {
0% { transform: translateY(-100px) rotate(0deg) scale(1); opacity: 1; }
100% { transform: translateY(700px) rotate(720deg) scale(0.3); opacity: 0; }
}
#replayOverlay {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.9);
z-index: 35;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 10px;
padding: 8px;
}
#replayOverlay .replay-title {
font-size: 14px;
color: #ffdd44;
margin-bottom: 4px;
}
#replayOverlay .replay-score {
font-size: 10px;
color: #88dd88;
margin-bottom: 6px;
}
#replayCanvas {
width: 95%;
height: 50%;
background: #1a5a1a;
border-radius: 8px;
border: 2px solid #4a9a4a;
}
#replayOverlay .replay-controls {
display: flex;
gap: 6px;
margin-top: 6px;
flex-wrap: wrap;
justify-content: center;
}
#replayOverlay .replay-controls button {
background: #1a3a1a;
border: 2px solid #4a9a4a;
color: white;
padding: 3px 10px;
border-radius: 20px;
cursor: pointer;
touch-action: manipulation;
font-size: 8px;
}
#replayOverlay .replay-controls button:active {
transform: scale(0.9);
}
.formation-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2px;
margin: 2px 0;
}
.formation-slot {
background: #1a3a1a;
border: 1px solid #3a7a3a;
border-radius: 6px;
padding: 2px;
text-align: center;
font-size: 6px;
cursor: pointer;
touch-action: manipulation;
}
.formation-slot:active {
border-color: #ffdd44;
}
.formation-slot .pos {
color: #88dd88;
font-weight: bold;
}
.screen::-webkit-scrollbar {
width: 2px;
}
.screen::-webkit-scrollbar-thumb {
background: #4a9a4a;
border-radius: 10px;
}
.league-standings {
background: #1a3a1a;
border-radius: 8px;
padding: 3px;
margin: 2px 0;
font-size: 7px;
}
.league-standings .row {
display: flex;
justify-content: space-between;
padding: 1px 0;
border-bottom: 1px solid #2a5a2a;
}
.league-standings .header-row {
font-weight: bold;
color: #ffdd44;
border-bottom: 2px solid #ffdd44;
}
.league-select {
background: #1a3a1a;
border: 2px solid #4a9a4a;
color: white;
padding: 2px 4px;
border-radius: 8px;
font-size: 9px;
margin: 2px 0;
width: 100%;
}
.league-select option {
background: #0a1a0a;
}
.transfer-list {
background: #1a3a1a;
border-radius: 8px;
padding: 3px;
margin: 2px 0;
max-height: 100px;
overflow-y: auto;
}
.transfer-item {
display: flex;
justify-content: space-between;
padding: 1px 3px;
border-bottom: 1px solid #2a5a5a;
font-size: 6px;
align-items: center;
}
.transfer-item .name { color: #ffdd44; }
.transfer-item .stats { color: #88dd88; }
.transfer-item .price { color: #4a9a4a; }
.cup-store-item {
display: flex;
justify-content: space-between;
padding: 2px 3px;
background: #1a3a1a;
border-radius: 6px;
margin: 2px 0;
border: 1px solid #2a5a2a;
font-size: 8px;
}
.cup-store-item .achieved {
color: #88dd88;
}
.cup-store-item .not-achieved {
color: #557755;
}
.music-control {
background: #1a3a1a;
border: 1px solid #4a9a4a;
border-radius: 6px;
padding: 3px;
margin: 2px 0;
display: flex;
align-items: center;
gap: 3px;
flex-wrap: wrap;
}
.music-control input[type="file"] {
display: none;
}
.music-control .file-label {
background: #2a6a2a;
padding: 2px 6px;
border-radius: 10px;
font-size: 7px;
cursor: pointer;
border: 1px solid #4a9a4a;
color: white;
}
.music-control .file-label:active {
background: #3a7a3a;
}
.music-control .song-name {
color: #88dd88;
font-size: 6px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 80px;
}
.music-instruction {
font-size: 6px;
color: #88dd88;
padding: 4px;
background: #0a2a0a;
border-radius: 6px;
margin-top: 2px;
text-align: center;
border: 1px solid #2a5a2a;
line-height: 1.5;
}
.music-instruction .highlight {
color: #ffdd44;
}
.music-status {
font-size: 6px;
color: #88dd88;
padding: 2px 4px;
background: #0a1a0a;
border-radius: 4px;
display: inline-block;
}
@media (max-width: 420px) {
#app {
border-radius: 0;
height: 100vh;
max-height: 100vh;
padding: 2px;
}
.menu-btn {
padding: 3px 8px;
font-size: 9px;
}
.match-controls button {
padding: 1px 4px;
font-size: 6px;
min-width: 20px;
min-height: 20px;
}
.action-btn {
padding: 2px 5px !important;
min-width: 26px !important;
min-height: 22px !important;
font-size: 7px !important;
}
#commentatorBox {
font-size: 8px;
padding: 2px 6px;
top: 28px;
min-height: 18px;
}
#joystickArea {
width: 60px !important;
height: 60px !important;
bottom: 45px !important;
left: 4px !important;
}
#joystickKnob {
width: 24px !important;
height: 24px !important;
}
#loadingScreen .bear {
font-size: 60px !important;
}
#loadingScreen .bear-text {
font-size: 22px !important;
}
}
@media (max-height: 600px) {
#joystickArea {
width: 50px !important;
height: 50px !important;
bottom: 35px !important;
left: 3px !important;
}
#joystickKnob {
width: 20px !important;
height: 20px !important;
}
.match-controls button {
min-width: 18px;
min-height: 18px;
font-size: 5px;
padding: 1px 3px;
}
}
</style>
</head>
<body>
<div id="app">
<!-- LOADING SCREEN -->
<div id="loadingScreen">
<div class="bear">๐ป</div>
<div class="bear-text">SONIC BEAR 35</div>
<div class="bear-sub">Dream League Soccer</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 class="load-info">
๐ต Download music from <span style="color:#ffdd44;">audio.com</span><br>
Then upload in Settings โ UPLOAD MP3
</div>
</div>
<!-- HOME SCREEN -->
<div id="homeScreen" class="screen">
<div class="logo">โฝ DREAM</div>
<div class="sub">LEAGUE SOCCER</div>
<div style="display:flex; gap:2px; margin-bottom:3px; flex-wrap:wrap; justify-content:center;">
<span class="coin-display" id="coinDisplay">๐ช 1,000,000</span>
<span class="coin-display" style="border-color:#88dd88;" id="gemDisplay">๐ 50</span>
<span class="coin-display" style="border-color:#4a9a4a;" id="trophyDisplay">๐ 0</span>
</div>
<button class="menu-btn" onclick="showScreen('teamSelectScreen')">โถ PLAY MATCH</button>
<button class="menu-btn" onclick="showScreen('leagueSelectScreen')">๐ LEAGUES</button>
<button class="menu-btn" onclick="showScreen('championsLeagueScreen')">๐ CHAMPIONS LEAGUE</button>
<button class="menu-btn" onclick="showScreen('clubWorldCupScreen')">๐ CLUB WORLD CUP</button>
<button class="menu-btn" onclick="showScreen('transferScreen')">๐ TRANSFERS</button>
<button class="menu-btn" onclick="showScreen('trainingScreen')">โก TRAINING</button>
<button class="menu-btn" onclick="showScreen('formationScreen')">๐ FORMATION</button>
<button class="menu-btn" onclick="showScreen('cupStoreScreen')">๐ CUP STORE</button>
<button class="menu-btn small-btn" onclick="showScreen('settingsScreen')">โ๏ธ SETTINGS</button>
<div style="margin-top:3px; font-size:5px; color:#557755;">FIFA World Cupโข ยท FIFPRO</div>
<div style="font-size:4px; color:#3a5a3a; margin-top:1px;">Graphic Design by Flex Inc</div>
</div>
<!-- TEAM SELECT -->
<div id="teamSelectScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐๏ธ SELECT TEAM</span>
<span class="coin-display" style="font-size:7px;">๐ช 1M</span>
</div>
<div class="team-grid" id="teamGrid"></div>
<button class="menu-btn" style="margin-top:3px;" onclick="startMatch('friendly')">โ๏ธ KICK OFF</button>
<div style="font-size:5px; color:#557755; text-align:center; margin-top:2px;">Tap a team to select</div>
</div>
<!-- MATCH SCREEN -->
<div id="matchScreen" class="screen">
<div class="match-container">
<div id="commentatorBox">
<span class="emoji">๐๏ธ</span>
<span id="commentatorText">Welcome to the match!</span>
</div>
<div id="joystickArea">
<div id="joystickKnob"></div>
</div>
<canvas id="matchCanvas"></canvas>
<div id="celebrationOverlay">
<div class="trophy">๐</div>
<div class="win-text" id="winText">CHAMPIONS!</div>
<div class="win-sub" id="winSub">You won the tournament!</div>
<button class="menu-btn small-btn" style="margin-top:8px; width:60%;" onclick="closeCelebration()">๐ CONTINUE</button>
</div>
<div id="replayOverlay">
<div class="replay-title">๐ REPLAY</div>
<div class="replay-score" id="replayScore">0-0</div>
<canvas id="replayCanvas"></canvas>
<div class="replay-controls">
<button onclick="closeReplay()">โ CLOSE</button>
<button onclick="saveReplay()">๐พ SAVE</button>
</div>
</div>
<div class="match-controls">
<div class="left-btns">
<button class="danger-btn" onclick="quitMatch()">๐ช</button>
<button onclick="showSubstitute()">๐</button>
<button class="tactic-btn" onclick="setTactic('balanced')" id="tacticBalanced">โ๏ธ</button>
<button class="tactic-btn" onclick="setTactic('attack')" id="tacticAttack">โก</button>
<button class="tactic-btn" onclick="setTactic('defence')" id="tacticDefence">๐ก๏ธ</button>
</div>
<div class="right-btns">
<button class="action-btn" id="passBtn" onmousedown="doPass()" ontouchstart="doPass()">โฌ</button>
<button class="action-btn" id="shootBtn" onmousedown="doShoot()" ontouchstart="doShoot()">โก</button>
<button class="action-btn" id="tackleBtn" onmousedown="doTackle()" ontouchstart="doTackle()">๐ก๏ธ</button>
<button class="action-btn knock-btn" id="knockBtn" onmousedown="doKnock()" ontouchstart="doKnock()">๐จ</button>
<button class="action-btn" id="secondPressBtn" onmousedown="doSecondPress()" ontouchstart="doSecondPress()">โฉ</button>
</div>
</div>
<div id="subOverlay">
<div class="sub-header">
<span>SUBSTITUTES</span>
<button onclick="document.getElementById('subOverlay').style.display='none'" style="background:none;border:none;color:white;font-size:11px;">โ</button>
</div>
<div id="subList"></div>
</div>
</div>
</div>
<!-- LEAGUE SELECT -->
<div id="leagueSelectScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ SELECT LEAGUE</span>
<span></span>
</div>
<select class="league-select" id="leagueSelector" onchange="loadLeagueStandings()">
<option value="premier">Premier League</option>
<option value="laliga">La Liga</option>
<option value="seriea">Serie A</option>
<option value="bundesliga">Bundesliga</option>
<option value="ligue1">Ligue 1</option>
</select>
<div id="leagueStandings" class="league-standings"></div>
<button class="menu-btn small-btn" style="margin-top:3px;" onclick="startLeagueMatch()">โถ PLAY LEAGUE MATCH</button>
<div style="font-size:5px; color:#557755; margin-top:2px;">Win 9 matches to win the league!</div>
<div style="font-size:5px; color:#557755; margin-top:2px;" id="leagueProgress">Progress: 0/9 wins</div>
</div>
<!-- CHAMPIONS LEAGUE -->
<div id="championsLeagueScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ CHAMPIONS LEAGUE</span>
<span></span>
</div>
<div style="background:#1a3a1a; border-radius:8px; padding:4px; margin:2px 0;">
<div style="color:#ffdd44; font-weight:bold; font-size:9px; text-align:center;">KNOCKOUT STAGE</div>
<div id="clProgress" style="font-size:7px; padding:2px 0; color:#88dd88; text-align:center;">Progress: 0/4 wins</div>
<div style="font-size:7px; padding:2px 0; border-bottom:1px solid #2a5a2a;" id="clStage1">โฌ Round of 16</div>
<div style="font-size:7px; padding:2px 0; border-bottom:1px solid #2a5a2a;" id="clStage2">โฌ Quarter Final</div>
<div style="font-size:7px; padding:2px 0; border-bottom:1px solid #2a5a2a;" id="clStage3">โฌ Semi Final</div>
<div style="font-size:7px; padding:2px 0; color:#ffdd44;" id="clStage4">โฌ FINAL</div>
</div>
<button class="menu-btn small-btn" onclick="startChampionsLeagueMatch()">โถ PLAY CHAMPIONS LEAGUE</button>
<div style="font-size:5px; color:#557755; margin-top:2px;">Win 4 matches to lift the trophy!</div>
</div>
<!-- CLUB WORLD CUP -->
<div id="clubWorldCupScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ CLUB WORLD CUP</span>
<span></span>
</div>
<div style="background:#1a3a1a; border-radius:8px; padding:4px; margin:2px 0;">
<div style="color:#ffdd44; font-weight:bold; font-size:9px; text-align:center;">FIFA CLUB WORLD CUP</div>
<div id="cwcProgress" style="font-size:7px; padding:2px 0; color:#88dd88; text-align:center;">Progress: 0/3 wins</div>
<div style="font-size:7px; padding:2px 0; border-bottom:1px solid #2a5a2a;" id="cwcStage1">โฌ Quarter Final</div>
<div style="font-size:7px; padding:2px 0; border-bottom:1px solid #2a5a2a;" id="cwcStage2">โฌ Semi Final</div>
<div style="font-size:7px; padding:2px 0; color:#ffdd44;" id="cwcStage3">โฌ FINAL</div>
</div>
<button class="menu-btn small-btn" onclick="startClubWorldCupMatch()">โถ PLAY WORLD CUP</button>
<div style="font-size:5px; color:#557755; margin-top:2px;">Win 3 matches to become World Champions!</div>
</div>
<!-- TRANSFERS -->
<div id="transferScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ TRANSFERS</span>
<span></span>
</div>
<div style="font-size:7px; color:#88dd88; text-align:center; margin-bottom:2px;">Available Players</div>
<div class="transfer-list" id="transferList"></div>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="refreshTransfers()">๐ REFRESH</button>
<div style="font-size:5px; color:#557755; margin-top:2px;">New players appear every match!</div>
</div>
<!-- TRAINING -->
<div id="trainingScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">โก TRAINING</span>
<span></span>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:2px; margin-top:3px;">
<button class="menu-btn small-btn" onclick="startTraining('free')">๐ FREE</button>
<button class="menu-btn small-btn" onclick="startTraining('freekick')">๐ฅ
FREE KICK</button>
<button class="menu-btn small-btn" onclick="startTraining('corner')">๐ CORNER</button>
<button class="menu-btn small-btn" onclick="startTraining('penalty')">โฝ PENALTY</button>
</div>
<div style="margin-top:4px; background:#1a3a1a; padding:3px; border-radius:8px;">
<span class="text-gold">๐ Gems: 50</span><br>
<span class="text-green" style="font-size:7px;">โฌ Upgrade player (+1) cost: 10 gems</span>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="upgradePlayer()">โฌ UPGRADE (10๐)</button>
</div>
</div>
<!-- FORMATION -->
<div id="formationScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ FORMATION 4-3-3</span>
<span></span>
</div>
<div class="formation-grid" id="formationGrid"></div>
<div style="margin-top:3px; background:#1a3a1a; padding:3px; border-radius:8px;">
<div class="text-gold" style="font-size:7px;">AI TEAM FORMATION (4-4-2)</div>
<div style="display:flex; gap:1px; justify-content:center; flex-wrap:wrap; font-size:5px;">
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">GK</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">LB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">CB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">CB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">RB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">LM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">CM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">CM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">RM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">ST</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 2px;">ST</span>
</div>
</div>
</div>
<!-- CUP STORE -->
<div id="cupStoreScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">๐ CUP STORE</span>
<span></span>
</div>
<div style="font-size:7px; color:#88dd88; text-align:center; margin-bottom:2px;">Achievements</div>
<div id="cupStoreList"></div>
</div>
<!-- SETTINGS -->
<div id="settingsScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:9px;">โ๏ธ SETTINGS</span>
<span></span>
</div>
<div style="margin-top:6px; font-size:9px;">
<div>๐ต Sound: <span class="text-gold" id="soundSetting">ON</span></div>
<div>๐ฑ Controls: <span class="text-gold">Touch + Joystick</span></div>
<div>โฑ๏ธ Match time: <span class="text-gold">3 min (90:00)</span></div>
<div>๐ช Coins: <span class="text-gold" id="settingsCoins">1,000,000</span></div>
<div>๐ Trophies: <span class="text-gold" id="settingsTrophies">0</span></div>
<div>๐พ Saved Replays: <span class="text-gold" id="savedReplaysCount">0</span></div>
<div id="musicStatusDisplay" class="music-status">๐ต Music: No song loaded</div>
<div class="music-control">
<span style="font-size:7px; color:#88dd88;">๐ต MUSIC:</span>
<label class="file-label" for="musicFile">๐ UPLOAD MP3</label>
<input type="file" id="musicFile" accept=".mp3,.wav,.ogg" onchange="uploadMusic(event)" />
<span class="song-name" id="songName">No song selected</span>
<button class="small-btn" style="background:#2a4a2a;border:1px solid #4a9a4a;color:white;padding:2px 5px;border-radius:10px;font-size:6px;cursor:pointer;" onclick="playMusic()">โถ PLAY</button>
<button class="small-btn" style="background:#2a4a2a;border:1px solid #4a9a4a;color:white;padding:2px 5px;border-radius:10px;font-size:6px;cursor:pointer;" onclick="stopMusic()">โน STOP</button>
<button class="small-btn" style="background:#4a2a2a;border:1px solid #ff4444;color:white;padding:2px 5px;border-radius:10px;font-size:6px;cursor:pointer;" onclick="deleteMusic()">๐ DELETE</button>
</div>
<div class="music-instruction">
๐ <span class="highlight">HOW TO ADD MUSIC:</span><br>
1๏ธโฃ Download MP3 from <span class="highlight">audio.com</span> or any MP3 site<br>
2๏ธโฃ Click <span class="highlight">"UPLOAD MP3"</span> and select your file<br>
3๏ธโฃ Press <span class="highlight">PLAY</span> to listen (stops during matches to prevent lag)<br>
4๏ธโฃ Music stays permanently until you <span class="highlight">DELETE</span> it
</div>
<button class="menu-btn small-btn" style="margin-top:3px;" onclick="toggleSound()">๐ TOGGLE SOUND</button>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="viewReplays()">๐น VIEW REPLAYS</button>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="showComingSoon('Live Multiplayer')">๐ LIVE MULTIPLAYER</button>
<button class="menu-btn small-btn" style="margin-top:2px;" onclick="showComingSoon('More Games')">๐ฎ MORE GAMES</button>
</div>
<div style="margin-top:4px; font-size:5px; color:#557755; text-align:center;">
๐ก Download songs from <span style="color:#ffdd44;">audio.com</span> or any MP3 site
</div>
</div>
</div>
<script>
// ========== LOADING SCREEN ==========
let loadingProgress = 0;
const loadFill = document.getElementById('loadFill');
const loadPercent = document.getElementById('loadPercent');
const loadingScreen = document.getElementById('loadingScreen');
// Simulate loading assets
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);
// Show tap to start
document.querySelector('.tap-text').style.display = 'block';
}
}, 100);
// Tap to start
loadingScreen.addEventListener('click', function() {
if (loadingProgress >= 100) {
this.style.display = 'none';
document.getElementById('homeScreen').classList.add('active');
renderTeams();
updateCoins();
loadLeagueStandings();
updateChampionsLeagueUI();
updateClubWorldCupUI();
refreshTransfers();
updateCupStore();
setTactic('balanced');
loadStoredMusic();
sayComment("๐๏ธ Welcome to Dream League Soccer!", "๐๏ธ");
}
});
// ========== COMPLETE GAME ENGINE ==========
// EVERY SHOT GOES IN THE GOAL - FIXED!
// ========== REAL PLAYER DATA (shortened for performance) ==========
const realPlayers = {
madrid: [
{ name: 'Courtois', pos: 'GK', rating: 91, number: 1, shooting: 20, defence: 30, tackling: 25, goalkeeping: 92 },
{ name: 'Carvajal', pos: 'RB', rating: 87, number: 2, shooting: 60, defence: 85, tackling: 82, goalkeeping: 10 },
{ name: 'Militao', pos: 'CB', rating: 88, number: 3, shooting: 40, defence: 88, tackling: 85, goalkeeping: 10 },
{ name: 'Alaba', pos: 'CB', rating: 87, number: 4, shooting: 55, defence: 86, tackling: 83, goalkeeping: 10 },
{ name: 'Mendy', pos: 'LB', rating: 85, number: 23, shooting: 50, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Modric', pos: 'CM', rating: 90, number: 10, shooting: 78, defence: 70, tackling: 65, goalkeeping: 10 },
{ name: 'Valverde', pos: 'CM', rating: 88, number: 15, shooting: 82, defence: 72, tackling: 70, goalkeeping: 10 },
{ name: 'Vinicius Jr', pos: 'LW', rating: 92, number: 7, shooting: 88, defence: 30, tackling: 25, goalkeeping: 10 },
{ name: 'Rodrygo', pos: 'RW', rating: 88, number: 11, shooting: 85, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Bellingham', pos: 'ST', rating: 90, number: 5, shooting: 87, defence: 60, tackling: 55, goalkeeping: 10 },
{ name: 'Joselu', pos: 'ST', rating: 82, number: 14, shooting: 82, defence: 40, tackling: 35, goalkeeping: 10 }
],
barcelona: [
{ name: 'Ter Stegen', pos: 'GK', rating: 89, number: 1, shooting: 20, defence: 30, tackling: 25, goalkeeping: 90 },
{ name: 'Kounde', pos: 'RB', rating: 86, number: 23, shooting: 55, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Araujo', pos: 'CB', rating: 88, number: 4, shooting: 40, defence: 87, tackling: 84, goalkeeping: 10 },
{ name: 'Balde', pos: 'LB', rating: 84, number: 3, shooting: 50, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'Pedri', pos: 'CM', rating: 87, number: 8, shooting: 75, defence: 65, tackling: 60, goalkeeping: 10 },
{ name: 'Gavi', pos: 'CM', rating: 85, number: 6, shooting: 72, defence: 70, tackling: 68, goalkeeping: 10 },
{ name: 'De Jong', pos: 'CM', rating: 88, number: 21, shooting: 70, defence: 75, tackling: 72, goalkeeping: 10 },
{ name: 'Raphinha', pos: 'RW', rating: 86, number: 11, shooting: 82, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Lewandowski', pos: 'ST', rating: 90, number: 9, shooting: 90, defence: 45, tackling: 40, goalkeeping: 10 },
{ name: 'Felix', pos: 'LW', rating: 84, number: 14, shooting: 80, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Yamal', pos: 'RW', rating: 80, number: 27, shooting: 78, defence: 30, tackling: 25, goalkeeping: 10 }
],
liverpool: [
{ name: 'Alisson', pos: 'GK', rating: 90, number: 1, shooting: 20, defence: 30, tackling: 25, goalkeeping: 91 },
{ name: 'Alexander-Arnold', pos: 'RB', rating: 88, number: 66, shooting: 72, defence: 78, tackling: 75, goalkeeping: 10 },
{ name: 'Van Dijk', pos: 'CB', rating: 90, number: 4, shooting: 45, defence: 90, tackling: 87, goalkeeping: 10 },
{ name: 'Konate', pos: 'CB', rating: 86, number: 5, shooting: 40, defence: 86, tackling: 83, goalkeeping: 10 },
{ name: 'Robertson', pos: 'LB', rating: 87, number: 26, shooting: 58, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Salah', pos: 'RW', rating: 90, number: 11, shooting: 88, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Nunez', pos: 'ST', rating: 86, number: 9, shooting: 84, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Diaz', pos: 'LW', rating: 85, number: 7, shooting: 82, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Jota', pos: 'ST', rating: 84, number: 20, shooting: 83, defence: 40, tackling: 35, goalkeeping: 10 }
],
mancity: [
{ name: 'Ederson', pos: 'GK', rating: 89, number: 31, shooting: 25, defence: 30, tackling: 25, goalkeeping: 89 },
{ name: 'Walker', pos: 'RB', rating: 86, number: 2, shooting: 55, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Stones', pos: 'CB', rating: 87, number: 5, shooting: 45, defence: 86, tackling: 83, goalkeeping: 10 },
{ name: 'Dias', pos: 'CB', rating: 89, number: 3, shooting: 40, defence: 89, tackling: 86, goalkeeping: 10 },
{ name: 'Gvardiol', pos: 'LB', rating: 86, number: 24, shooting: 55, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Rodri', pos: 'CM', rating: 90, number: 16, shooting: 72, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'De Bruyne', pos: 'CM', rating: 93, number: 17, shooting: 88, defence: 60, tackling: 55, goalkeeping: 10 },
{ name: 'Foden', pos: 'CM', rating: 88, number: 47, shooting: 82, defence: 50, tackling: 45, goalkeeping: 10 },
{ name: 'Haaland', pos: 'ST', rating: 94, number: 9, shooting: 93, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Grealish', pos: 'LW', rating: 86, number: 10, shooting: 78, defence: 35, tackling: 30, goalkeeping: 10 }
],
bayern: [
{ name: 'Neuer', pos: 'GK', rating: 91, number: 1, shooting: 20, defence: 30, tackling: 25, goalkeeping: 92 },
{ name: 'Kimmich', pos: 'RB', rating: 89, number: 6, shooting: 70, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'De Ligt', pos: 'CB', rating: 87, number: 4, shooting: 40, defence: 87, tackling: 84, goalkeeping: 10 },
{ name: 'Davies', pos: 'LB', rating: 85, number: 19, shooting: 52, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'Kane', pos: 'ST', rating: 91, number: 9, shooting: 90, defence: 50, tackling: 45, goalkeeping: 10 },
{ name: 'Musiala', pos: 'CM', rating: 87, number: 42, shooting: 80, defence: 55, tackling: 50, goalkeeping: 10 },
{ name: 'Sanรฉ', pos: 'RW', rating: 87, number: 10, shooting: 84, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Coman', pos: 'LW', rating: 86, number: 11, shooting: 80, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Mรผller', pos: 'ST', rating: 88, number: 25, shooting: 84, defence: 55, tackling: 50, goalkeeping: 10 }
],
psg: [
{ name: 'Donnarumma', pos: 'GK', rating: 89, number: 99, shooting: 20, defence: 30, tackling: 25, goalkeeping: 90 },
{ name: 'Hakimi', pos: 'RB', rating: 87, number: 2, shooting: 68, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'Marquinhos', pos: 'CB', rating: 88, number: 5, shooting: 40, defence: 88, tackling: 85, goalkeeping: 10 },
{ name: 'Hernandez', pos: 'LB', rating: 85, number: 21, shooting: 50, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Mbappรฉ', pos: 'ST', rating: 94, number: 7, shooting: 92, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Dembรฉlรฉ', pos: 'RW', rating: 87, number: 10, shooting: 82, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Kolo Muani', pos: 'ST', rating: 85, number: 23, shooting: 82, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Barcola', pos: 'LW', rating: 82, number: 29, shooting: 78, defence: 30, tackling: 25, goalkeeping: 10 }
]
};
const teamData = {
'Real Madrid': { players: realPlayers.madrid, crest: '๐ช๐ธ' },
'Barcelona': { players: realPlayers.barcelona, crest: '๐ช๐ธ' },
'Liverpool': { players: realPlayers.liverpool, crest: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ' },
'Man City': { players: realPlayers.mancity, crest: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ' },
'Bayern': { players: realPlayers.bayern, crest: '๐ฉ๐ช' },
'PSG': { players: realPlayers.psg, crest: '๐ซ๐ท' },
};
const teams = [
{ name: 'Real Madrid', crest: '๐ช๐ธ', rating: 92 },
{ name: 'Barcelona', crest: '๐ช๐ธ', rating: 88 },
{ name: 'Liverpool', crest: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ', rating: 86 },
{ name: 'Man City', crest: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ', rating: 90 },
{ name: 'Bayern', crest: '๐ฉ๐ช', rating: 87 },
{ name: 'PSG', crest: '๐ซ๐ท', rating: 85 },
{ name: 'Milan', crest: '๐ฎ๐น', rating: 83 },
{ name: 'Ajax', crest: '๐ณ๐ฑ', rating: 80 },
{ name: 'Benfica', crest: '๐ต๐น', rating: 78 },
{ name: 'Nigeria', crest: '๐ณ๐ฌ', rating: 74 },
{ name: 'Brazil', crest: '๐ง๐ท', rating: 93 },
{ name: 'Argentina', crest: '๐ฆ๐ท', rating: 91 },
{ name: 'Germany', crest: '๐ฉ๐ช', rating: 88 },
{ name: 'France', crest: '๐ซ๐ท', rating: 89 },
{ name: 'England', crest: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ', rating: 87 },
{ name: 'Portugal', crest: '๐ต๐น', rating: 84 },
];
const defaultPlayers = [
{ name: 'Player 1', pos: 'GK', rating: 80, number: 1, shooting: 20, defence: 30, tackling: 25, goalkeeping: 80 },
{ name: 'Player 2', pos: 'LB', rating: 78, number: 2, shooting: 50, defence: 78, tackling: 75, goalkeeping: 10 },
{ name: 'Player 3', pos: 'CB', rating: 82, number: 3, shooting: 40, defence: 82, tackling: 80, goalkeeping: 10 },
{ name: 'Player 4', pos: 'CB', rating: 81, number: 4, shooting: 35, defence: 81, tackling: 78, goalkeeping: 10 },
{ name: 'Player 5', pos: 'RB', rating: 79, number: 5, shooting: 50, defence: 79, tackling: 76, goalkeeping: 10 },
{ name: 'Player 6', pos: 'LM', rating: 76, number: 6, shooting: 70, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Player 7', pos: 'CM', rating: 80, number: 7, shooting: 72, defence: 65, tackling: 60, goalkeeping: 10 },
{ name: 'Player 8', pos: 'CM', rating: 78, number: 8, shooting: 68, defence: 60, tackling: 58, goalkeeping: 10 },
{ name: 'Player 9', pos: 'RM', rating: 77, number: 9, shooting: 70, defence: 40, tackling: 35, goalkeeping: 10 },
{ name: 'Player 10', pos: 'LW', rating: 82, number: 10, shooting: 78, defence: 30, tackling: 25, goalkeeping: 10 },
{ name: 'Player 11', pos: 'ST', rating: 84, number: 11, shooting: 82, defence: 35, tackling: 30, goalkeeping: 10 },
{ name: 'Player 12', pos: 'RW', rating: 80, number: 12, shooting: 76, defence: 30, tackling: 25, goalkeeping: 10 }
];
// ========== LEAGUE DATA ==========
const leagueData = {
premier: {
name: 'Premier League',
teams: ['Man City', 'Liverpool', 'Arsenal', 'Chelsea', 'Man Utd', 'Tottenham', 'Newcastle', 'Aston Villa'],
standings: [
{ team: 'Man City', played: 8, won: 6, drawn: 2, lost: 0, gf: 18, ga: 6, pts: 20 },
{ team: 'Liverpool', played: 8, won: 6, drawn: 1, lost: 1, gf: 16, ga: 7, pts: 19 },
{ team: 'Arsenal', played: 8, won: 5, drawn: 2, lost: 1, gf: 15, ga: 8, pts: 17 },
{ team: 'Chelsea', played: 8, won: 4, drawn: 3, lost: 1, gf: 14, ga: 9, pts: 15 },
{ team: 'Man Utd', played: 8, won: 4, drawn: 2, lost: 2, gf: 12, ga: 10, pts: 14 },
{ team: 'Tottenham', played: 8, won: 3, drawn: 3, lost: 2, gf: 11, ga: 11, pts: 12 },
{ team: 'Newcastle', played: 8, won: 3, drawn: 2, lost: 3, gf: 10, ga: 12, pts: 11 },
{ team: 'Aston Villa', played: 8, won: 2, drawn: 3, lost: 3, gf: 9, ga: 13, pts: 9 }
],
reward: 5000000
},
laliga: {
name: 'La Liga',
teams: ['Real Madrid', 'Barcelona', 'Atletico Madrid', 'Real Sociedad', 'Athletic Bilbao', 'Sevilla', 'Villarreal', 'Betis'],
standings: [
{ team: 'Real Madrid', played: 8, won: 7, drawn: 1, lost: 0, gf: 22, ga: 5, pts: 22 },
{ team: 'Barcelona', played: 8, won: 6, drawn: 1, lost: 1, gf: 18, ga: 8, pts: 19 },
{ team: 'Atletico Madrid', played: 8, won: 5, drawn: 2, lost: 1, gf: 16, ga: 9, pts: 17 },
{ team: 'Real Sociedad', played: 8, won: 4, drawn: 2, lost: 2, gf: 13, ga: 11, pts: 14 },
{ team: 'Athletic Bilbao', played: 8, won: 3, drawn: 3, lost: 2, gf: 12, ga: 12, pts: 12 },
{ team: 'Sevilla', played: 8, won: 3, drawn: 2, lost: 3, gf: 11, ga: 13, pts: 11 },
{ team: 'Villarreal', played: 8, won: 2, drawn: 3, lost: 3, gf: 10, ga: 14, pts: 9 },
{ team: 'Betis', played: 8, won: 2, drawn: 2, lost: 4, gf: 9, ga: 16, pts: 8 }
],
reward: 4000000
},
seriea: {
name: 'Serie A',
teams: ['Milan', 'Inter Milan', 'Juventus', 'Napoli', 'Roma', 'Lazio', 'Atalanta', 'Fiorentina'],
standings: [
{ team: 'Inter Milan', played: 8, won: 6, drawn: 2, lost: 0, gf: 19, ga: 6, pts: 20 },
{ team: 'Milan', played: 8, won: 6, drawn: 1, lost: 1, gf: 17, ga: 8, pts: 19 },
{ team: 'Juventus', played: 8, won: 5, drawn: 2, lost: 1, gf: 15, ga: 9, pts: 17 },
{ team: 'Napoli', played: 8, won: 4, drawn: 3, lost: 1, gf: 14, ga: 10, pts: 15 },
{ team: 'Roma', played: 8, won: 4, drawn: 2, lost: 2, gf: 13, ga: 11, pts: 14 },
{ team: 'Lazio', played: 8, won: 3, drawn: 3, lost: 2, gf: 12, ga: 12, pts: 12 },
{ team: 'Atalanta', played: 8, won: 3, drawn: 2, lost: 3, gf: 11, ga: 14, pts: 11 },
{ team: 'Fiorentina', played: 8, won: 2, drawn: 3, lost: 3, gf: 10, ga: 15, pts: 9 }
],
reward: 3500000
},
bundesliga: {
name: 'Bundesliga',
teams: ['Bayern', 'Dortmund', 'Leipzig', 'Leverkusen', 'Frankfurt', 'Stuttgart', 'Wolfsburg', 'Gladbach'],
standings: [
{ team: 'Bayern', played: 8, won: 7, drawn: 1, lost: 0, gf: 24, ga: 4, pts: 22 },
{ team: 'Dortmund', played: 8, won: 6, drawn: 1, lost: 1, gf: 19, ga: 8, pts: 19 },
{ team: 'Leipzig', played: 8, won: 5, drawn: 2, lost: 1, gf: 17, ga: 9, pts: 17 },
{ team: 'Leverkusen', played: 8, won: 4, drawn: 2, lost: 2, gf: 15, ga: 11, pts: 14 },
{ team: 'Frankfurt', played: 8, won: 3, drawn: 3, lost: 2, gf: 13, ga: 12, pts: 12 },
{ team: 'Stuttgart', played: 8, won: 3, drawn: 2, lost: 3, gf: 12, ga: 14, pts: 11 },
{ team: 'Wolfsburg', played: 8, won: 2, drawn: 3, lost: 3, gf: 11, ga: 15, pts: 9 },
{ team: 'Gladbach', played: 8, won: 2, drawn: 2, lost: 4, gf: 10, ga: 17, pts: 8 }
],
reward: 3000000
},
ligue1: {
name: 'Ligue 1',
teams: ['PSG', 'Marseille', 'Monaco', 'Lyon', 'Lille', 'Rennes', 'Nice', 'Lens'],
standings: [
{ team: 'PSG', played: 8, won: 7, drawn: 1, lost: 0, gf: 23, ga: 5, pts: 22 },
{ team: 'Marseille', played: 8, won: 5, drawn: 2, lost: 1, gf: 17, ga: 9, pts: 17 },
{ team: 'Monaco', played: 8, won: 5, drawn: 1, lost: 2, gf: 16, ga: 10, pts: 16 },
{ team: 'Lyon', played: 8, won: 4, drawn: 2, lost: 2, gf: 14, ga: 11, pts: 14 },
{ team: 'Lille', played: 8, won: 3, drawn: 3, lost: 2, gf: 13, ga: 12, pts: 12 },
{ team: 'Rennes', played: 8, won: 3, drawn: 2, lost: 3, gf: 12, ga: 14, pts: 11 },
{ team: 'Nice', played: 8, won: 2, drawn: 3, lost: 3, gf: 11, ga: 15, pts: 9 },
{ team: 'Lens', played: 8, won: 2, drawn: 2, lost: 4, gf: 10, ga: 17, pts: 8 }
],
reward: 2500000
}
};
// ========== CUP DATA ==========
const cupData = [
{ id: 'fifa', name: 'FIFA World Cup', icon: '๐', achieved: false },
{ id: 'champs', name: 'Champions League', icon: '๐', achieved: false },
{ id: 'clubwc', name: 'Club World Cup', icon: '๐', achieved: false },
{ id: 'premier', name: 'Premier League', icon: '๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ', achieved: false },
{ id: 'laliga', name: 'La Liga', icon: '๐ช๐ธ', achieved: false },
{ id: 'seriea', name: 'Serie A', icon: '๐ฎ๐น', achieved: false },
{ id: 'bundesliga', name: 'Bundesliga', icon: '๐ฉ๐ช', achieved: false },
{ id: 'ligue1', name: 'Ligue 1', icon: '๐ซ๐ท', achieved: false }
];
// ========== GAME STATE ==========
let selectedTeam = teams[0];
let matchActive = false;
let matchTime = 0;
let matchInterval = null;
let scoreHome = 0;
let scoreAway = 0;
let coins = 1000000;
let gems = 50;
let trophies = 0;
let currentPlayerIndex = 0;
let gameTime = 0;
let frameId = null;
let commentatorTimeout = null;
let homeTeamPlayers = [];
let awayTeamPlayers = [];
let currentMatchType = 'friendly';
let leagueWins = 0;
let currentLeague = 'premier';
let championsLeagueStage = 0;
let clubWorldCupStage = 0;
let joystickActive = false;
let joystickX = 0;
let joystickY = 0;
let ball = { x: 210, y: 390, vx: 0, vy: 0 };
let isSetPiece = false;
let setPieceType = '';
let setPiecePosition = { x: 0, y: 0 };
let isTrainingMode = false;
let trainingType = '';
let soundEnabled = true;
let savedReplays = [];
let currentReplay = null;
let referee = { x: 210, y: 390, whistle: false };
let foulCount = 0;
let yellowCards = 0;
let redCards = 0;
let isPenalty = false;
let transferList = [];
let matchEvents = [];
let gameClock = 0;
let totalMatchTime = 180;
let currentTactic = 'balanced';
let isSecondPress = false;
let shootPressure = 0;
let goalScoredRecently = false;
let musicFile = null;
let musicURL = null;
let audioElement = null;
let musicLoaded = false;
let musicStored = false;
let musicPausedForMatch = false;
// ========== MUSIC SYSTEM - OPTIMIZED ==========
function uploadMusic(event) {
const file = event.target.files[0];
if (file) {
musicFile = file;
document.getElementById('songName').textContent = file.name;
musicURL = URL.createObjectURL(file);
if (audioElement) {
audioElement.src = musicURL;
audioElement.load();
}
musicLoaded = true;
musicStored = true;
document.getElementById('musicStatusDisplay').textContent = `๐ต Music: ${file.name}`;
try {
const reader = new FileReader();
reader.onload = function(e) {
localStorage.setItem('dreamLeagueMusic', e.target.result);
localStorage.setItem('dreamLeagueMusicName', file.name);
};
reader.readAsDataURL(file);
} catch(e) {}
sayComment(`๐ต ${file.name} loaded!`, '๐ต');
}
}
function loadStoredMusic() {
try {
const stored = localStorage.getItem('dreamLeagueMusic');
const name = localStorage.getItem('dreamLeagueMusicName');
if (stored && name) {
musicURL = stored;
if (audioElement) {
audioElement.src = musicURL;
audioElement.load();
}
musicLoaded = true;
musicStored = true;
document.getElementById('songName').textContent = name;
document.getElementById('musicStatusDisplay').textContent = `๐ต Music: ${name}`;
}
} catch(e) {}
}
function playMusic() {
if (!musicLoaded && !musicURL) {
alert('๐ Please upload a music file first!\n\n1. Download MP3 from audio.com\n2. Click "UPLOAD MP3" in Settings\n3. Select your file\n4. Press PLAY');
return;
}
if (!audioElement) {
audioElement = new Audio(musicURL);
audioElement.loop = true;
audioElement.volume = 0.7;
}
if (!matchActive) {
if (audioElement.paused) {
audioElement.play();
sayComment('๐ต Playing music!', '๐ต');
}
} else {
sayComment('๐ต Music pauses during matches to prevent lag!', '๐ต');
}
}
function stopMusic() {
if (audioElement) {
audioElement.pause();
audioElement.currentTime = 0;
sayComment('โน Music stopped', 'โน');
}
}
function deleteMusic() {
if (audioElement) {
audioElement.pause();
audioElement.currentTime = 0;
audioElement.src = '';
}
musicLoaded = false;
musicStored = false;
musicURL = null;
document.getElementById('songName').textContent = 'No song selected';
document.getElementById('musicStatusDisplay').textContent = '๐ต Music: No song loaded';
try {
localStorage.removeItem('dreamLeagueMusic');
localStorage.removeItem('dreamLeagueMusicName');
} catch(e) {}
sayComment('๐ Music deleted!', '๐');
}
function pauseMusicForMatch() {
if (audioElement && !audioElement.paused) {
audioElement.pause();
musicPausedForMatch = true;
}
}
function resumeMusicAfterMatch() {
if (musicPausedForMatch && audioElement && musicLoaded) {
audioElement.play();
musicPausedForMatch = false;
}
}
// ========== COMMENTATOR WITH REAL VOICE ==========
function sayComment(text, emoji = '๐๏ธ') {
const box = document.getElementById('commentatorBox');
const textEl = document.getElementById('commentatorText');
if (box && textEl) {
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)';
}, 2500);
}
if (soundEnabled && window.speechSynthesis) {
try {
window.speechSynthesis.cancel();
const cleanText = text.replace(/[^a-zA-Z0-9 ]/g, '').trim();
if (cleanText.length > 0) {
const utterance = new SpeechSynthesisUtterance(cleanText);
utterance.rate = 0.85;
utterance.pitch = 1.1;
utterance.volume = 1;
const voices = window.speechSynthesis.getVoices();
const maleVoice = voices.find(v => v.name.toLowerCase().includes('male') || v.name.toLowerCase().includes('david'));
if (maleVoice) utterance.voice = maleVoice;
window.speechSynthesis.speak(utterance);
}
} catch(e) {}
}
}
function randomPhrase(phraseArray) {
return phraseArray[Math.floor(Math.random() * phraseArray.length)];
}
// ========== COMMENTATOR PHRASES ==========
const commentatorPhrases = {
goal: [
"โก GOAL! What a strike!",
"๐ฏ INTO THE BACK OF THE NET!",
"๐ฅ UNBELIEVABLE! GOAL!",
"๐ซ MAGIC! He's done it!",
"๐ WORLD CLASS FINISH!",
"๐ GOAL! The crowd goes wild!",
"โฝ GOLAZO! Absolutely brilliant!"
],
pass: ["โฌ Clean pass!", "๐ฏ Perfect through ball!", "๐ Great vision!"],
shoot: ["๐จ Shot on target!", "๐ฏ Testing the keeper!", "โก Powerful strike!"],
tackle: ["๐ก๏ธ Clean tackle!", "๐ช Strong challenge!", "โ๏ธ Ball won back!"],
miss: ["๐ฑ Oh no! Missed it!", "๐ค Unlucky! So close!", "๐
Off target!"],
aiGoal: ["๐ค AI scores! Unlucky!", "๐คฌ Against the run of play!", "๐ญ They've equalized!"],
foul: ["โ ๏ธ Foul! Free kick!", "๐จ Yellow card!", "โก Free kick opportunity!", "๐ด RED CARD!"],
corner: ["๐ Corner kick!", "๐ฏ Cross coming in!"],
throwin: ["๐ Throw-in!", "๐ค Play restarts!"],
penalty: ["โฝ PENALTY!", "๐ฏ Spot kick!", "๐งค Keeper ready!"],
save: ["๐งค Great save!", "๐ Keeper denies!", "๐ช What a stop!"]
};
// ========== 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 === 'teamSelectScreen') renderTeams();
if (id === 'formationScreen') renderFormation();
if (id === 'leagueSelectScreen') loadLeagueStandings();
if (id === 'transferScreen') refreshTransfers();
if (id === 'cupStoreScreen') updateCupStore();
if (id === 'settingsScreen') updateSettings();
if (id === 'matchScreen') {
pauseMusicForMatch();
setTimeout(() => {
initMatchCanvas();
document.getElementById('joystickArea').style.display = 'block';
setupJoystick();
}, 100);
} else {
if (id !== 'matchScreen') {
resumeMusicAfterMatch();
}
}
}
function renderTeams() {
const grid = document.getElementById('teamGrid');
if (!grid) return;
grid.innerHTML = '';
teams.forEach(t => {
const div = document.createElement('div');
div.className = 'team-card';
div.innerHTML = `<span class="crest">${t.crest}</span>
<div class="name">${t.name}</div>
<div class="rating">โญ ${t.rating}</div>`;
div.onclick = () => { selectedTeam = t; renderTeams(); };
if (selectedTeam.name === t.name) div.style.borderColor = '#ffdd44';
grid.appendChild(div);
});
}
function renderFormation() {
const grid = document.getElementById('formationGrid');
if (!grid) return;
grid.innerHTML = '';
const positions = ['GK', 'LB', 'CB', 'CB', 'RB', 'LM', 'CM', 'CM', 'RM', 'LW', 'ST', 'RW'];
const teamPlayers = getTeamPlayers(selectedTeam.name);
positions.forEach((pos, i) => {
const p = teamPlayers[i % teamPlayers.length];
const div = document.createElement('div');
div.className = 'formation-slot';
div.innerHTML = `<span class="pos">${pos}</span><br>${p.name}<br><span style="color:#ffdd44;">${p.rating}</span>`;
div.onclick = () => {
showSubstitute();
document.getElementById('subOverlay').style.display = 'block';
};
grid.appendChild(div);
});
}
function getTeamPlayers(teamName) {
if (teamData[teamName]) {
return teamData[teamName].players;
}
return defaultPlayers;
}
function loadLeagueStandings() {
const league = document.getElementById('leagueSelector').value;
currentLeague = league;
const data = leagueData[league];
if (!data) return;
const container = document.getElementById('leagueStandings');
if (!container) return;
let html = `<div style="color:#ffdd44; font-weight:bold; font-size:9px; text-align:center; margin-bottom:2px;">${data.name}</div>`;
html += `<div class="row header-row"><span>Team</span><span>P</span><span>GD</span><span>Pts</span></div>`;
data.standings.forEach((t, i) => {
const gd = t.gf - t.ga;
const medal = i === 0 ? '๐' : i === 1 ? '๐ฅ' : i === 2 ? '๐ฅ' : `${i+1}.`;
html += `<div class="row"><span>${medal} ${t.team}</span><span>${t.played}</span><span>${gd}</span><span style="color:#ffdd44;">${t.pts}</span></div>`;
});
container.innerHTML = html;
const progressEl = document.getElementById('leagueProgress');
if (progressEl) progressEl.textContent = `Progress: ${leagueWins}/9 wins`;
}
function updateCupStore() {
const container = document.getElementById('cupStoreList');
if (!container) return;
let html = '';
cupData.forEach(cup => {
const achieved = cup.achieved || false;
html += `<div class="cup-store-item">
<span>${cup.icon} ${cup.name}</span>
<span class="${achieved ? 'achieved' : 'not-achieved'}">${achieved ? 'โ
ACHIEVED' : 'โฌ NOT ACHIEVED'}</span>
</div>`;
});
container.innerHTML = html;
}
function updateSettings() {
document.getElementById('settingsCoins').textContent = coins.toLocaleString();
document.getElementById('settingsTrophies').textContent = trophies;
document.getElementById('savedReplaysCount').textContent = savedReplays.length;
}
function showComingSoon(feature) {
alert(`๐ ${feature} coming soon!\nStay tuned for updates!`);
}
// ========== TRANSFER SYSTEM ==========
function generateTransferList() {
const allPlayers = [];
Object.values(realPlayers).forEach(team => {
team.forEach(p => {
allPlayers.push({...p, team: Object.keys(teamData).find(key => teamData[key].players.includes(p)) || 'Unknown'});
});
});
const shuffled = allPlayers.sort(() => Math.random() - 0.5);
transferList = shuffled.slice(0, 5).map(p => ({
...p,
price: Math.floor(p.rating * 8000 + Math.random() * 40000),
shooting: p.shooting || 50 + Math.floor(Math.random() * 30),
defence: p.defence || 50 + Math.floor(Math.random() * 30),
tackling: p.tackling || 50 + Math.floor(Math.random() * 30),
goalkeeping: p.goalkeeping || 50 + Math.floor(Math.random() * 30)
}));
}
function refreshTransfers() {
generateTransferList();
const container = document.getElementById('transferList');
if (!container) return;
let html = '';
transferList.forEach(p => {
html += `<div class="transfer-item">
<span class="name">${p.name}</span>
<span class="stats">โฝ${p.shooting} ๐ก๏ธ${p.defence} โ๏ธ${p.tackling}</span>
<span class="price">๐ช${p.price.toLocaleString()}</span>
<button style="background:#1a3a1a;border:1px solid #4a9a4a;color:white;padding:1px 4px;border-radius:8px;font-size:5px;cursor:pointer;" onclick="buyPlayer('${p.name}')">BUY</button>
</div>`;
});
container.innerHTML = html || '<div style="text-align:center;color:#557755;padding:4px;">No players available</div>';
}
function buyPlayer(name) {
const player = transferList.find(p => p.name === name);
if (!player) return;
if (coins >= player.price) {
coins -= player.price;
const teamPlayers = getTeamPlayers(selectedTeam.name);
const existing = teamPlayers.find(p => p.name === player.name);
if (!existing) {
teamPlayers.push({
name: player.name,
pos: player.pos || 'CM',
rating: player.rating,
number: teamPlayers.length + 1,
shooting: player.shooting,
defence: player.defence,
tackling: player.tackling,
goalkeeping: player.goalkeeping
});
sayComment(`โ
Signed ${player.name}!`, '๐');
updateCoins();
refreshTransfers();
renderFormation();
} else {
alert('Player already in squad!');
}
} else {
alert('Not enough coins!');
}
}
// ========== JOYSTICK CONTROLS - FIXED ==========
function setupJoystick() {
const area = document.getElementById('joystickArea');
const knob = document.getElementById('joystickKnob');
if (!area || !knob) {
setTimeout(setupJoystick, 100);
return;
}
const newArea = area.cloneNode(true);
area.parentNode.replaceChild(newArea, area);
const newKnob = newArea.querySelector('#joystickKnob');
const joyArea = newArea;
const joyKnob = newKnob;
function handleMove(clientX, clientY) {
const rect = joyArea.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 - joyKnob.offsetWidth / 2;
if (dist > maxDist && maxDist > 0) {
dx = (dx / dist) * maxDist;
dy = (dy / dist) * maxDist;
}
joyKnob.style.transform = `translate(${dx}px, ${dy}px)`;
joystickX = maxDist > 0 ? dx / maxDist : 0;
joystickY = maxDist > 0 ? dy / maxDist : 0;
joystickActive = true;
movePlayerWithJoystick(joystickX, joystickY);
}
function handleEnd() {
joyKnob.style.transform = 'translate(0, 0)';
joystickX = 0;
joystickY = 0;
joystickActive = false;
}
joyArea.addEventListener('touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
joyArea.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
joyArea.addEventListener('touchend', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
joyArea.addEventListener('touchcancel', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
let isDragging = false;
joyArea.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) {
if (!matchActive) return;
const ballCarrier = homeTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (ballCarrier) {
const speed = currentTactic === 'attack' ? 2.5 : currentTactic === 'defence' ? 1.2 : 2;
ballCarrier.targetX += x * speed;
ballCarrier.targetY += y * speed;
ballCarrier.targetX = Math.max(20, Math.min(380, ballCarrier.targetX));
ballCarrier.targetY = Math.max(20, Math.min(680, ballCarrier.targetY));
}
}
// ========== TACTICS ==========
function setTactic(tactic) {
currentTactic = tactic;
document.querySelectorAll('.tactic-btn').forEach(b => b.classList.remove('active'));
if (tactic === 'balanced') document.getElementById('tacticBalanced').classList.add('active');
else if (tactic === 'attack') document.getElementById('tacticAttack').classList.add('active');
else if (tactic === 'defence') document.getElementById('tacticDefence').classList.add('active');
sayComment(`๐ ${tactic.toUpperCase()} tactic set!`, '๐');
}
// ========== MATCH ENGINE ==========
function initPlayers() {
homeTeamPlayers = [];
awayTeamPlayers = [];
const homePositions = [
{ x: 35, y: 340 }, { x: 70, y: 270 }, { x: 70, y: 340 },
{ x: 70, y: 410 }, { x: 70, y: 480 }, { x: 120, y: 260 },
{ x: 120, y: 340 }, { x: 120, y: 420 }, { x: 120, y: 490 },
{ x: 170, y: 310 }, { x: 170, y: 430 }, { x: 170, y: 370 }
];
const teamPlayers = getTeamPlayers(selectedTeam.name);
homePositions.forEach((pos, i) => {
const p = teamPlayers[i % teamPlayers.length];
homeTeamPlayers.push({
x: pos.x + (Math.random() - 0.5) * 6,
y: pos.y + (Math.random() - 0.5) * 6,
targetX: pos.x,
targetY: pos.y,
id: i,
hasBall: i === 0,
color: '#ffdd44',
stamina: 100,
rating: p.rating || 80,
name: p.name,
number: p.number || i + 1,
shooting: p.shooting || 50 + Math.floor(Math.random() * 30),
defence: p.defence || 50 + Math.floor(Math.random() * 30),
tackling: p.tackling || 50 + Math.floor(Math.random() * 30),
goalkeeping: p.goalkeeping || 50 + Math.floor(Math.random() * 30),
isFallen: false,
fallTimer: 0
});
});
const aiTeamName = getRandomAITeam();
const awayPositions = [
{ x: 385, y: 340 }, { x: 350, y: 270 }, { x: 350, y: 340 },
{ x: 350, y: 410 }, { x: 350, y: 480 }, { x: 300, y: 260 },
{ x: 300, y: 340 }, { x: 300, y: 420 }, { x: 300, y: 490 },
{ x: 250, y: 310 }, { x: 250, y: 430 }, { x: 250, y: 370 }
];
awayPositions.forEach((pos, i) => {
const isGK = i === 0;
awayTeamPlayers.push({
x: pos.x + (Math.random() - 0.5) * 6,
y: pos.y + (Math.random() - 0.5) * 6,
targetX: pos.x,
targetY: pos.y,
id: i,
hasBall: false,
color: '#ff6666',
stamina: 100,
rating: 75 + Math.floor(Math.random() * 15),
name: isGK ? `${aiTeamName} GK` : `${aiTeamName} ${i}`,
number: i + 1,
shooting: isGK ? 20 : 50 + Math.floor(Math.random() * 30),
defence: isGK ? 30 : 50 + Math.floor(Math.random() * 30),
tackling: isGK ? 25 : 50 + Math.floor(Math.random() * 30),
goalkeeping: isGK ? 70 + Math.floor(Math.random() * 20) : 10,
isFallen: false,
fallTimer: 0,
teamName: aiTeamName
});
});
referee = { x: 210, y: 390, whistle: false };
ball.x = 210;
ball.y = 390;
ball.vx = 0;
ball.vy = 0;
homeTeamPlayers[0].hasBall = true;
sayComment(`โ๏ธ vs ${aiTeamName}! Let's go!`, 'โ๏ธ');
}
function getRandomAITeam() {
const aiTeams = ['Real Madrid', 'Barcelona', 'Liverpool', 'Man City', 'Bayern', 'PSG', 'Milan', 'Ajax', 'Benfica', 'Nigeria', 'Brazil', 'Argentina', 'Germany', 'France', 'England', 'Portugal'];
const filtered = aiTeams.filter(t => t !== selectedTeam.name);
return filtered[Math.floor(Math.random() * filtered.length)];
}
function startMatch(type) {
currentMatchType = type || 'friendly';
showScreen('matchScreen');
scoreHome = 0;
scoreAway = 0;
matchTime = 0;
gameTime = 0;
gameClock = 0;
matchEvents = [];
isSetPiece = false;
setPieceType = '';
isPenalty = false;
foulCount = 0;
yellowCards = 0;
redCards = 0;
shootPressure = 0;
goalScoredRecently = false;
document.getElementById('subOverlay').style.display = 'none';
document.getElementById('celebrationOverlay').style.display = 'none';
document.getElementById('replayOverlay').style.display = 'none';
initPlayers();
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
matchActive = true;
if (matchInterval) clearInterval(matchInterval);
if (frameId) cancelAnimationFrame(frameId);
pauseMusicForMatch();
matchInterval = setInterval(() => {
matchTime++;
gameTime++;
gameClock++;
if (!isSetPiece && !isPenalty) {
updateMatch();
}
drawMatch();
if (gameClock >= totalMatchTime) {
clearInterval(matchInterval);
matchActive = false;
resumeMusicAfterMatch();
endMatch();
}
}, 1000);
function animate() {
if (!matchActive) return;
drawMatch();
frameId = requestAnimationFrame(animate);
}
animate();
setTimeout(() => {
setupJoystick();
}, 300);
setTimeout(refreshTransfers, 500);
setTactic('balanced');
}
function updateMatch() {
homeTeamPlayers.forEach((p, i) => {
if (p.isFallen) {
p.fallTimer--;
if (p.fallTimer <= 0) p.isFallen = false;
return;
}
if (p.hasBall) {
if (!joystickActive) {
const attackSpeed = currentTactic === 'attack' ? 1.5 : 1;
p.targetX = 380 + Math.sin(gameTime / 3 + i) * 20 * attackSpeed;
p.targetY = 340 + Math.sin(gameTime / 4 + i * 2) * 50 * attackSpeed;
}
p.stamina = Math.max(0, p.stamina - 0.3);
} else {
const baseX = currentTactic === 'attack' ? 30 + (i % 4) * 35 : 50 + (i % 4) * 40;
const baseY = currentTactic === 'attack' ? 180 + Math.floor(i / 4) * 60 : 200 + Math.floor(i / 4) * 60;
p.targetX = baseX + Math.sin(gameTime / 5 + i) * 15;
p.targetY = baseY + Math.cos(gameTime / 6 + i) * 10;
p.stamina = Math.min(100, p.stamina + 0.2);
}
p.x += (p.targetX - p.x) * 0.06;
p.y += (p.targetY - p.y) * 0.06;
});
awayTeamPlayers.forEach((p, i) => {
if (p.isFallen) {
p.fallTimer--;
if (p.fallTimer <= 0) p.isFallen = false;
return;
}
if (p.hasBall) {
p.targetX = 50 + Math.sin(gameTime / 2 + i) * 15;
p.targetY = 340 + Math.sin(gameTime / 3 + i * 1.5) * 40;
p.stamina = Math.max(0, p.stamina - 0.4);
} else {
const targetHome = homeTeamPlayers[i % homeTeamPlayers.length];
if (targetHome) {
const pressure = isSecondPress ? 0.8 : 0.5;
p.targetX = targetHome.x + (Math.random() - 0.5) * 30 * pressure;
p.targetY = targetHome.y + (Math.random() - 0.5) * 30 * pressure;
}
p.stamina = Math.min(100, p.stamina + 0.15);
}
p.x += (p.targetX - p.x) * 0.055;
p.y += (p.targetY - p.y) * 0.055;
});
const ballCarrier = homeTeamPlayers.find(p => p.hasBall && !p.isFallen) || awayTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (ballCarrier) {
ball.x = ballCarrier.x + (homeTeamPlayers.includes(ballCarrier) ? 15 : -15);
ball.y = ballCarrier.y;
ball.vx *= 0.85;
ball.vy *= 0.85;
} else {
ball.x += ball.vx;
ball.y += ball.vy;
ball.vx *= 0.97;
ball.vy *= 0.97;
}
if (ball.x > 390) { ball.x = 390; ball.vx *= -0.5; }
if (ball.x < 10) { ball.x = 10; ball.vx *= -0.5; }
if (ball.y > 680) { ball.y = 680; ball.vy *= -0.5; }
if (ball.y < 10) { ball.y = 10; ball.vy *= -0.5; }
// ========== GOAL DETECTION - EVERY SHOT GOES IN ==========
// If ball is near the goal, it will go in automatically
if (ball.x < 20 && ball.y > 300 && ball.y < 380 && ball.vx < 0) {
if (!goalScoredRecently) {
// Move ball into goal
ball.x = 5;
ball.y = 340 + (Math.random() - 0.5) * 20;
scoreHome++;
goalScoredRecently = true;
sayComment(randomPhrase(commentatorPhrases.goal), 'โก');
coins += 200000;
gems += 1;
updateCoins();
showReplay(`โก GOAL! ${selectedTeam.name} scores!`);
setTimeout(() => {
resetBall();
goalScoredRecently = false;
}, 800);
}
} else if (ball.x > 380 && ball.y > 300 && ball.y < 380 && ball.vx > 0) {
if (!goalScoredRecently) {
// AI scores
ball.x = 395;
ball.y = 340 + (Math.random() - 0.5) * 20;
scoreAway++;
goalScoredRecently = true;
sayComment(randomPhrase(commentatorPhrases.aiGoal), '๐ค');
setTimeout(() => {
resetBall();
goalScoredRecently = false;
}, 800);
}
}
// Corner / Throw-in
if (ball.x < 5 || ball.x > 395) {
if (!isSetPiece && !goalScoredRecently) {
isSetPiece = true;
const isRight = ball.x > 395;
setPiecePosition = { x: isRight ? 390 : 10, y: Math.min(680, Math.max(20, ball.y)) };
const aiHasBall = awayTeamPlayers.some(p => p.hasBall);
if (aiHasBall) {
setPieceType = 'corner';
sayComment(randomPhrase(commentatorPhrases.corner), '๐');
} else {
setPieceType = 'throw-in';
sayComment(randomPhrase(commentatorPhrases.throwin), '๐');
}
homeTeamPlayers.forEach(p => p.hasBall = false);
awayTeamPlayers.forEach(p => p.hasBall = false);
setTimeout(() => {
isSetPiece = false;
ball.x = setPiecePosition.x;
ball.y = setPiecePosition.y;
const idx = Math.floor(Math.random() * homeTeamPlayers.length);
homeTeamPlayers[idx].hasBall = true;
sayComment("โก Play restarts!", "โก");
}, 1000);
}
return;
}
// Fouls - AI tackles
awayTeamPlayers.forEach(p => {
if (p.hasBall && !p.isFallen) {
homeTeamPlayers.forEach(h => {
if (h.isFallen) return;
const dist = Math.hypot(h.x - p.x, h.y - p.y);
if (dist < 18 && Math.random() < 0.02) {
isSetPiece = true;
setPieceType = 'free-kick';
setPiecePosition = { x: ball.x, y: ball.y };
p.hasBall = false;
p.isFallen = true;
p.fallTimer = 20;
foulCount++;
if (ball.x > 350 && ball.x < 390 && ball.y > 300 && ball.y < 380) {
isPenalty = true;
setPieceType = 'penalty';
sayComment("โฝ PENALTY! In the box!", "โฝ");
setTimeout(() => {
isPenalty = false;
isSetPiece = false;
setupPenalty();
}, 1000);
return;
}
if (foulCount % 3 === 0 && Math.random() < 0.3) {
yellowCards++;
sayComment("๐จ Yellow card!", "๐จ");
} else if (foulCount % 5 === 0 && Math.random() < 0.2) {
redCards++;
sayComment("๐ด RED CARD! SENT OFF!", "๐ด");
awayTeamPlayers = awayTeamPlayers.filter(a => a.id !== p.id);
} else {
sayComment(randomPhrase(commentatorPhrases.foul), 'โ ๏ธ');
}
setTimeout(() => {
isSetPiece = false;
homeTeamPlayers.forEach(h2 => h2.hasBall = false);
const idx = Math.floor(Math.random() * homeTeamPlayers.length);
homeTeamPlayers[idx].hasBall = true;
ball.x = setPiecePosition.x + 20;
ball.y = setPiecePosition.y;
sayComment("โก Free kick!", "โก");
}, 1500);
return;
}
});
}
});
awayTeamPlayers.forEach(p => {
if (p.isFallen) return;
const dist = Math.hypot(p.x - ball.x, p.y - ball.y);
if (dist < 20 && Math.random() < 0.04) {
homeTeamPlayers.forEach(h => h.hasBall = false);
p.hasBall = true;
ball.x = p.x - 15;
ball.y = p.y;
sayComment(randomPhrase(commentatorPhrases.tackle), '๐ก๏ธ');
}
});
homeTeamPlayers.forEach(p => {
if (p.isFallen) return;
const dist = Math.hypot(p.x - ball.x, p.y - ball.y);
if (dist < 20 && Math.random() < 0.05) {
awayTeamPlayers.forEach(a => a.hasBall = false);
p.hasBall = true;
ball.x = p.x + 15;
ball.y = p.y;
sayComment(randomPhrase(commentatorPhrases.tackle), '๐ก๏ธ');
}
});
const aiAttacker = awayTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (aiAttacker && Math.random() < 0.03) {
const targetX = 50;
const targetY = 340 + (Math.random() - 0.5) * 120;
ball.vx = (targetX - ball.x) * 0.06;
ball.vy = (targetY - ball.y) * 0.06;
aiAttacker.hasBall = false;
}
referee.x += (ball.x - referee.x) * 0.03 + (Math.random() - 0.5) * 2;
referee.y += (ball.y - referee.y) * 0.03 + (Math.random() - 0.5) * 2;
referee.x = Math.max(20, Math.min(380, referee.x));
referee.y = Math.max(20, Math.min(680, referee.y));
}
function setupPenalty() {
isPenalty = true;
const penaltyTaker = homeTeamPlayers[0];
const keeper = awayTeamPlayers[0];
penaltyTaker.x = 370;
penaltyTaker.y = 340;
keeper.x = 50;
keeper.y = 340;
ball.x = 370;
ball.y = 340;
penaltyTaker.hasBall = true;
keeper.hasBall = false;
sayComment("โฝ Penalty! Choose your spot!", "โฝ");
setTimeout(() => {
if (isPenalty && matchActive) {
// Penalty always goes in
ball.x = 5;
ball.y = 340 + (Math.random() - 0.5) * 30;
penaltyTaker.hasBall = false;
scoreHome++;
sayComment("โก GOAL! Perfect penalty!", "โก");
coins += 100000;
updateCoins();
isPenalty = false;
setTimeout(() => resetBall(), 800);
}
}, 2000);
}
function resetBall() {
ball.x = 210;
ball.y = 390;
ball.vx = 0;
ball.vy = 0;
const idx = Math.floor(Math.random() * homeTeamPlayers.length);
homeTeamPlayers.forEach(p => p.hasBall = false);
awayTeamPlayers.forEach(p => p.hasBall = false);
homeTeamPlayers[idx].hasBall = true;
isPenalty = false;
isSetPiece = false;
}
function drawMatch() {
const canvas = document.getElementById('matchCanvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const W = canvas.width || 400;
const H = canvas.height || 700;
const gradient = ctx.createLinearGradient(0, 0, 0, H);
gradient.addColorStop(0, '#2d8a2d');
gradient.addColorStop(0.3, '#3a9a3a');
gradient.addColorStop(0.5, '#42a542');
gradient.addColorStop(0.7, '#3a9a3a');
gradient.addColorStop(1, '#2d8a2d');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, W, H);
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
ctx.lineWidth = 2;
ctx.strokeRect(10, 10, W-20, H-20);
ctx.beginPath();
ctx.arc(W/2, H/2, 45, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(W/2, 10);
ctx.lineTo(W/2, H-10);
ctx.stroke();
ctx.strokeRect(10, H/2-50, 35, 100);
ctx.strokeRect(W-45, H/2-50, 35, 100);
ctx.strokeRect(10, H/2-120, 60, 240);
ctx.strokeRect(W-70, H/2-120, 60, 240);
ctx.beginPath();
ctx.arc(45, H/2, 4, 0, Math.PI*2);
ctx.fill();
ctx.beginPath();
ctx.arc(W-45, H/2, 4, 0, Math.PI*2);
ctx.fill();
homeTeamPlayers.forEach((p) => {
if (!p.isFallen) {
drawStickman(ctx, p.x, p.y, '#ffdd44', p.hasBall, p.stamina, p.number, p.name);
} else {
ctx.fillStyle = 'rgba(255,0,0,0.3)';
ctx.fillRect(p.x-8, p.y-4, 16, 8);
ctx.fillStyle = '#ff4444';
ctx.font = '10px sans-serif';
ctx.fillText('๐ต', p.x-5, p.y+4);
}
});
awayTeamPlayers.forEach((p) => {
if (!p.isFallen) {
drawStickman(ctx, p.x, p.y, '#ff6666', p.hasBall, p.stamina, p.number, p.teamName || 'AI');
} else {
ctx.fillStyle = 'rgba(255,0,0,0.3)';
ctx.fillRect(p.x-8, p.y-4, 16, 8);
ctx.fillStyle = '#ff4444';
ctx.font = '10px sans-serif';
ctx.fillText('๐ต', p.x-5, p.y+4);
}
});
ctx.fillStyle = '#ffdd44';
ctx.font = '14px sans-serif';
ctx.fillText('๐จโโ๏ธ', referee.x-8, referee.y-12);
ctx.shadowColor = 'rgba(255,255,255,0.6)';
ctx.shadowBlur = 15;
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(ball.x, ball.y, 6, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(10, 6, W/2-10, 28);
ctx.fillRect(W/2+10, 6, W/2-20, 28);
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 15px sans-serif';
ctx.fillText(`${selectedTeam.name} ${scoreHome}`, 15, 27);
ctx.fillStyle = '#ff6666';
const aiName = awayTeamPlayers[0]?.teamName || 'AI';
ctx.fillText(`${aiName} ${scoreAway}`, W-85, 27);
const progress = Math.min(1, gameClock / totalMatchTime);
const displayMins = Math.floor(progress * 90);
const displaySecs = Math.floor((progress * 90 * 60) % 60);
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(W/2-40, 6, 80, 18);
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 11px sans-serif';
ctx.fillText(`${String(displayMins).padStart(2,'0')}:${String(displaySecs).padStart(2,'0')}`, W/2-28, 21);
const barWidth = 70;
const barX = W/2 - 35;
const barY = 27;
ctx.fillStyle = 'rgba(0,0,0,0.4)';
ctx.fillRect(barX, barY, barWidth, 3);
ctx.fillStyle = progress > 0.8 ? '#ff4444' : '#4a9a4a';
ctx.fillRect(barX, barY, progress * barWidth, 3);
if (yellowCards > 0 || redCards > 0) {
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(W-55, 40, 45, 14);
let cardText = '';
if (yellowCards > 0) cardText += `๐จ${yellowCards}`;
if (redCards > 0) cardText += ` ๐ด${redCards}`;
ctx.fillStyle = '#fff';
ctx.font = '8px sans-serif';
ctx.fillText(cardText, W-52, 51);
}
if (isSetPiece || isPenalty) {
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 12px sans-serif';
const labels = {
'free-kick': 'โก FREE KICK',
'corner': '๐ CORNER',
'throw-in': '๐ THROW-IN',
'penalty': 'โฝ PENALTY'
};
ctx.fillText(labels[setPieceType] || '', W/2-45, 65);
}
ctx.fillStyle = 'rgba(255,255,255,0.15)';
ctx.font = '7px sans-serif';
const tacticLabels = { balanced: 'โ๏ธ BAL', attack: 'โก ATK', defence: '๐ก๏ธ DEF' };
ctx.fillText(tacticLabels[currentTactic] || 'BAL', W-55, H-6);
const typeLabels = {
'friendly': 'FRIENDLY',
'league': 'LEAGUE',
'champions': 'CHAMPIONS LEAGUE',
'worldcup': 'CLUB WORLD CUP',
'training': 'TRAINING'
};
ctx.fillText(typeLabels[currentMatchType] || 'FRIENDLY', 8, H-6);
}
function drawStickman(ctx, x, y, color, hasBall, stamina, number, name) {
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,0.2)';
ctx.beginPath();
ctx.ellipse(x, y+28, 10, 3, 0, 0, Math.PI*2);
ctx.fill();
if (stamina !== undefined) {
ctx.fillStyle = stamina > 70 ? '#4a9a4a' : stamina > 40 ? '#ffdd44' : '#ff4444';
ctx.fillRect(x-8, y-34, 16 * (stamina/100), 3);
}
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.font = '6px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(name || '', x, y-38);
ctx.textAlign = 'left';
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '5px sans-serif';
ctx.fillText(number || '', x-2, y-30);
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(x, y-10, 7, 0, Math.PI*2);
ctx.stroke();
ctx.fillStyle = color;
ctx.fillRect(x-3, y-12, 2, 2);
ctx.fillRect(x+2, y-12, 2, 2);
ctx.beginPath();
ctx.moveTo(x, y-3);
ctx.lineTo(x, y+12);
ctx.stroke();
const legOffset = hasBall ? Math.sin(gameTime / 2.5 + x * 2) * 4 : 0;
ctx.beginPath();
ctx.moveTo(x, y+12);
ctx.lineTo(x-5 + legOffset, y+22);
ctx.moveTo(x, y+12);
ctx.lineTo(x+5 - legOffset, y+22);
ctx.stroke();
const armOffset = hasBall ? Math.sin(gameTime / 3 + y * 1.5) * 3 : 1;
ctx.beginPath();
ctx.moveTo(x, y+2);
ctx.lineTo(x-7 + armOffset, y-4);
ctx.moveTo(x, y+2);
ctx.lineTo(x+7 - armOffset, y-4);
ctx.stroke();
if (hasBall) {
ctx.shadowColor = 'rgba(255, 220, 50, 0.5)';
ctx.shadowBlur = 15;
ctx.fillStyle = 'rgba(255, 220, 50, 0.15)';
ctx.beginPath();
ctx.arc(x, y-14, 13, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = '#ffdd44';
ctx.font = '6px sans-serif';
ctx.fillText('โฝ', x-3, y-26);
}
}
// ========== MATCH CONTROLS ==========
function doPass() {
if (!matchActive || isSetPiece || isPenalty) return;
const passer = homeTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (!passer) {
sayComment("No possession!", "โ");
return;
}
let nearest = null;
let minDist = Infinity;
homeTeamPlayers.forEach(p => {
if (p === passer || p.isFallen) return;
const dist = Math.hypot(p.x - passer.x, p.y - passer.y);
if (dist < minDist && dist > 15 && dist < 150) {
minDist = dist;
nearest = p;
}
});
if (nearest) {
passer.hasBall = false;
nearest.hasBall = true;
ball.x = nearest.x + 15;
ball.y = nearest.y;
ball.vx = (nearest.x - passer.x) * 0.08;
ball.vy = (nearest.y - passer.y) * 0.08;
shootPressure = 30;
sayComment(randomPhrase(commentatorPhrases.pass), 'โฌ');
} else {
sayComment("No one to pass to!", "๐
");
}
}
// ========== SHOOT - EVERY SHOT GOES IN THE GOAL ==========
function doShoot() {
if (!matchActive || isSetPiece || isPenalty) return;
const shooter = homeTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (!shooter) {
sayComment("Get the ball first!", "โ");
return;
}
shootPressure = 100;
setTimeout(() => { shootPressure = 0; }, 500);
// Training modes
if (currentMatchType === 'training') {
if (trainingType === 'freekick' || trainingType === 'penalty') {
// Always score in training
scoreHome++;
shooter.hasBall = false;
sayComment("โก GOAL! Perfect training shot!", "โก");
showReplay(`โก Training Goal!`);
setTimeout(() => resetBall(), 600);
return;
}
}
// ========== EVERY SHOT GOES IN THE GOAL ==========
// Force the ball into the goal
shooter.hasBall = false;
ball.x = 5;
ball.y = 340 + (Math.random() - 0.5) * 30;
ball.vx = -0.1;
ball.vy = 0;
// Score the goal
if (!goalScoredRecently) {
scoreHome++;
goalScoredRecently = true;
sayComment(randomPhrase(commentatorPhrases.goal), 'โก');
coins += 200000;
gems += 1;
updateCoins();
showReplay(`โก GOAL! ${shooter.name} scores!`);
setTimeout(() => {
resetBall();
goalScoredRecently = false;
}, 800);
}
}
function doTackle() {
if (!matchActive || isSetPiece || isPenalty) return;
let tackled = false;
awayTeamPlayers.forEach(p => {
if (p.hasBall && !p.isFallen) {
const dist = Math.hypot(p.x - ball.x, p.y - ball.y);
if (dist < 25) {
const successRate = 0.4 + (p.stamina || 50) / 300;
if (Math.random() < successRate) {
p.hasBall = false;
p.isFallen = true;
p.fallTimer = 15;
const nearestHome = homeTeamPlayers.reduce((a, b) =>
Math.hypot(a.x - ball.x, a.y - ball.y) < Math.hypot(b.x - ball.x, b.y - ball.y) ? a : b
);
if (nearestHome && !nearestHome.isFallen) {
nearestHome.hasBall = true;
ball.x = nearestHome.x + 15;
ball.y = nearestHome.y;
tackled = true;
sayComment(randomPhrase(commentatorPhrases.tackle), '๐ก๏ธ');
}
} else {
isSetPiece = true;
setPieceType = 'free-kick';
setPiecePosition = { x: ball.x, y: ball.y };
p.isFallen = true;
p.fallTimer = 20;
foulCount++;
sayComment(randomPhrase(commentatorPhrases.foul), 'โ ๏ธ');
if (foulCount % 3 === 0 && Math.random() < 0.3) {
yellowCards++;
sayComment("๐จ Yellow card!", "๐จ");
} else if (foulCount % 5 === 0 && Math.random() < 0.2) {
redCards++;
sayComment("๐ด RED CARD! SENT OFF!", "๐ด");
awayTeamPlayers = awayTeamPlayers.filter(a => a.id !== p.id);
}
setTimeout(() => {
isSetPiece = false;
homeTeamPlayers.forEach(h => h.hasBall = false);
const idx = Math.floor(Math.random() * homeTeamPlayers.length);
homeTeamPlayers[idx].hasBall = true;
ball.x = setPiecePosition.x + 20;
ball.y = setPiecePosition.y;
}, 1500);
return;
}
}
}
});
if (!tackled) {
sayComment("Missed the tackle!", "โ");
}
}
function doKnock() {
if (!matchActive || isSetPiece || isPenalty) return;
const player = homeTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (!player) {
sayComment("You don't have the ball!", "โ");
return;
}
const knockDistance = 30;
const angle = Math.atan2(player.y - 340, player.x - 380);
ball.x += Math.cos(angle) * knockDistance;
ball.y += Math.sin(angle) * knockDistance;
player.hasBall = false;
sayComment("๐จ Knock ahead!", "๐จ");
setTimeout(() => {
if (!player.hasBall && !awayTeamPlayers.some(p => p.hasBall)) {
const dist = Math.hypot(player.x - ball.x, player.y - ball.y);
if (dist < 40) {
player.hasBall = true;
}
}
}, 300);
}
function doSecondPress() {
if (!matchActive) return;
isSecondPress = !isSecondPress;
sayComment(isSecondPress ? "โฉ Second press ON!" : "โฉ Second press OFF", "โฉ");
const btn = document.getElementById('secondPressBtn');
if (btn) btn.style.borderColor = isSecondPress ? '#44ff88' : '#4a9a4a';
}
// ========== SUBSTITUTION ==========
function doSubstitution(playerIndex) {
if (!matchActive) return;
const idx = playerIndex;
if (idx >= homeTeamPlayers.length) return;
const teamPlayers = getTeamPlayers(selectedTeam.name);
const currentPlayer = homeTeamPlayers[idx];
const onFieldNames = homeTeamPlayers.map(p => p.name);
const available = teamPlayers.filter(p => !onFieldNames.includes(p.name));
if (available.length === 0) {
sayComment("No substitutes available!", "โ");
return;
}
const newPlayerData = available[Math.floor(Math.random() * available.length)];
homeTeamPlayers[idx] = {
...homeTeamPlayers[idx],
name: newPlayerData.name,
rating: newPlayerData.rating || 80,
number: newPlayerData.number || idx + 1,
shooting: newPlayerData.shooting || 50,
defence: newPlayerData.defence || 50,
tackling: newPlayerData.tackling || 50,
goalkeeping: newPlayerData.goalkeeping || 10,
stamina: 100,
isFallen: false,
fallTimer: 0
};
sayComment(`๐ ${currentPlayer.name} โ ${newPlayerData.name}`, '๐');
document.getElementById('subOverlay').style.display = 'none';
renderFormation();
}
function showSubstitute() {
const overlay = document.getElementById('subOverlay');
const list = document.getElementById('subList');
if (!overlay || !list) return;
list.innerHTML = '';
homeTeamPlayers.forEach((p, i) => {
const healthPercent = p.stamina || 100;
const healthClass = healthPercent > 60 ? '' : healthPercent > 30 ? 'medium' : 'low';
const btn = document.createElement('button');
btn.innerHTML = `${p.name} (${p.rating}) <span class="health-bar ${healthClass}" style="width:${Math.min(16, healthPercent/6)}px;"></span>`;
btn.onclick = () => doSubstitution(i);
list.appendChild(btn);
});
overlay.style.display = 'block';
}
// ========== QUIT MATCH ==========
function quitMatch() {
if (matchInterval) clearInterval(matchInterval);
if (frameId) cancelAnimationFrame(frameId);
matchActive = false;
resumeMusicAfterMatch();
sayComment("Match abandoned!", "๐ช");
setTimeout(() => showScreen('teamSelectScreen'), 500);
}
// ========== REPLAY SYSTEM ==========
function showReplay(title) {
const overlay = document.getElementById('replayOverlay');
const canvas = document.getElementById('replayCanvas');
if (!overlay || !canvas) return;
overlay.style.display = 'flex';
document.getElementById('replayScore').textContent = `${scoreHome}-${scoreAway}`;
const ctx = canvas.getContext('2d');
canvas.width = canvas.clientWidth || 300;
canvas.height = canvas.clientHeight || 180;
ctx.fillStyle = '#1a6a1a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 1;
ctx.strokeRect(5, 5, canvas.width-10, canvas.height-10);
ctx.beginPath();
ctx.arc(canvas.width/2, canvas.height/2, 25, 0, Math.PI*2);
ctx.stroke();
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(canvas.width/2, canvas.height/2, 4, 0, Math.PI*2);
ctx.fill();
homeTeamPlayers.slice(0, 6).forEach((p, i) => {
ctx.strokeStyle = '#ffdd44';
ctx.lineWidth = 2;
const x = 15 + i * 25;
const y = 50 + (i % 3) * 25;
ctx.beginPath();
ctx.arc(x, y-6, 5, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x, y-1);
ctx.lineTo(x, y+8);
ctx.stroke();
ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.font = '4px sans-serif';
ctx.fillText(p.name || '', x-4, y-12);
});
awayTeamPlayers.slice(0, 6).forEach((p, i) => {
ctx.strokeStyle = '#ff6666';
ctx.lineWidth = 2;
const x = canvas.width - 15 - i * 25;
const y = 50 + (i % 3) * 25;
ctx.beginPath();
ctx.arc(x, y-6, 5, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x, y-1);
ctx.lineTo(x, y+8);
ctx.stroke();
});
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 10px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(title, canvas.width/2, 15);
ctx.textAlign = 'left';
currentReplay = {
title: title,
score: `${scoreHome}-${scoreAway}`,
time: new Date().toLocaleTimeString(),
events: [...matchEvents]
};
}
function closeReplay() {
document.getElementById('replayOverlay').style.display = 'none';
currentReplay = null;
}
function saveReplay() {
if (currentReplay) {
savedReplays.push({
...currentReplay,
savedAt: new Date().toLocaleString()
});
document.getElementById('savedReplaysCount').textContent = savedReplays.length;
sayComment("๐พ Replay saved!", "๐พ");
closeReplay();
}
}
function viewReplays() {
if (savedReplays.length === 0) {
alert("๐น No saved replays yet!\n\nScore a goal to save a replay.");
return;
}
let msg = "๐น SAVED REPLAYS:\n\n";
savedReplays.forEach((r, i) => {
msg += `${i+1}. ${r.title} - ${r.score} (${r.savedAt})\n`;
});
alert(msg);
}
// ========== END MATCH ==========
function endMatch() {
const won = scoreHome > scoreAway;
const drew = scoreHome === scoreAway;
if (won) {
coins += 1000000;
gems += 2;
if (currentMatchType === 'league') {
leagueWins++;
const progressEl = document.getElementById('leagueProgress');
if (progressEl) progressEl.textContent = `Progress: ${leagueWins}/9 wins`;
if (leagueWins >= 9) {
trophies++;
showCelebration(`๐ LEAGUE CHAMPIONS!`, `You won ${leagueData[currentLeague].name}!`);
coins += leagueData[currentLeague].reward || 3000000;
const cup = cupData.find(c => c.id === currentLeague);
if (cup) cup.achieved = true;
updateCupStore();
}
} else if (currentMatchType === 'champions') {
championsLeagueStage++;
updateChampionsLeagueUI();
if (championsLeagueStage >= 4) {
trophies++;
showCelebration(`๐ CHAMPIONS LEAGUE WINNERS!`, `You conquered Europe!`);
coins += 8000000;
const cup = cupData.find(c => c.id === 'champs');
if (cup) cup.achieved = true;
updateCupStore();
}
} else if (currentMatchType === 'worldcup') {
clubWorldCupStage++;
updateClubWorldCupUI();
if (clubWorldCupStage >= 3) {
trophies++;
showCelebration(`๐ CLUB WORLD CUP WINNERS!`, `You are World Champions!`);
coins += 10000000;
const cup = cupData.find(c => c.id === 'clubwc');
if (cup) cup.achieved = true;
updateCupStore();
}
}
} else if (drew) {
coins += 500000;
} else {
coins += 200000;
}
updateCoins();
refreshTransfers();
resumeMusicAfterMatch();
setTimeout(() => {
showScreen('teamSelectScreen');
}, 800);
}
// ========== CELEBRATION ==========
function showCelebration(title, subtitle) {
const overlay = document.getElementById('celebrationOverlay');
document.getElementById('winText').textContent = title;
document.getElementById('winSub').textContent = subtitle;
overlay.style.display = 'flex';
createConfetti();
sayComment(`๐ ${title} ๐`, '๐');
}
function createConfetti() {
const overlay = document.getElementById('celebrationOverlay');
const colors = ['#ffdd44', '#ff4444', '#44ff44', '#4444ff', '#ff44ff', '#44ffff', '#ff8844', '#88ff44'];
for (let i = 0; i < 40; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = Math.random() * 100 + '%';
confetti.style.top = '-10px';
confetti.style.background = colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = (Math.random() * 5 + 3) + 'px';
confetti.style.height = (Math.random() * 5 + 3) + 'px';
confetti.style.animationDuration = (Math.random() * 2 + 2) + 's';
confetti.style.animationDelay = (Math.random() * 2) + 's';
overlay.appendChild(confetti);
}
setTimeout(() => {
overlay.querySelectorAll('.confetti').forEach(c => c.remove());
}, 4000);
}
function closeCelebration() {
document.getElementById('celebrationOverlay').style.display = 'none';
showScreen('teamSelectScreen');
}
// ========== LEAGUE AND TOURNAMENT FUNCTIONS ==========
function startLeagueMatch() {
const league = document.getElementById('leagueSelector').value;
currentLeague = league;
startMatch('league');
}
function startChampionsLeagueMatch() {
if (championsLeagueStage < 4) {
startMatch('champions');
} else {
alert('๐ You already won the Champions League!');
}
}
function startClubWorldCupMatch() {
if (clubWorldCupStage < 3) {
startMatch('worldcup');
} else {
alert('๐ You already won the Club World Cup!');
}
}
function updateChampionsLeagueUI() {
const stages = ['clStage1', 'clStage2', 'clStage3', 'clStage4'];
const labels = ['Round of 16', 'Quarter Final', 'Semi Final', 'FINAL'];
for (let i = 0; i < 4; i++) {
const el = document.getElementById(stages[i]);
if (el) {
if (i < championsLeagueStage) {
el.innerHTML = `โ
${labels[i]} (Won)`;
el.style.color = '#88dd88';
} else if (i === championsLeagueStage) {
el.innerHTML = `โถ๏ธ ${labels[i]} (Current)`;
el.style.color = '#ffdd44';
} else {
el.innerHTML = `โฌ ${labels[i]}`;
el.style.color = '#557755';
}
}
}
const progressEl = document.getElementById('clProgress');
if (progressEl) progressEl.textContent = `Progress: ${championsLeagueStage}/4 wins`;
}
function updateClubWorldCupUI() {
const stages = ['cwcStage1', 'cwcStage2', 'cwcStage3'];
const labels = ['Quarter Final', 'Semi Final', 'FINAL'];
for (let i = 0; i < 3; i++) {
const el = document.getElementById(stages[i]);
if (el) {
if (i < clubWorldCupStage) {
el.innerHTML = `โ
${labels[i]} (Won)`;
el.style.color = '#88dd88';
} else if (i === clubWorldCupStage) {
el.innerHTML = `โถ๏ธ ${labels[i]} (Current)`;
el.style.color = '#ffdd44';
} else {
el.innerHTML = `โฌ ${labels[i]}`;
el.style.color = '#557755';
}
}
}
const progressEl = document.getElementById('cwcProgress');
if (progressEl) progressEl.textContent = `Progress: ${clubWorldCupStage}/3 wins`;
}
// ========== TRAINING FUNCTIONS ==========
function startTraining(type) {
trainingType = type;
isTrainingMode = true;
currentMatchType = 'training';
showScreen('matchScreen');
scoreHome = 0;
scoreAway = 0;
matchTime = 0;
gameTime = 0;
gameClock = 0;
isSetPiece = false;
isPenalty = false;
document.getElementById('subOverlay').style.display = 'none';
document.getElementById('celebrationOverlay').style.display = 'none';
initTrainingPlayers();
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
matchActive = true;
pauseMusicForMatch();
if (matchInterval) clearInterval(matchInterval);
if (frameId) cancelAnimationFrame(frameId);
matchInterval = setInterval(() => {
matchTime++;
gameTime++;
gameClock++;
if (!isSetPiece && !isPenalty) {
updateMatch();
}
drawMatch();
if (gameClock >= totalMatchTime) {
clearInterval(matchInterval);
matchActive = false;
resumeMusicAfterMatch();
endMatch();
}
}, 1000);
function animate() {
if (!matchActive) return;
drawMatch();
frameId = requestAnimationFrame(animate);
}
animate();
setTimeout(() => {
setupJoystick();
}, 300);
setTimeout(() => {
if (type === 'freekick') setupFreeKickTraining();
else if (type === 'corner') setupCornerTraining();
else if (type === 'penalty') setupPenaltyTraining();
else sayComment("๐ Free training! Play freely!", "๐");
}, 200);
}
function initTrainingPlayers() {
homeTeamPlayers = [];
awayTeamPlayers = [];
const homePositions = [
{ x: 35, y: 340 }, { x: 70, y: 270 }, { x: 70, y: 340 },
{ x: 70, y: 410 }, { x: 70, y: 480 }, { x: 120, y: 260 },
{ x: 120, y: 340 }, { x: 120, y: 420 }, { x: 120, y: 490 },
{ x: 170, y: 310 }, { x: 170, y: 430 }, { x: 170, y: 370 }
];
const teamPlayers = getTeamPlayers(selectedTeam.name);
homePositions.forEach((pos, i) => {
const p = teamPlayers[i % teamPlayers.length];
homeTeamPlayers.push({
x: pos.x + (Math.random() - 0.5) * 6,
y: pos.y + (Math.random() - 0.5) * 6,
targetX: pos.x,
targetY: pos.y,
id: i,
hasBall: i === 0,
color: '#ffdd44',
stamina: 100,
rating: p.rating || 80,
name: p.name,
number: p.number || i + 1,
shooting: p.shooting || 50,
defence: p.defence || 50,
tackling: p.tackling || 50,
goalkeeping: p.goalkeeping || 10,
isFallen: false,
fallTimer: 0
});
});
const awayPositions = [
{ x: 385, y: 340 }, { x: 350, y: 270 }, { x: 350, y: 410 },
{ x: 300, y: 340 }, { x: 250, y: 310 }, { x: 250, y: 370 }
];
awayPositions.forEach((pos, i) => {
awayTeamPlayers.push({
x: pos.x + (Math.random() - 0.5) * 6,
y: pos.y + (Math.random() - 0.5) * 6,
targetX: pos.x,
targetY: pos.y,
id: i,
hasBall: false,
color: '#ff6666',
stamina: 100,
rating: 70 + Math.floor(Math.random() * 10),
name: `AI ${i+1}`,
number: i + 1,
shooting: 50 + Math.floor(Math.random() * 20),
defence: 50 + Math.floor(Math.random() * 20),
tackling: 50 + Math.floor(Math.random() * 20),
goalkeeping: i === 0 ? 70 + Math.floor(Math.random() * 15) : 10,
isFallen: false,
fallTimer: 0,
teamName: 'Training'
});
});
referee = { x: 210, y: 390, whistle: false };
ball.x = 210;
ball.y = 390;
ball.vx = 0;
ball.vy = 0;
homeTeamPlayers[0].hasBall = true;
}
function setupFreeKickTraining() {
ball.x = 350;
ball.y = 340;
awayTeamPlayers = [];
for (let i = 0; i < 4; i++) {
awayTeamPlayers.push({
x: 320 + i * 12,
y: 340 - 15 + i * 8,
targetX: 320 + i * 12,
targetY: 340 - 15 + i * 8,
id: i,
hasBall: false,
color: '#ff6666',
stamina: 100,
rating: 80,
name: 'Wall',
number: i + 1,
shooting: 20,
defence: 80,
tackling: 70,
goalkeeping: 10,
isFallen: false,
fallTimer: 0,
teamName: 'Wall'
});
}
homeTeamPlayers.forEach(p => p.hasBall = false);
homeTeamPlayers[0].hasBall = true;
homeTeamPlayers[0].x = 380;
homeTeamPlayers[0].y = 340;
sayComment("๐ฅ
Free kick practice! Aim for the top corner!", "๐ฏ");
}
function setupCornerTraining() {
ball.x = 15;
ball.y = 600;
homeTeamPlayers.forEach((p, i) => {
p.x = 200 + i * 20;
p.y = 300 + i * 15;
p.hasBall = false;
});
homeTeamPlayers[0].hasBall = true;
homeTeamPlayers[0].x = 20;
homeTeamPlayers[0].y = 590;
sayComment("๐ Corner kick practice! Deliver a perfect cross!", "๐ฏ");
}
function setupPenaltyTraining() {
ball.x = 370;
ball.y = 340;
awayTeamPlayers = [];
awayTeamPlayers.push({
x: 50,
y: 340,
targetX: 50,
targetY: 340,
id: 0,
hasBall: false,
color: '#ff6666',
stamina: 100,
rating: 85,
name: 'GK',
number: 1,
shooting: 20,
defence: 30,
tackling: 25,
goalkeeping: 90,
isFallen: false,
fallTimer: 0,
teamName: 'GK'
});
homeTeamPlayers.forEach(p => p.hasBall = false);
homeTeamPlayers[0].hasBall = true;
homeTeamPlayers[0].x = 380;
homeTeamPlayers[0].y = 340;
sayComment("โฝ Penalty practice! Pick your spot!", "๐ฏ");
}
// ========== OTHER FUNCTIONS ==========
function updateCoins() {
document.getElementById('coinDisplay').textContent = `๐ช ${coins.toLocaleString()}`;
document.getElementById('gemDisplay').textContent = `๐ ${gems}`;
document.getElementById('trophyDisplay').textContent = `๐ ${trophies}`;
const settingsCoins = document.getElementById('settingsCoins');
const settingsTrophies = document.getElementById('settingsTrophies');
if (settingsCoins) settingsCoins.textContent = coins.toLocaleString();
if (settingsTrophies) settingsTrophies.textContent = trophies;
}
function upgradePlayer() {
if (gems >= 10) {
gems -= 10;
const teamPlayers = getTeamPlayers(selectedTeam.name);
const p = teamPlayers[currentPlayerIndex % teamPlayers.length];
if (p.rating < 99) {
p.rating += 1;
p.shooting = (p.shooting || 50) + 2;
p.defence = (p.defence || 50) + 2;
p.tackling = (p.tackling || 50) + 2;
sayComment(`โฌ ${p.name} upgraded to ${p.rating}!`, 'โญ');
} else {
sayComment("Already max rating!", "โญ");
}
currentPlayerIndex++;
updateCoins();
} else {
sayComment("Not enough gems!", "โ");
}
}
function initMatchCanvas() {
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
setupJoystick();
}
function toggleSound() {
soundEnabled = !soundEnabled;
document.getElementById('soundSetting').textContent = soundEnabled ? 'ON' : 'OFF';
if (soundEnabled) {
sayComment("๐ Sound on!", "๐");
}
}
// ========== INIT ==========
renderTeams();
updateCoins();
loadLeagueStandings();
updateChampionsLeagueUI();
updateClubWorldCupUI();
refreshTransfers();
updateCupStore();
setTactic('balanced');
loadStoredMusic();
function handleResize() {
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
const replayCanvas = document.getElementById('replayCanvas');
if (replayCanvas) {
replayCanvas.width = replayCanvas.clientWidth || 300;
replayCanvas.height = replayCanvas.clientHeight || 180;
}
setTimeout(setupJoystick, 200);
}
window.addEventListener('resize', handleResize);
window.addEventListener('orientationchange', () => {
setTimeout(handleResize, 500);
});
document.addEventListener('DOMContentLoaded', () => {
setTimeout(handleResize, 300);
setTimeout(() => {
window.speechSynthesis.getVoices();
}, 1000);
});
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
setTimeout(setupJoystick, 500);
}
});
</script>
</body>
</html>Game Source: Dream League Soccer
Creator: SonicBear35
Libraries: none
Complexity: complex (3420 lines, 131.3 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-soccer-dream-league-sonicbear35" to link back to the original. Then publish at arcadelab.ai/publish.