Stickman Soccer - Dream League
by SonicBear353093 lines121.6 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<title>Stickman Soccer - Dream League</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;
}
@media (orientation: landscape) {
#app {
max-width: 100%;
max-height: 100vh;
height: 100vh;
border-radius: 0;
flex-direction: row;
padding: 4px;
}
#matchCanvas {
height: 100% !important;
width: 55% !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;
}
.match-controls .left-btns,
.match-controls .right-btns {
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
}
.match-controls button {
min-width: 48px !important;
min-height: 38px !important;
font-size: 10px !important;
}
#commentatorBox {
top: 8px !important;
font-size: 12px !important;
padding: 4px 12px !important;
}
#joystickArea {
width: 100px !important;
height: 100px !important;
bottom: 15px !important;
left: 8px !important;
}
#joystickKnob {
width: 38px !important;
height: 38px !important;
}
.match-controls .right-btns {
gap: 3px !important;
}
.match-controls .left-btns {
gap: 3px !important;
}
}
@media (min-width: 421px) and (orientation: portrait) {
#app {
border-radius: 40px;
height: 780px;
}
}
.screen {
display: none;
flex-direction: column;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
padding: 8px;
background: linear-gradient(145deg, #0f2a0f, #1a3a1a);
overflow-y: auto;
}
.screen.active {
display: flex;
}
#homeScreen {
justify-content: center;
align-items: center;
gap: 3px;
background: radial-gradient(circle at 50% 30%, #1a4a1a, #0a1a0a);
}
#homeScreen .logo {
font-size: 36px;
font-weight: 900;
color: #ffdd44;
text-shadow: 0 0 30px #ffaa00, 0 0 60px #ff8800;
letter-spacing: 2px;
}
#homeScreen .sub {
font-size: 10px;
color: #aaddaa;
letter-spacing: 3px;
margin-bottom: 10px;
}
.menu-btn {
background: linear-gradient(145deg, #2a6a2a, #1a4a1a);
border: 2px solid #4a9a4a;
color: white;
padding: 8px 24px;
border-radius: 60px;
font-size: 13px;
font-weight: bold;
width: 85%;
text-align: center;
margin: 2px 0;
cursor: pointer;
transition: 0.15s;
box-shadow: 0 3px 0 #0a2a0a;
letter-spacing: 1px;
touch-action: manipulation;
}
.menu-btn:active {
transform: translateY(3px);
box-shadow: none;
}
.small-btn {
padding: 4px 10px;
font-size: 9px;
width: auto;
}
.coin-display {
background: #1a3a1a;
padding: 3px 8px;
border-radius: 30px;
border: 1px solid #ffdd44;
color: #ffdd44;
font-weight: bold;
font-size: 11px;
}
.back-btn {
background: #2a4a2a;
border: none;
color: white;
padding: 3px 8px;
border-radius: 30px;
cursor: pointer;
font-size: 11px;
touch-action: manipulation;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
background: #1a3a1a;
padding: 4px 8px;
border-radius: 30px;
border: 1px solid #3a7a3a;
}
.team-grid {
display: flex;
flex-wrap: wrap;
gap: 3px;
justify-content: center;
margin: 3px 0;
}
.team-card {
background: #1a3a1a;
border: 2px solid #2a5a2a;
border-radius: 10px;
padding: 4px 3px;
width: 50px;
text-align: center;
font-size: 7px;
cursor: pointer;
transition: 0.15s;
touch-action: manipulation;
}
.team-card:active {
transform: scale(0.95);
}
.team-card .crest {
font-size: 16px;
display: block;
}
.team-card .name {
font-size: 6px;
margin-top: 1px;
color: #ccddcc;
}
#matchScreen {
padding: 0;
background: #0a1a0a;
position: relative;
}
#matchCanvas {
width: 100%;
height: 100%;
background: #2d8a2d;
border-radius: 12px;
display: block;
touch-action: none;
cursor: pointer;
image-rendering: pixelated;
}
.match-controls {
position: absolute;
bottom: 3px;
left: 0;
right: 0;
padding: 0 3px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 20;
}
.match-controls button {
pointer-events: auto;
background: rgba(0,0,0,0.8);
border: 2px solid #4a9a4a;
color: white;
border-radius: 30px;
padding: 3px 8px;
font-size: 9px;
font-weight: bold;
backdrop-filter: blur(4px);
cursor: pointer;
touch-action: manipulation;
min-width: 32px;
min-height: 32px;
}
.match-controls button:active {
transform: scale(0.9);
}
.match-controls .right-btns {
display: flex;
gap: 3px;
}
.match-controls .left-btns {
display: flex;
gap: 3px;
}
.action-btn {
background: rgba(255, 200, 0, 0.25) !important;
border-color: #ffdd44 !important;
font-size: 11px !important;
padding: 5px 12px !important;
min-width: 40px !important;
min-height: 36px !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: 8px !important;
padding: 3px 6px !important;
min-width: 30px !important;
min-height: 28px !important;
}
.tactic-btn.active {
background: rgba(68, 255, 136, 0.4) !important;
}
#commentatorBox {
position: absolute;
top: 45px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.85);
border: 2px solid #ffdd44;
border-radius: 20px;
padding: 5px 16px;
font-size: 12px;
font-weight: bold;
color: #ffdd44;
text-align: center;
max-width: 80%;
z-index: 15;
pointer-events: none;
transition: all 0.3s;
box-shadow: 0 0 30px rgba(255, 200, 0, 0.2);
min-height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
#commentatorBox .emoji {
margin-right: 6px;
font-size: 14px;
}
#joystickArea {
position: absolute;
bottom: 70px;
left: 8px;
width: 90px;
height: 90px;
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: 36px;
height: 36px;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 220, 50, 0.8), rgba(255, 200, 0, 0.3));
border: 3px solid #ffdd44;
transform: translate(-50%, -50%);
pointer-events: none;
touch-action: none;
box-shadow: 0 0 20px rgba(255, 200, 0, 0.2);
transition: none;
}
#subOverlay {
display: none;
position: absolute;
bottom: 55px;
left: 4px;
right: 4px;
background: rgba(0,0,0,0.95);
padding: 6px;
border-radius: 14px;
border: 2px solid #4a9a4a;
max-height: 150px;
overflow-y: auto;
z-index: 25;
}
#subOverlay .sub-header {
display: flex;
justify-content: space-between;
color: #ffdd44;
font-weight: bold;
margin-bottom: 3px;
font-size: 11px;
}
#subList {
display: flex;
flex-wrap: wrap;
gap: 3px;
}
#subList button {
background: #1a3a1a;
border: 1px solid #4a9a4a;
color: white;
padding: 2px 6px;
border-radius: 16px;
font-size: 8px;
cursor: pointer;
touch-action: manipulation;
flex: 1 0 auto;
min-width: 50px;
}
#subList button:active {
background: #2a5a2a;
}
#subList .health-bar {
display: inline-block;
width: 20px;
height: 4px;
border-radius: 2px;
background: #4a9a4a;
margin-left: 4px;
}
#subList .health-bar.low {
background: #ff4444;
}
#subList .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: 12px;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.8); }
to { opacity: 1; transform: scale(1); }
}
#celebrationOverlay .trophy {
font-size: 70px;
animation: bounce 1s ease infinite;
}
#celebrationOverlay .win-text {
font-size: 24px;
font-weight: bold;
color: #ffdd44;
text-shadow: 0 0 30px #ffaa00;
margin-top: 8px;
text-align: center;
}
#celebrationOverlay .win-sub {
font-size: 14px;
color: #88dd88;
margin-top: 4px;
text-align: center;
}
@keyframes bounce {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-20px) scale(1.1); }
}
.confetti {
position: absolute;
width: 8px;
height: 8px;
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; }
}
#songInfo {
position: absolute;
bottom: 100px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.8);
padding: 8px 16px;
border-radius: 20px;
font-size: 10px;
color: #88dd88;
z-index: 10;
text-align: center;
border: 1px solid #4a9a4a;
pointer-events: none;
display: none;
}
.formation-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 3px;
margin: 4px 0;
}
.formation-slot {
background: #1a3a1a;
border: 1px solid #3a7a3a;
border-radius: 8px;
padding: 3px;
text-align: center;
font-size: 8px;
cursor: pointer;
touch-action: manipulation;
}
.formation-slot:active {
border-color: #ffdd44;
}
.formation-slot .pos {
color: #88dd88;
font-weight: bold;
}
.screen::-webkit-scrollbar {
width: 3px;
}
.screen::-webkit-scrollbar-thumb {
background: #4a9a4a;
border-radius: 10px;
}
.league-standings {
background: #1a3a1a;
border-radius: 12px;
padding: 5px;
margin: 4px 0;
font-size: 9px;
}
.league-standings .row {
display: flex;
justify-content: space-between;
padding: 2px 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: 3px 6px;
border-radius: 10px;
font-size: 11px;
margin: 3px 0;
width: 100%;
}
.league-select option {
background: #0a1a0a;
}
.transfer-list {
background: #1a3a1a;
border-radius: 12px;
padding: 5px;
margin: 3px 0;
max-height: 140px;
overflow-y: auto;
}
.transfer-item {
display: flex;
justify-content: space-between;
padding: 2px 4px;
border-bottom: 1px solid #2a5a5a;
font-size: 8px;
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: 4px 6px;
background: #1a3a1a;
border-radius: 8px;
margin: 3px 0;
border: 1px solid #2a5a2a;
font-size: 10px;
}
.cup-store-item .achieved {
color: #88dd88;
}
.cup-store-item .not-achieved {
color: #557755;
}
.coming-soon {
color: #ffdd44;
text-align: center;
padding: 10px;
font-size: 14px;
}
#sonicStart {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #0a1a0a;
z-index: 50;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 12px;
}
#sonicStart .sonic-logo {
font-size: 60px;
animation: bounce 0.8s ease infinite;
}
#sonicStart .sonic-text {
font-size: 28px;
color: #ffdd44;
font-weight: bold;
text-shadow: 0 0 30px #ff8800;
margin-top: 10px;
}
#sonicStart .sonic-sub {
font-size: 14px;
color: #88dd88;
margin-top: 5px;
}
#sonicStart .tap-text {
font-size: 12px;
color: #557755;
margin-top: 20px;
animation: pulse 1.5s ease infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
#loadingScreen {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #0a1a0a;
z-index: 45;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 12px;
}
#loadingScreen .loader {
width: 50px;
height: 50px;
border: 4px solid #2a5a2a;
border-top: 4px solid #ffdd44;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#loadingScreen .load-text {
color: #88dd88;
margin-top: 10px;
font-size: 12px;
}
#loadingScreen .load-percent {
color: #ffdd44;
font-size: 20px;
font-weight: bold;
margin-top: 5px;
}
@media (max-width: 420px) {
#app {
border-radius: 0;
height: 100vh;
max-height: 100vh;
padding: 2px;
}
.menu-btn {
padding: 5px 14px;
font-size: 11px;
}
.match-controls button {
padding: 2px 6px;
font-size: 8px;
min-width: 28px;
min-height: 28px;
}
.action-btn {
padding: 3px 8px !important;
min-width: 34px !important;
min-height: 30px !important;
font-size: 9px !important;
}
#commentatorBox {
font-size: 10px;
padding: 3px 10px;
top: 35px;
min-height: 24px;
}
#joystickArea {
width: 70px;
height: 70px;
bottom: 60px;
left: 4px;
}
#joystickKnob {
width: 28px;
height: 28px;
}
}
@media (max-height: 600px) {
#joystickArea {
width: 60px;
height: 60px;
bottom: 50px;
left: 4px;
}
#joystickKnob {
width: 24px;
height: 24px;
}
.match-controls button {
min-width: 24px;
min-height: 24px;
font-size: 7px;
padding: 2px 5px;
}
}
</style>
</head>
<body>
<div id="app">
<!-- LOADING SCREEN -->
<div id="loadingScreen">
<div class="loader"></div>
<div class="load-text">Loading Dream League...</div>
<div class="load-percent" id="loadPercent">100%</div>
</div>
<!-- SONIC START SCREEN -->
<div id="sonicStart">
<div class="sonic-logo">๐ฆ</div>
<div class="sonic-text">SONIC INC</div>
<div class="sonic-sub">Dream League Soccer</div>
<div class="tap-text">๐ TAP TO START</div>
<div style="font-size:8px; color:#557755; margin-top:15px;">Graphic Design by Flex Inc</div>
</div>
<!-- HOME SCREEN -->
<div id="homeScreen" class="screen active">
<div class="logo">โฝ DREAM</div>
<div class="sub">LEAGUE SOCCER</div>
<div style="display:flex; gap:3px; margin-bottom:5px; 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:6px; font-size:7px; color:#557755;">FIFA World Cupโข ยท FIFPRO</div>
<div style="font-size:6px; color:#3a5a3a; margin-top:2px;">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:11px;">๐๏ธ SELECT TEAM</span>
<span class="coin-display" style="font-size:9px;">๐ช 1M</span>
</div>
<div class="team-grid" id="teamGrid"></div>
<button class="menu-btn" style="margin-top:5px;" onclick="startMatch('friendly')">โ๏ธ KICK OFF</button>
<div style="font-size:7px; color:#557755; text-align:center; margin-top:2px;">Tap a team to select</div>
</div>
<!-- MATCH SCREEN -->
<div id="matchScreen" class="screen">
<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="songInfo">๐ต Press power button to add song from your files</div>
<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:12px; width:60%;" onclick="closeCelebration()">๐ CONTINUE</button>
</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()">โฌ PASS</button>
<button class="action-btn" id="shootBtn" onmousedown="doShoot()" ontouchstart="doShoot()">โก SHOOT</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:14px;">โ</button>
</div>
<div id="subList"></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:11px;">๐ 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:5px;" onclick="startLeagueMatch()">โถ PLAY LEAGUE MATCH</button>
<div style="font-size:7px; color:#557755; margin-top:3px;">Win 9 matches to win the league!</div>
<div style="font-size:7px; 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:11px;">๐ CHAMPIONS LEAGUE</span>
<span></span>
</div>
<div style="background:#1a3a1a; border-radius:12px; padding:6px; margin:3px 0;">
<div style="color:#ffdd44; font-weight:bold; font-size:11px; text-align:center;">KNOCKOUT STAGE</div>
<div id="clProgress" style="font-size:9px; padding:3px 0; color:#88dd88; text-align:center;">Progress: 0/3 wins</div>
<div style="font-size:9px; padding:3px 0; border-bottom:1px solid #2a5a2a;" id="clStage1">โฌ Round of 16</div>
<div style="font-size:9px; padding:3px 0; border-bottom:1px solid #2a5a2a;" id="clStage2">โฌ Quarter Final</div>
<div style="font-size:9px; padding:3px 0; border-bottom:1px solid #2a5a2a;" id="clStage3">โฌ Semi Final</div>
<div style="font-size:9px; padding:3px 0; color:#ffdd44;" id="clStage4">โฌ FINAL</div>
</div>
<button class="menu-btn small-btn" onclick="startChampionsLeagueMatch()">โถ PLAY CHAMPIONS LEAGUE</button>
<div style="font-size:7px; color:#557755; margin-top:3px;">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:11px;">๐ CLUB WORLD CUP</span>
<span></span>
</div>
<div style="background:#1a3a1a; border-radius:12px; padding:6px; margin:3px 0;">
<div style="color:#ffdd44; font-weight:bold; font-size:11px; text-align:center;">FIFA CLUB WORLD CUP</div>
<div id="cwcProgress" style="font-size:9px; padding:3px 0; color:#88dd88; text-align:center;">Progress: 0/3 wins</div>
<div style="font-size:9px; padding:3px 0; border-bottom:1px solid #2a5a2a;" id="cwcStage1">โฌ Quarter Final</div>
<div style="font-size:9px; padding:3px 0; border-bottom:1px solid #2a5a2a;" id="cwcStage2">โฌ Semi Final</div>
<div style="font-size:9px; padding:3px 0; color:#ffdd44;" id="cwcStage3">โฌ FINAL</div>
</div>
<button class="menu-btn small-btn" onclick="startClubWorldCupMatch()">โถ PLAY WORLD CUP</button>
<div style="font-size:7px; color:#557755; margin-top:3px;">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:11px;">๐ TRANSFERS</span>
<span></span>
</div>
<div style="font-size:9px; color:#88dd88; text-align:center; margin-bottom:3px;">Available Players</div>
<div class="transfer-list" id="transferList"></div>
<button class="menu-btn small-btn" style="margin-top:4px;" onclick="refreshTransfers()">๐ REFRESH</button>
<div style="font-size:7px; color:#557755; margin-top:3px;">New players appear every match!</div>
<div style="font-size:7px; color:#557755; margin-top:2px;">๐ก Download songs from audio.com or any MP3 site</div>
</div>
<!-- TRAINING -->
<div id="trainingScreen" class="screen">
<div class="header">
<button class="back-btn" onclick="showScreen('homeScreen')">โ</button>
<span style="font-size:11px;">โก TRAINING</span>
<span></span>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:3px; margin-top:5px;">
<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:6px; background:#1a3a1a; padding:5px; border-radius:12px;">
<span class="text-gold">๐ Gems: 50</span><br>
<span class="text-green" style="font-size:9px;">โฌ Upgrade player (+1) cost: 10 gems</span>
<button class="menu-btn small-btn" style="margin-top:3px;" 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:11px;">๐ FORMATION 4-3-3</span>
<span></span>
</div>
<div class="formation-grid" id="formationGrid"></div>
<div style="margin-top:5px; background:#1a3a1a; padding:4px; border-radius:12px;">
<div class="text-gold" style="font-size:9px;">AI TEAM FORMATION (4-4-2)</div>
<div style="display:flex; gap:2px; justify-content:center; flex-wrap:wrap; font-size:7px;">
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">GK</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">LB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">CB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">CB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">RB</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">LM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">CM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">CM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">RM</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">ST</span>
<span class="formation-slot" style="border-color:#ff8844; padding:1px 3px;">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:11px;">๐ CUP STORE</span>
<span></span>
</div>
<div style="font-size:9px; color:#88dd88; text-align:center; margin-bottom:4px;">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:11px;">โ๏ธ SETTINGS</span>
<span></span>
</div>
<div style="margin-top:10px; font-size:11px;">
<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="savedReplays">0</span></div>
<button class="menu-btn small-btn" style="margin-top:6px;" onclick="toggleSound()">๐ TOGGLE SOUND</button>
<button class="menu-btn small-btn" style="margin-top:3px;" onclick="viewReplays()">๐น VIEW REPLAYS</button>
<button class="menu-btn small-btn" style="margin-top:3px;" onclick="showComingSoon('Live Multiplayer')">๐ LIVE MULTIPLAYER</button>
<button class="menu-btn small-btn" style="margin-top:3px;" onclick="showComingSoon('More Games')">๐ฎ MORE GAMES</button>
</div>
<div style="margin-top:8px; font-size:8px; color:#557755; text-align:center;">
๐ก Add songs: Download MP3 from audio.com or any MP3 site
</div>
</div>
</div>
<script>
// ========== OPTIMIZED GAME ENGINE ==========
// All game state and logic with performance optimizations
// ========== REAL PLAYER DATA ==========
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: 'Tchouameni', pos: 'CM', rating: 86, number: 18, shooting: 70, defence: 80, tackling: 78, 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: 'Christensen', pos: 'CB', rating: 85, number: 15, shooting: 35, defence: 85, tackling: 82, 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: 'Mac Allister', pos: 'CM', rating: 86, number: 10, shooting: 74, defence: 68, tackling: 65, goalkeeping: 10 },
{ name: 'Szoboszlai', pos: 'CM', rating: 85, number: 8, shooting: 78, defence: 60, tackling: 55, goalkeeping: 10 },
{ name: 'Jones', pos: 'CM', rating: 82, number: 17, shooting: 70, defence: 65, tackling: 62, 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: 'Bernardo', pos: 'RW', rating: 87, number: 20, shooting: 80, defence: 55, tackling: 50, 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 },
{ name: 'Doku', pos: 'RW', rating: 83, number: 11, shooting: 76, defence: 30, tackling: 25, 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: 'Kim Min-jae', pos: 'CB', rating: 86, number: 3, shooting: 35, defence: 86, tackling: 83, goalkeeping: 10 },
{ name: 'Davies', pos: 'LB', rating: 85, number: 19, shooting: 52, defence: 82, tackling: 78, goalkeeping: 10 },
{ name: 'Goretzka', pos: 'CM', rating: 86, number: 8, shooting: 74, defence: 75, tackling: 72, 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: 'Kane', pos: 'ST', rating: 91, number: 9, shooting: 90, defence: 50, tackling: 45, goalkeeping: 10 },
{ name: 'Mรผller', pos: 'ST', rating: 88, number: 25, shooting: 84, defence: 55, tackling: 50, goalkeeping: 10 },
{ name: 'Gnabry', pos: 'LW', rating: 85, number: 7, shooting: 82, defence: 35, tackling: 30, 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: 'Skriniar', pos: 'CB', rating: 86, number: 37, shooting: 35, defence: 86, tackling: 83, goalkeeping: 10 },
{ name: 'Hernandez', pos: 'LB', rating: 85, number: 21, shooting: 50, defence: 84, tackling: 80, goalkeeping: 10 },
{ name: 'Ugarte', pos: 'CM', rating: 84, number: 4, shooting: 65, defence: 78, tackling: 76, goalkeeping: 10 },
{ name: 'Vitinha', pos: 'CM', rating: 85, number: 17, shooting: 72, defence: 65, tackling: 60, goalkeeping: 10 },
{ name: 'Zaire-Emery', pos: 'CM', rating: 83, number: 33, shooting: 68, defence: 60, tackling: 58, 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;
// ========== 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!", "๐ฅ ROCKET OF A SHOT! GOAL!"
],
pass: ["โฌ Clean pass!", "๐ฏ Perfect through ball!", "๐ Great vision!", "๐ค Nice one-touch pass!"],
shoot: ["๐จ Shot on target!", "๐ฏ Testing the keeper!", "โก Powerful strike!", "๐ช Over the bar!"],
tackle: ["๐ก๏ธ Clean tackle!", "๐ช Strong challenge!", "โ๏ธ Ball won back!", "๐ Great defending!"],
miss: ["๐ฑ Oh no! Missed it!", "๐ค Unlucky! So close!", "๐
Off target!", "๐คฏ How did he miss?"],
aiGoal: ["๐ค AI scores! Unlucky!", "๐คฌ Against the run of play!", "๐ญ They've equalized!", "๐ AI takes the lead!"],
foul: ["โ ๏ธ Foul! Free kick!", "๐จ Yellow card!", "โก Free kick opportunity!", "๐ด RED CARD! SENT OFF!"],
corner: ["๐ Corner kick!", "๐ฏ Cross coming in!", "๐ Set piece time!"],
throwin: ["๐ Throw-in!", "๐ค Play restarts!"],
penalty: ["โฝ PENALTY!", "๐ฏ Spot kick!", "๐งค Keeper ready!"],
save: ["๐งค Great save!", "๐ Keeper denies!", "๐ช What a stop!"],
kickoff: ["๐๏ธ And we're underway!", "โฝ Kickoff! Let's go!", "๐๏ธ The match begins!"]
};
// ========== INITIALIZATION ==========
function initGame() {
// Show loading
document.getElementById('loadingScreen').style.display = 'flex';
// Simulate loading
let progress = 0;
const loadInterval = setInterval(() => {
progress += 5;
document.getElementById('loadPercent').textContent = Math.min(100, progress) + '%';
if (progress >= 100) {
clearInterval(loadInterval);
document.getElementById('loadingScreen').style.display = 'none';
document.getElementById('sonicStart').style.display = 'flex';
}
}, 50);
}
// Start game on tap
document.getElementById('sonicStart').addEventListener('click', function() {
this.style.display = 'none';
document.getElementById('homeScreen').classList.add('active');
renderTeams();
updateCoins();
loadLeagueStandings();
updateChampionsLeagueUI();
updateClubWorldCupUI();
refreshTransfers();
updateCupStore();
setupJoystick();
// Play initial voice
setTimeout(() => {
sayComment("Welcome to Dream League Soccer!", "๐๏ธ");
}, 500);
});
// ========== UI HELPERS ==========
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(id).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') {
setTimeout(() => {
initMatchCanvas();
document.getElementById('joystickArea').style.display = 'block';
document.getElementById('songInfo').style.display = 'block';
}, 100);
}
}
function renderTeams() {
const grid = document.getElementById('teamGrid');
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');
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');
let html = `<div style="color:#ffdd44; font-weight:bold; font-size:11px; text-align:center; margin-bottom:3px;">${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;
document.getElementById('leagueProgress').textContent = `Progress: ${leagueWins}/9 wins`;
}
function updateCupStore() {
const container = document.getElementById('cupStoreList');
let html = '';
cupData.forEach(cup => {
const achieved = cup.achieived || 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('savedReplays').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 6px;border-radius:12px;font-size:7px;cursor:pointer;" onclick="buyPlayer('${p.name}')">BUY</button>
</div>`;
});
container.innerHTML = html || '<div style="text-align:center;color:#557755;padding:8px;">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!');
}
}
// ========== COMMENTATOR ==========
function sayComment(text, emoji = '๐๏ธ') {
const box = document.getElementById('commentatorBox');
const textEl = document.getElementById('commentatorText');
if (box && textEl) {
textEl.textContent = text;
box.querySelector('.emoji').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)';
}, 3000);
}
// Voice synthesis
if (soundEnabled && window.speechSynthesis) {
try {
const utterance = new SpeechSynthesisUtterance(text.replace(/[^a-zA-Z0-9 ]/g, ''));
utterance.rate = 0.85;
utterance.pitch = 1.1;
window.speechSynthesis.speak(utterance);
} catch(e) {}
}
}
function randomPhrase(phraseArray) {
return phraseArray[Math.floor(Math.random() * phraseArray.length)];
}
// ========== JOYSTICK CONTROLS ==========
function setupJoystick() {
const area = document.getElementById('joystickArea');
const knob = document.getElementById('joystickKnob');
if (!area || !knob) return;
const radius = area.offsetWidth / 2 - knob.offsetWidth / 2;
function handleMove(clientX, clientY) {
const rect = area.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
let dx = clientX - centerX;
let dy = clientY - centerY;
const dist = Math.sqrt(dx * dx + dy * dy);
const maxDist = rect.width / 2 - knob.offsetWidth / 2;
if (dist > maxDist) {
dx = (dx / dist) * maxDist;
dy = (dy / dist) * maxDist;
}
knob.style.transform = `translate(${dx}px, ${dy}px)`;
joystickX = dx / maxDist;
joystickY = dy / maxDist;
joystickActive = true;
movePlayerWithJoystick(joystickX, joystickY);
}
function handleEnd() {
knob.style.transform = 'translate(0, 0)';
joystickX = 0;
joystickY = 0;
joystickActive = false;
}
area.addEventListener('touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
area.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (touch) handleMove(touch.clientX, touch.clientY);
}, { passive: false });
area.addEventListener('touchend', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
area.addEventListener('touchcancel', (e) => {
e.preventDefault();
handleEnd();
}, { passive: false });
let isDragging = false;
area.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) * 8,
y: pos.y + (Math.random() - 0.5) * 8,
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
});
});
// AI team - use actual club names
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) * 8,
y: pos.y + (Math.random() - 0.5) * 8,
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;
// Say opponent name
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;
document.getElementById('subOverlay').style.display = 'none';
document.getElementById('celebrationOverlay').style.display = 'none';
initPlayers();
const canvas = document.getElementById('matchCanvas');
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
matchActive = true;
if (matchInterval) clearInterval(matchInterval);
if (frameId) cancelAnimationFrame(frameId);
matchInterval = setInterval(() => {
matchTime++;
gameTime++;
gameClock++;
if (!isSetPiece && !isPenalty) {
updateMatch();
}
drawMatch();
const progress = Math.min(1, gameClock / totalMatchTime);
if (gameClock >= totalMatchTime) {
clearInterval(matchInterval);
matchActive = false;
endMatch();
}
}, 1000);
function animate() {
if (!matchActive) return;
drawMatch();
frameId = requestAnimationFrame(animate);
}
animate();
setTimeout(setupJoystick, 300);
setTimeout(refreshTransfers, 500);
setTactic('balanced');
}
function updateMatch() {
// Home team movement with tactics
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;
});
// AI team movement - more aggressive
const aiTeamName = awayTeamPlayers[0]?.teamName || 'AI';
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;
});
// Ball physics
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;
}
// Ball bounds
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; }
// Corner / Throw-in
if (ball.x < 5 || ball.x > 395) {
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++;
// Check if in box - penalty
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;
}
// Cards
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!", "๐ด");
// Remove player
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;
}
});
}
});
// AI steals
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), '๐ก๏ธ');
}
});
// Home steals
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), '๐ก๏ธ');
}
});
// AI attacks
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;
const ratingFactor = (aiAttacker.rating || 80) / 100;
if (Math.random() < 0.2 * ratingFactor) {
scoreAway++;
sayComment(randomPhrase(commentatorPhrases.aiGoal), '๐ค');
setTimeout(() => resetBall(), 500);
} else {
sayComment(randomPhrase(commentatorPhrases.miss), '๐
');
setTimeout(() => {
const idx = Math.floor(Math.random() * homeTeamPlayers.length);
homeTeamPlayers.forEach(p => p.hasBall = false);
homeTeamPlayers[idx].hasBall = true;
}, 300);
}
}
// Referee
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) {
const targetY = 340 + (Math.random() - 0.5) * 80;
const power = 0.08;
ball.vx = (50 - ball.x) * power;
ball.vy = (targetY - ball.y) * power;
penaltyTaker.hasBall = false;
const keeperDive = (Math.random() - 0.5) * 60;
keeper.y = 340 + keeperDive;
if (Math.abs(ball.y - 340) < 30 && Math.random() < 0.5) {
scoreHome++;
sayComment("โก GOAL! Perfect penalty!", "โก");
coins += 100000;
updateCoins();
} else if (Math.abs(ball.y - keeper.y) < 20) {
sayComment("๐งค SAVED! Great keeping!", "๐งค");
} else {
sayComment("๐
Penalty missed!", "๐
");
}
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;
}
// ========== DRAW FUNCTIONS ==========
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;
// Green pitch
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);
// Pitch markings - white lines
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();
// Draw players
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);
}
});
// Referee
ctx.fillStyle = '#ffdd44';
ctx.font = '14px sans-serif';
ctx.fillText('๐จโโ๏ธ', referee.x-8, referee.y-12);
// Ball
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;
// Score
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(10, 8, W/2-10, 30);
ctx.fillRect(W/2+10, 8, W/2-20, 30);
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 16px sans-serif';
ctx.fillText(`${selectedTeam.name} ${scoreHome}`, 15, 30);
ctx.fillStyle = '#ff6666';
const aiName = awayTeamPlayers[0]?.teamName || 'AI';
ctx.fillText(`${aiName} ${scoreAway}`, W-90, 30);
// Clock
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-45, 8, 90, 20);
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 12px sans-serif';
ctx.fillText(`${String(displayMins).padStart(2,'0')}:${String(displaySecs).padStart(2,'0')}`, W/2-30, 24);
// Time bar
const barWidth = 80;
const barX = W/2 - 40;
const barY = 30;
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);
// Cards
if (yellowCards > 0 || redCards > 0) {
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(W-60, 45, 50, 16);
let cardText = '';
if (yellowCards > 0) cardText += `๐จ${yellowCards}`;
if (redCards > 0) cardText += ` ๐ด${redCards}`;
ctx.fillStyle = '#fff';
ctx.font = '9px sans-serif';
ctx.fillText(cardText, W-55, 57);
}
// Set piece indicator
if (isSetPiece || isPenalty) {
ctx.fillStyle = '#ffdd44';
ctx.font = 'bold 13px sans-serif';
const labels = {
'free-kick': 'โก FREE KICK',
'corner': '๐ CORNER',
'throw-in': '๐ THROW-IN',
'penalty': 'โฝ PENALTY'
};
ctx.fillText(labels[setPieceType] || '', W/2-50, 70);
}
// Tactics indicator
ctx.fillStyle = 'rgba(255,255,255,0.15)';
ctx.font = '8px sans-serif';
const tacticLabels = { balanced: 'โ๏ธ BAL', attack: 'โก ATK', defence: '๐ก๏ธ DEF' };
ctx.fillText(tacticLabels[currentTactic] || 'BAL', W-60, H-8);
// Match type
const typeLabels = {
'friendly': 'FRIENDLY',
'league': 'LEAGUE',
'champions': 'CHAMPIONS LEAGUE',
'worldcup': 'CLUB WORLD CUP',
'training': 'TRAINING'
};
ctx.fillText(typeLabels[currentMatchType] || 'FRIENDLY', 10, H-8);
}
function drawStickman(ctx, x, y, color, hasBall, stamina, number, name) {
ctx.shadowBlur = 0;
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.2)';
ctx.beginPath();
ctx.ellipse(x, y+30, 12, 4, 0, 0, Math.PI*2);
ctx.fill();
// Stamina
if (stamina !== undefined) {
ctx.fillStyle = stamina > 70 ? '#4a9a4a' : stamina > 40 ? '#ffdd44' : '#ff4444';
ctx.fillRect(x-10, y-38, 20 * (stamina/100), 3);
}
// Name
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.font = '7px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(name || '', x, y-42);
ctx.textAlign = 'left';
// Number
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '6px sans-serif';
ctx.fillText(number || '', x-2, y-34);
ctx.strokeStyle = color;
ctx.lineWidth = 2.5;
// Head
ctx.beginPath();
ctx.arc(x, y-12, 8, 0, Math.PI*2);
ctx.stroke();
ctx.fillStyle = color;
ctx.fillRect(x-4, y-14, 2, 2);
ctx.fillRect(x+2, y-14, 2, 2);
// Body
ctx.beginPath();
ctx.moveTo(x, y-4);
ctx.lineTo(x, y+14);
ctx.stroke();
// Legs
const legOffset = hasBall ? Math.sin(gameTime / 2.5 + x * 2) * 5 : 0;
ctx.beginPath();
ctx.moveTo(x, y+14);
ctx.lineTo(x-6 + legOffset, y+26);
ctx.moveTo(x, y+14);
ctx.lineTo(x+6 - legOffset, y+26);
ctx.stroke();
// Arms
const armOffset = hasBall ? Math.sin(gameTime / 3 + y * 1.5) * 4 : 2;
ctx.beginPath();
ctx.moveTo(x, y+3);
ctx.lineTo(x-9 + armOffset, y-5);
ctx.moveTo(x, y+3);
ctx.lineTo(x+9 - armOffset, y-5);
ctx.stroke();
// Ball indicator
if (hasBall) {
ctx.shadowColor = 'rgba(255, 220, 50, 0.5)';
ctx.shadowBlur = 20;
ctx.fillStyle = 'rgba(255, 220, 50, 0.15)';
ctx.beginPath();
ctx.arc(x, y-16, 16, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = '#ffdd44';
ctx.font = '7px sans-serif';
ctx.fillText('โฝ', x-3, y-30);
}
}
// ========== 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!", "๐
");
}
}
function doShoot() {
if (!matchActive || isSetPiece || isPenalty) return;
const shooter = homeTeamPlayers.find(p => p.hasBall && !p.isFallen);
if (!shooter) {
sayComment("Get the ball first!", "โ");
return;
}
// Show pressure indicator
shootPressure = 100;
setTimeout(() => { shootPressure = 0; }, 500);
// Training modes
if (currentMatchType === 'training') {
if (trainingType === 'freekick' || trainingType === 'penalty') {
const targetY = 340 + (Math.random() - 0.5) * 60;
ball.vx = (50 - ball.x) * 0.08;
ball.vy = (targetY - ball.y) * 0.08;
shooter.hasBall = false;
if (Math.random() < 0.5) {
scoreHome++;
sayComment("โก GOAL! Perfect training shot!", "โก");
setTimeout(() => resetBall(), 600);
} else {
sayComment("๐
Good effort! Try again!", "๐
");
}
return;
}
}
// Check if AI players are far enough for clear shot
const aiNear = awayTeamPlayers.some(p => {
const dist = Math.hypot(p.x - shooter.x, p.y - shooter.y);
return dist < 40 && p.id !== 0;
});
let power = 0.06 + (shooter.rating || 80) / 2000 + (shooter.shooting || 50) / 3000;
if (currentTactic === 'attack') power *= 1.2;
const targetX = 380 + (Math.random() - 0.5) * 40;
const targetY = 340 + (Math.random() - 0.5) * 80;
ball.vx = (targetX - ball.x) * power;
ball.vy = (targetY - ball.y) * power;
shooter.hasBall = false;
// Goal chance based on position and AI proximity
const distToGoal = Math.hypot(390 - ball.x, 340 - ball.y);
const accuracy = Math.max(0.1, 0.7 - (distToGoal / 500));
const ratingBonus = (shooter.rating || 80) / 100;
const aiBlock = aiNear ? 0.3 : 0.1;
const goalChance = (0.15 * accuracy * ratingBonus + 0.05) - aiBlock;
if (Math.random() < goalChance) {
scoreHome++;
sayComment(randomPhrase(commentatorPhrases.goal), 'โก');
coins += 200000;
gems += 1;
updateCoins();
setTimeout(() => resetBall(), 600);
} else if (Math.random() < 0.3) {
sayComment(randomPhrase(commentatorPhrases.shoot), '๐ฏ');
// Keeper save
const keeper = awayTeamPlayers[0];
if (keeper && Math.abs(ball.y - 340) < 30) {
sayComment(randomPhrase(commentatorPhrases.save), '๐งค');
}
setTimeout(() => {
const aiIdx = Math.floor(Math.random() * awayTeamPlayers.length);
awayTeamPlayers.forEach(p => p.hasBall = false);
awayTeamPlayers[aiIdx].hasBall = true;
}, 300);
} else {
sayComment(randomPhrase(commentatorPhrases.miss), '๐
');
setTimeout(() => {
const aiIdx = Math.floor(Math.random() * awayTeamPlayers.length);
awayTeamPlayers.forEach(p => p.hasBall = false);
awayTeamPlayers[aiIdx].hasBall = true;
}, 200);
}
}
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 {
// Foul
isSetPiece = true;
setPieceType = 'free-kick';
setPiecePosition = { x: ball.x, y: ball.y };
p.isFallen = true;
p.fallTimer = 20;
foulCount++;
sayComment(randomPhrase(commentatorPhrases.foul), 'โ ๏ธ');
// Cards
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! Pressure!" : "โฉ Second press OFF", "โฉ");
document.getElementById('secondPressBtn').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];
// Find a player not currently on the field
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');
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:${healthPercent}%;"></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;
sayComment("Match abandoned!", "๐ช");
setTimeout(() => showScreen('teamSelectScreen'), 500);
}
// ========== END MATCH ==========
function endMatch() {
const won = scoreHome > scoreAway;
const drew = scoreHome === scoreAway;
if (won) {
coins += 1000000;
gems += 2;
if (currentMatchType === 'league') {
leagueWins++;
document.getElementById('leagueProgress').textContent = `Progress: ${leagueWins}/9 wins`;
if (leagueWins >= 9) {
trophies++;
showCelebration(`๐ LEAGUE CHAMPIONS!`, `You won ${leagueData[currentLeague].name}!`);
coins += leagueData[currentLeague].reward || 3000000;
// Mark cup as achieved
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();
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 < 50; 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() * 6 + 3) + 'px';
confetti.style.height = (Math.random() * 6 + 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';
}
}
}
document.getElementById('clProgress').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';
}
}
}
document.getElementById('cwcProgress').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');
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
matchActive = true;
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;
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) * 8,
y: pos.y + (Math.random() - 0.5) * 8,
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) * 8,
y: pos.y + (Math.random() - 0.5) * 8,
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!", "๐ฏ");
}
// ========== REPLAY SYSTEM ==========
function showReplay(title) {
// Simple replay notification
sayComment(`๐ ${title} - Replay saved!`, '๐');
savedReplays.push({
title: title,
time: gameTime,
score: `${scoreHome}-${scoreAway}`,
savedAt: new Date().toLocaleTimeString()
});
document.getElementById('savedReplays').textContent = savedReplays.length;
}
function viewReplays() {
if (savedReplays.length === 0) {
alert("No saved replays yet!");
return;
}
let msg = "๐น SAVED REPLAYS:\n\n";
savedReplays.forEach((r, i) => {
msg += `${i+1}. ${r.title} - ${r.score} (${r.savedAt})\n`;
});
alert(msg);
}
function toggleSound() {
soundEnabled = !soundEnabled;
document.getElementById('soundSetting').textContent = soundEnabled ? 'ON' : 'OFF';
if (soundEnabled) {
sayComment("๐ Sound on!", "๐");
}
}
// ========== OTHER FUNCTIONS ==========
function updateCoins() {
document.getElementById('coinDisplay').textContent = `๐ช ${coins.toLocaleString()}`;
document.getElementById('gemDisplay').textContent = `๐ ${gems}`;
document.getElementById('trophyDisplay').textContent = `๐ ${trophies}`;
document.getElementById('settingsCoins').textContent = coins.toLocaleString();
document.getElementById('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;
}
}
// ========== INIT ==========
// Start the game
initGame();
// Global event listeners
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
}, 200);
setTimeout(setupJoystick, 300);
});
window.addEventListener('resize', () => {
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
setupJoystick();
});
window.addEventListener('orientationchange', () => {
setTimeout(() => {
const canvas = document.getElementById('matchCanvas');
if (canvas) {
canvas.width = canvas.clientWidth || 400;
canvas.height = canvas.clientHeight || 700;
}
setupJoystick();
}, 400);
});
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
setTimeout(setupJoystick, 300);
}
});
</script>
</body>
</html>Game Source: Stickman Soccer - Dream League
Creator: SonicBear35
Libraries: none
Complexity: complex (3093 lines, 121.6 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.