/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a3d2f }); /**** * Game Code ****/ // Player class: represents a footballer // --- CONSTANTS --- var Player = function Player(name, attack, defense, stamina, value, seasonsRemaining) { var self = {}; self.name = name; self.attack = attack; self.defense = defense; self.stamina = stamina; self.value = value; self.maxStamina = stamina; self.inSquad = false; // true if in starting 5 self.seasonsRemaining = typeof seasonsRemaining === "number" ? seasonsRemaining : null; // null for non-transfer players, or integer for transfer market return self; }; // Team class: holds a list of players var Team = function Team(name, players) { var self = {}; self.name = name; self.players = players; // array of Player return self; }; var SQUAD_SIZE = 5; var BENCH_SIZE = 3; var INITIAL_BUDGET = 100; var PLAYER_MIN_VALUE = 10; var PLAYER_MAX_VALUE = 40; // --- GLOBALS --- var allPlayers = []; // All players owned by user var squad = []; // Starting 5 var bench = []; // Bench 3 var transferList = []; // Players available to buy var budget = INITIAL_BUDGET; var opponentTeam = null; var matchInProgress = false; var matchLog = []; var matchResult = null; var selectedPlayerIdx = null; // For swapping var selectedBenchIdx = null; // For swapping var infoText = null; var budgetText = null; var matchText = null; var transferText = null; var transferBtns = []; var swapBtns = []; var playBtn = null; var nextBtn = null; var sellBtns = []; var buyBtns = []; var squadLabels = []; var benchLabels = []; var opponentLabels = []; var guiY = 0; // --- YOUTH ACADEMY --- var youthAcademy = []; // Array of young players waiting for promotion/sale var youthLabels = []; var promoteBtns = []; var sellYouthBtns = []; var youthTimer = null; var YOUTH_TIMER_INTERVAL = 10000; // 10 seconds for demo (tweak as needed) var YOUTH_MAX = 3; // Max youth in academy at once // --- TRANSFER OFFERS SYSTEM --- // Each offer: {player: Player, offerValue: number, club: string} var transferOffers = []; var offerLabels = []; var acceptOfferBtns = []; var rejectOfferBtns = []; var OFFER_TIMER = null; var OFFER_INTERVAL = 15000; // 15 seconds for demo var OFFER_CLUBS = ["Galatasaray", "Fenerbahce", "Besiktas", "Trabzonspor", "Basaksehir", "Sivasspor", "Konyaspor", "Antalyaspor", "Alanyaspor", "Denizlispor"]; // --- UTILS --- function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function randomName() { var first = ["Ahmet", "Mehmet", "Mustafa", "Ali", "Hüseyin", "Hasan", "Cesur", "Osman", "Yusuf", "Murat", "Emre", "Burak", "Fatih", "Serkan", "Onur", "Barış", "Cem", "Eren", "Kaan", "Deniz", "Çınar", "Aziz", "Ege", "Miraç"]; var last = ["Yılmaz", "Kaya", "Demir", "Şahin", "Çelik", "Yıldız", "Yıldırım", "Aydın", "Öztürk", "Arslan", "Doğan", "Kılıç", "Aslan", "Polat", "Koç", "Kurt", "Özdemir", "Aksoy", "Güneş", "Bozkurt", "Bozbalak", "Sakız", "Fizikli"]; return first[randomInt(0, first.length - 1)] + " " + last[randomInt(0, last.length - 1)]; } function makeRandomPlayer() { var atk = randomInt(5, 15); var def = randomInt(5, 15); var sta = randomInt(10, 20); var val = Math.floor((atk + def + sta) / 3) + randomInt(PLAYER_MIN_VALUE, PLAYER_MAX_VALUE); return new Player(randomName(), atk, def, sta, val); } // Real-life Turkish Super Lig squads (2023/24, main players, 5 per team for demo) var realSquads = { "Galatasaray": [new Player("Mauro Icardi", 18, 8, 16, 40), new Player("Dries Mertens", 16, 7, 15, 36), new Player("Lucas Torreira", 10, 16, 17, 34), new Player("Kerem Aktürkoğlu", 15, 8, 15, 32), new Player("Fernando Muslera", 7, 18, 16, 35)], "Fenerbahce": [new Player("Edin Dzeko", 17, 7, 15, 38), new Player("Dusan Tadic", 16, 8, 15, 36), new Player("Fred", 12, 14, 16, 33), new Player("Sebastian Szymanski", 15, 9, 15, 32), new Player("Dominik Livakovic", 6, 17, 16, 34)], "Besiktas": [new Player("Cenk Tosun", 16, 7, 15, 34), new Player("Rachid Ghezzal", 15, 8, 14, 32), new Player("Salih Uçan", 12, 13, 15, 30), new Player("Omar Colley", 8, 16, 15, 31), new Player("Mert Günok", 6, 17, 15, 30)], "Trabzonspor": [new Player("Edin Visca", 15, 8, 15, 32), new Player("Anastasios Bakasetas", 15, 9, 15, 32), new Player("Uğurcan Çakır", 6, 17, 16, 33), new Player("Enis Bardhi", 14, 8, 14, 29), new Player("Joaquin Fernandez", 8, 15, 14, 28)], "Basaksehir": [new Player("Danijel Aleksic", 14, 8, 14, 28), new Player("Leo Duarte", 8, 15, 14, 27), new Player("Serdar Gürler", 13, 8, 14, 27), new Player("Mahmut Tekdemir", 9, 14, 14, 26), new Player("Volkan Babacan", 6, 16, 14, 25)], "Sivasspor": [new Player("Mustapha Yatabare", 14, 8, 14, 27), new Player("Max Gradel", 13, 8, 14, 27), new Player("Hakan Arslan", 10, 13, 14, 25), new Player("Uğur Çiftçi", 8, 14, 14, 24), new Player("Ali Şaşal Vural", 6, 16, 14, 24)], "Konyaspor": [new Player("Sokol Cikalleshi", 14, 8, 14, 27), new Player("Amir Hadziahmetovic", 11, 13, 14, 25), new Player("Guilherme", 10, 13, 14, 25), new Player("Francisco Calvo", 8, 15, 14, 25), new Player("Ibrahim Sehic", 6, 16, 14, 24)], "Antalyaspor": [new Player("Haji Wright", 14, 8, 14, 27), new Player("Fernando", 11, 13, 14, 25), new Player("Bünyamin Balcı", 10, 13, 14, 24), new Player("Veysel Sarı", 8, 15, 14, 24), new Player("Helton Leite", 6, 16, 14, 24)], "Alanyaspor": [new Player("Efecan Karaca", 14, 8, 14, 27), new Player("Famara Diedhiou", 13, 8, 14, 26), new Player("Yusuf Özdemir", 10, 13, 14, 24), new Player("Fidan Aliti", 8, 15, 14, 24), new Player("Runar Runarsson", 6, 16, 14, 24)], "Denizlispor": [new Player("Ömer Şişmanoğlu", 13, 8, 14, 25), new Player("Mustafa Yumlu", 8, 15, 14, 24), new Player("Gökhan Süzen", 10, 13, 14, 23), new Player("Oğuz Yılmaz", 8, 14, 14, 23), new Player("Adam Stachowiak", 6, 16, 14, 23)] }; function makeOpponentTeam() { // List of realistic Turkish club names var clubNames = ["Denizlispor", "Sivasspor", "Galatasaray", "Fenerbahce", "Trabzonspor", "Besiktas", "Basaksehir", "Konyaspor", "Antalyaspor", "Alanyaspor"]; // Pick a random club name for the opponent var clubName = clubNames[randomInt(0, clubNames.length - 1)]; var oppPlayers; if (realSquads[clubName]) { // Use real squad, clone to avoid reference issues oppPlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { var p = realSquads[clubName][i]; oppPlayers.push(clonePlayer(p)); } } else { // Fallback to random oppPlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { oppPlayers.push(makeRandomPlayer()); } } return new Team(clubName, oppPlayers); } function clonePlayer(p) { return new Player(p.name, p.attack, p.defense, p.stamina, p.value, p.seasonsRemaining); } // --- INIT DATA --- function initPlayers() { allPlayers = []; for (var i = 0; i < SQUAD_SIZE + BENCH_SIZE; i++) { // For initial squad, generate lower stats (attack, defense, stamina) var atk = randomInt(4, 8); var def = randomInt(4, 8); var sta = randomInt(8, 13); var val = Math.floor((atk + def + sta) / 3) + randomInt(PLAYER_MIN_VALUE, PLAYER_MIN_VALUE + 5); allPlayers.push(new Player(randomName(), atk, def, sta, val)); } updateSquadAndBench(); } function updateSquadAndBench() { squad = []; bench = []; // Ensure squad has at most SQUAD_SIZE players and bench has remaining for (var i = 0; i < allPlayers.length; i++) { if (i < SQUAD_SIZE) { allPlayers[i].inSquad = true; // Ensure we don't add more than SQUAD_SIZE players to the squad if (squad.length < SQUAD_SIZE) { squad.push(allPlayers[i]); } else { // If somehow we have too many players marked as squad, put them on bench allPlayers[i].inSquad = false; bench.push(allPlayers[i]); } } else { allPlayers[i].inSquad = false; bench.push(allPlayers[i]); } } // If allPlayers has less than SQUAD_SIZE, squad will naturally have fewer players. // No need to fill empty slots, the updateSquadLabels function handles this. } function initTransferList() { transferList = []; // List of latest, highest-valued real-world football players (2024, top market values, demo) var topPlayers = [new Player("Kylian Mbappé", 20, 12, 19, 180), new Player("Erling Haaland", 21, 10, 18, 170), new Player("Jude Bellingham", 18, 14, 18, 150), new Player("Vinícius Júnior", 19, 12, 18, 150), new Player("Phil Foden", 17, 13, 17, 130), new Player("Bukayo Saka", 17, 12, 17, 120), new Player("Rodri", 14, 18, 17, 120), new Player("Jamal Musiala", 17, 12, 17, 120), new Player("Victor Osimhen", 19, 10, 17, 110), new Player("Florian Wirtz", 16, 12, 17, 110), new Player("Pedri", 15, 13, 17, 100), new Player("Declan Rice", 13, 17, 17, 100), new Player("Harry Kane", 20, 10, 16, 100), new Player("Martin Ødegaard", 16, 13, 16, 100), new Player("Rafael Leão", 18, 10, 16, 90), new Player("Khvicha Kvaratskhelia", 17, 11, 16, 90), new Player("Josko Gvardiol", 10, 18, 16, 90), new Player("Gavi", 14, 14, 16, 90), new Player("Alejandro Balde", 12, 15, 16, 80), new Player("William Saliba", 9, 18, 16, 80), new Player("Son Heung Min", 19, 11, 17, 110)]; // Always show 6 random top players in the transfer market, no duplicates var usedIdx = []; for (var i = 0; i < 6; i++) { var idx; do { idx = randomInt(0, topPlayers.length - 1); } while (usedIdx.indexOf(idx) !== -1); usedIdx.push(idx); // When adding to transferList, set seasonsRemaining=3 for transfer market players var p = topPlayers[idx]; transferList.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, 3)); } } // --- UI HELPERS --- function clearArray(arr) { while (arr.length > 0) { var el = arr.pop(); if (el && el.destroy) { el.destroy(); } } } function makeLabel(txt, x, y, size, color) { var t = new Text2(txt, { size: size || 60, fill: color || "#fff" }); t.x = x; t.y = y; return t; } function updateBudgetText() { budgetText.setText("Budget: $" + budget + "M"); } function showInfo(msg) { infoText.setText(msg); } function updateSquadLabels() { clearArray(squadLabels); // Add extra margin at the top for squad section var startY = guiY + 240; // Keep top margin for squad section var squadX = 80; // left margin var swapBtnX = squadX + 700; // move swap arrow much closer to name var sellBtnX = squadX + 800; // move sell button just after swap arrow var rowSpacing = 50; // reduced for almost zero vertical space between squad texts for (var i = 0; i < SQUAD_SIZE; i++) { var p = squad[i]; // Check if player exists at this index if (!p) { // Display an empty slot if player is missing var t = makeLabel(i + 1 + ". Empty Slot", squadX, startY + i * rowSpacing, 48, "#aaaaaa"); game.addChild(t); squadLabels.push(t); // Do not add swap or sell buttons for empty slots continue; } var seasonsTxt = typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null ? " (" + p.seasonsRemaining + "s)" : ""; var t = makeLabel(i + 1 + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]" + seasonsTxt, squadX, startY + i * rowSpacing, 48, "#ffe066"); game.addChild(t); squadLabels.push(t); // Add swap button var btn = makeLabel("↔", swapBtnX, t.y, 48, "#fff"); btn.idx = i; btn.interactive = true; btn.down = function (x, y, obj) { selectedPlayerIdx = obj.idx; if (selectedPlayerIdx !== null && squad[selectedPlayerIdx]) { showInfo("Tap a bench player to swap with " + squad[selectedPlayerIdx].name + " or tap 'Cancel'"); // Add a cancel button if not already present if (!swapBtns.cancelBtn) { var cancelBtn = makeLabel("Cancel", swapBtnX + 80, btn.y, 40, "#fdcb6e"); cancelBtn.interactive = true; cancelBtn.down = function (x, y, obj) { selectedPlayerIdx = null; // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } showInfo("Substitution cancelled."); refreshUI(); }; game.addChild(cancelBtn); swapBtns.cancelBtn = cancelBtn; } } else { // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } showInfo("Tap a bench player to swap."); } }; game.addChild(btn); swapBtns.push(btn); // Add sell button var sellBtn = makeLabel("Sell", sellBtnX, t.y, 40, "#ff7675"); sellBtn.idx = i; sellBtn.interactive = true; sellBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = squad[idx]; if (!p) { showInfo("Player not available."); return; } // Find the player in allPlayers by reference, not by index var allIdx = allPlayers.indexOf(p); if (allIdx !== -1) { budget += p.value; allPlayers.splice(allIdx, 1); updateSquadAndBench(); updateBudgetText(); showInfo("Sold " + p.name + " for $" + p.value + "M"); refreshUI(); } else { showInfo("Player not found in squad."); } }; }(i); game.addChild(sellBtn); sellBtns.push(sellBtn); } } function updateBenchLabels() { clearArray(benchLabels); // Add extra margin at the top for bench section var startY = guiY + 240; // Increased for more top margin var benchX = 1100; // moved closer to squad var rowSpacing = 48; // reduced for almost zero vertical space between bench texts for (var i = 0; i < BENCH_SIZE; i++) { var p = bench[i]; if (!p) { // Display an empty slot if player is missing var t = makeLabel("B" + (i + 1) + ". Empty Slot", benchX, startY + i * rowSpacing, 48, "#aaaaaa"); game.addChild(t); benchLabels.push(t); continue; } var seasonsTxt = typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null ? " (" + p.seasonsRemaining + "s)" : ""; var t = makeLabel("B" + (i + 1) + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]" + seasonsTxt, benchX, startY + i * rowSpacing, 48, "#b2bec3"); game.addChild(t); benchLabels.push(t); // Add swap handler t.idx = i; t.interactive = true; t.down = function (x, y, obj) { if (selectedPlayerIdx !== null) { // Swap squad[selectedPlayerIdx] with bench[obj.idx] var sIdx = selectedPlayerIdx; var bIdx = obj.idx; // Ensure both slots have a player before swapping if (squad[sIdx] && bench[bIdx]) { var temp = squad[sIdx]; squad[sIdx] = bench[bIdx]; bench[bIdx] = temp; } else if (!squad[sIdx] && bench[bIdx]) { // Move bench player to empty squad slot squad[sIdx] = bench[bIdx]; bench[bIdx] = undefined; // Or null, or remove from array if it's a sparse array } else if (squad[sIdx] && !bench[bIdx]) { // Move squad player to empty bench slot bench[bIdx] = squad[sIdx]; squad[sIdx] = undefined; // Or null, or remove from array } else { // Both are empty or other unexpected state, do nothing selectedPlayerIdx = null; // Clear selection // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } showInfo("Cannot swap with empty slots."); refreshUI(); return; } // Update allPlayers order - Reconstruct allPlayers from squad and bench allPlayers = []; for (var j = 0; j < squad.length; j++) { if (squad[j]) allPlayers.push(squad[j]); } for (var j = 0; j < bench.length; j++) { if (bench[j]) allPlayers.push(bench[j]); } // Recalculate squad and bench based on new allPlayers order updateSquadAndBench(); selectedPlayerIdx = null; // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } showInfo("Swapped players."); refreshUI(); return; } }; } } function updateTransferLabels() { clearArray(transferBtns); clearArray(buyBtns); // --- Centered Transfer Market Layout --- // Calculate center X for the section var sectionWidth = 1100; var sectionX = (2048 - sectionWidth) / 2; var rowHeight = 64; var sectionHeight = (transferList.length + 1) * rowHeight + 120; var startY = 400; // Start well below the top for visual balance // Remove old transferText if present if (transferText) { transferText.destroy(); } // Centered header transferText = makeLabel("Transfer Market", 2048 / 2, startY - 90, 56, "#00b894"); transferText.anchor.set(0.5, 0); // Center header horizontally game.addChild(transferText); // Calculate X positions for player info and buy button var playerInfoX = sectionX + 40; var buyBtnX = sectionX + sectionWidth - 180; for (var i = 0; i < transferList.length; i++) { var p = transferList[i]; // Centered row Y var rowY = startY + i * rowHeight; // Player info label, left-aligned in section var t = makeLabel(p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "] $" + p.value + "M", playerInfoX, rowY, 44, "#fff"); t.anchor.set(0, 0); // Left align in section game.addChild(t); transferBtns.push(t); // Buy button, right-aligned in section var buyBtn = makeLabel("Buy", buyBtnX, rowY, 40, "#00b894"); buyBtn.idx = i; buyBtn.interactive = true; buyBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = transferList[idx]; if (!p) { showInfo("Player not available."); return; } if (budget < p.value) { showInfo("Not enough budget!"); return; } // Allow buying a player as long as the total number of players is less than the maximum allowed if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) { showInfo("Squad full! Sell a player first."); return; } budget -= p.value; // When buying, always set seasonsRemaining=3 allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, 3)); updateSquadAndBench(); updateBudgetText(); showInfo("Bought " + p.name + " for $" + p.value + "M"); // Remove from transfer list, add new transferList.splice(idx, 1, makeRandomPlayer()); refreshUI(); }; }(i); game.addChild(buyBtn); buyBtns.push(buyBtn); } } function updateOpponentLabels() { clearArray(opponentLabels); // Position opponent section at bottom-left (for reference, but now only for opponent info) var oppStartY = 2048 - (SQUAD_SIZE + 2) * 120 - 200; // increased row height and more margin for opponent section if (oppStartY < guiY + 1800) { oppStartY = guiY + 1800; } // push down if needed for more space // --- League Table: show all teams, slightly larger, and moved to the left --- // Place league table just above the opponent section, but below the transfer market var leagueWidth = 600; // slightly larger var leagueX = 80; // move to the left side of the screen var leagueY = oppStartY - 650; // place above opponent section, below transfer market if (leagueY < guiY + 600) leagueY = guiY + 600; var leagueHeader = makeLabel("League Table", leagueX, leagueY, 54, "#fdcb6e"); // slightly larger font game.addChild(leagueHeader); opponentLabels.push(leagueHeader); // Sort league by points, then goal difference, then goals for var sortedLeague = leagueTeams.slice().sort(function (a, b) { if (b.points !== a.points) { return b.points - a.points; } var gdA = a.goalsFor - a.goalsAgainst; var gdB = b.goalsFor - b.goalsAgainst; if (gdB !== gdA) { return gdB - gdA; } return b.goalsFor - a.goalsFor; }); for (var i = 0; i < sortedLeague.length; i++) { var team = sortedLeague[i]; var color = team.name === "You" ? "#00cec9" : "#fff"; var gd = team.goalsFor - team.goalsAgainst; var labelTxt = i + 1 + ". " + team.name + " Pts:" + team.points + " GP:" + team.played + " W:" + team.wins + " D:" + team.draws + " L:" + team.losses + " GD:" + gd; var teamLabel = makeLabel(labelTxt, leagueX, leagueY + 70 + i * 48, 38, color); // slightly larger font and spacing game.addChild(teamLabel); opponentLabels.push(teamLabel); } // Now show opponent section below league table var t = makeLabel("Next Opponent: " + opponentTeam.name, 80, oppStartY, 56, "#fab1a0"); game.addChild(t); opponentLabels.push(t); // Reduce vertical spacing between opponent team player names to minimum without overlap var oppPlayerFontSize = 40; var oppPlayerSpacing = oppPlayerFontSize + 2; // 2px gap to avoid touching for (var i = 0; i < SQUAD_SIZE; i++) { var p = opponentTeam.players[i]; var pt = makeLabel(i + 1 + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]", 80, oppStartY + 120 + i * oppPlayerSpacing, oppPlayerFontSize, "#fff"); game.addChild(pt); opponentLabels.push(pt); } } function clearMatchText() { if (matchText) { matchText.destroy(); matchText = null; } } function showMatchLog() { clearMatchText(); var log = matchLog.join("\n"); matchText = new Text2(log, { size: 48, fill: "#fff", wordWrap: true, wordWrapWidth: 1800 }); // Position match summary directly underneath the Play Match button var playBtnX = 2048 / 2 - 200; // Same as playBtn X var playBtnY = 2048 - 200; // Same as playBtn Y matchText.x = playBtnX; matchText.y = playBtnY + 180; // 180px below Play Match button for extra separation game.addChild(matchText); } function clearAllUI() { clearArray(squadLabels); clearArray(benchLabels); clearArray(transferBtns); clearArray(buyBtns); clearArray(swapBtns); clearArray(sellBtns); clearArray(opponentLabels); // --- YOUTH ACADEMY UI --- clearArray(youthLabels); clearArray(promoteBtns); clearArray(sellYouthBtns); if (transferText) { transferText.destroy(); } transferText = null; // --- CLEAR TRANSFER OFFER UI --- clearArray(offerLabels); clearArray(acceptOfferBtns); clearArray(rejectOfferBtns); clearMatchText(); if (playBtn) { playBtn.destroy(); } playBtn = null; if (nextBtn) { nextBtn.destroy(); } nextBtn = null; } // --- LEAGUE SYSTEM --- // League teams: user + 10 Turkish clubs var leagueClubNames = ["Denizlispor", "Sivasspor", "Galatasaray", "Fenerbahce", "Trabzonspor", "Besiktas", "Basaksehir", "Konyaspor", "Antalyaspor", "Alanyaspor"]; var leagueTeams = []; // [{name, points, played, wins, draws, losses, goalsFor, goalsAgainst}] var leagueFixtures = []; // [{homeIdx, awayIdx}] var currentFixtureIdx = 0; var userTeamIdx = 0; // always 0 function initLeague() { leagueTeams = []; // User team leagueTeams.push({ name: "You", points: 0, played: 0, wins: 0, draws: 0, losses: 0, goalsFor: 0, goalsAgainst: 0 }); // Opponent clubs for (var i = 0; i < leagueClubNames.length; i++) { var clubName = leagueClubNames[i]; leagueTeams.push({ name: clubName, points: 0, played: 0, wins: 0, draws: 0, losses: 0, goalsFor: 0, goalsAgainst: 0, // Attach real squad if available for league simulation realSquad: realSquads[clubName] ? realSquads[clubName].map(function (p) { return clonePlayer(p); }) : null }); } // Generate fixtures: each team plays every other team twice (home/away) leagueFixtures = []; var n = leagueTeams.length; for (var i = 0; i < n; i++) { for (var j = 0; j < n; j++) { if (i !== j) { // Only add each pair twice (home/away) if (i < j) { leagueFixtures.push({ homeIdx: i, awayIdx: j }); leagueFixtures.push({ homeIdx: j, awayIdx: i }); } } } } // Shuffle fixtures for variety for (var k = leagueFixtures.length - 1; k > 0; k--) { var r = randomInt(0, k); var temp = leagueFixtures[k]; leagueFixtures[k] = leagueFixtures[r]; leagueFixtures[r] = temp; } currentFixtureIdx = 0; } function getCurrentOpponentIdx() { // Find the next fixture where user is home or away for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) { var f = leagueFixtures[i]; if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) { return f.homeIdx === userTeamIdx ? f.awayIdx : f.homeIdx; } } return null; } function getCurrentFixture() { for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) { var f = leagueFixtures[i]; if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) { return { idx: i, fixture: f }; } } return null; } function advanceFixture() { // Move to next user fixture for (var i = currentFixtureIdx + 1; i < leagueFixtures.length; i++) { var f = leagueFixtures[i]; if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) { currentFixtureIdx = i; return; } } // No more fixtures: season over currentFixtureIdx = leagueFixtures.length; } function isSeasonOver() { // If all user fixtures played for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) { var f = leagueFixtures[i]; if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) { return false; } } return true; } // --- GAME LOGIC --- function simulateMatch() { matchLog = []; matchResult = null; matchInProgress = true; // --- Add a random number of youth players after each match --- var numNewYouth = randomInt(0, 3); if (youthAcademy.length < YOUTH_MAX && numNewYouth > 0) { for (var i = 0; i < numNewYouth; i++) { if (youthAcademy.length >= YOUTH_MAX) break; // Don't add more than max // Generate a young player (attributes 1-10) var atk = randomInt(1, 10); var def = randomInt(1, 10); var sta = randomInt(1, 10); // Calculate base stat sum and average var statSum = atk + def + sta; var statAvg = Math.floor(statSum / 3); // Most players: value 1-5M, some: 6-10M, all <= 10M var val; if (Math.random() < 0.8) { val = Math.max(1, Math.min(5, statAvg + randomInt(0, 1))); } else { val = Math.max(6, Math.min(10, statAvg + randomInt(2, 4))); if (val < 6) val = 5; } if (val > 10) val = 10; // Cap value at 10M for youth academy players var p = new Player(randomName(), atk, def, sta, val, null); youthAcademy.push(p); } if (numNewYouth === 1) { showInfo("A new youth player has joined your academy!"); } else if (numNewYouth > 1) { showInfo(numNewYouth + " new youth players have joined your academy!"); } refreshUI(); } // Find all fixtures for this matchday (all teams play one match) if (currentFixtureIdx >= leagueFixtures.length) { matchLog.push("Season is over!"); showMatchLog(); matchInProgress = false; return; } // Gather all fixtures for this matchday (each team plays once) var nTeams = leagueTeams.length; var matchdayFixtures = []; var teamsPlayed = {}; for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) { var f = leagueFixtures[i]; if (!teamsPlayed[f.homeIdx] && !teamsPlayed[f.awayIdx]) { matchdayFixtures.push({ idx: i, fixture: f }); teamsPlayed[f.homeIdx] = true; teamsPlayed[f.awayIdx] = true; if (Object.keys(teamsPlayed).length >= nTeams) { break; } } } // Simulate all matches in this matchday var userMatchIdx = -1; for (var m = 0; m < matchdayFixtures.length; m++) { var fixtureObj = matchdayFixtures[m]; var fixture = fixtureObj.fixture; var homeIdx = fixture.homeIdx; var awayIdx = fixture.awayIdx; var homeTeam = leagueTeams[homeIdx]; var awayTeam = leagueTeams[awayIdx]; // Prepare teams var homePlayers, awayPlayers; if (homeIdx === userTeamIdx) { homePlayers = squad; } else { // Use real squad if available, else generate random team if (homeTeam.realSquad) { homePlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { homePlayers.push(clonePlayer(homeTeam.realSquad[i])); } } else { homePlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { homePlayers.push(makeRandomPlayer()); } } } if (awayIdx === userTeamIdx) { awayPlayers = squad; } else { if (awayTeam.realSquad) { awayPlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { awayPlayers.push(clonePlayer(awayTeam.realSquad[i])); } } else { awayPlayers = []; for (var i = 0; i < SQUAD_SIZE; i++) { awayPlayers.push(makeRandomPlayer()); } } } // Calculate stats // Determine team strengths var homeStrength = 0; for (var i = 0; i < homePlayers.length; i++) { homeStrength += homePlayers[i].attack + homePlayers[i].defense + homePlayers[i].stamina; } var awayStrength = 0; for (var i = 0; i < awayPlayers.length; i++) { awayStrength += awayPlayers[i].attack + awayPlayers[i].defense + awayPlayers[i].stamina; } var homeGoals = 0, awayGoals = 0; // Simulate match based on strength and randomness // A simple model: higher strength means more chances to score // Reduce number of chances and scoring probability for more realistic scores var homeChances = Math.max(1, Math.floor(homeStrength / 40) + randomInt(-1, 1)); // Fewer chances, less randomness var awayChances = Math.max(1, Math.floor(awayStrength / 40) + randomInt(-1, 1)); // Fewer chances, less randomness for (var i = 0; i < homeChances; i++) { if (Math.random() < 0.38) { // Lower chance to score per chance homeGoals++; } } for (var i = 0; i < awayChances; i++) { if (Math.random() < 0.38) { // Lower chance to score per chance awayGoals++; } } for (var turn = 0; turn < 5; turn++) { // Home attack (for match log details) var atkP = homePlayers[turn]; var defP = awayPlayers[turn]; // Check if players are defined before accessing their properties if (!atkP || !defP) { // Skip this turn if a player is missing continue; } var atkChance = atkP.attack + randomInt(0, atkP.stamina); var defChance = defP.defense + randomInt(0, defP.stamina); if (atkChance > defChance + 3) { //homeGoals++; // Already accounted for in overall simulation } else if (defChance > atkChance + 5) { // Defensive action (for match log details) } // Away attack (for match log details) var oAtkP = awayPlayers[turn]; var oDefP = homePlayers[turn]; // Check if players are defined before accessing their properties if (!oAtkP || !oDefP) { // Skip this turn if a player is missing continue; } var oAtkChance = oAtkP.attack + randomInt(0, oAtkP.stamina); var oDefChance = oDefP.defense + randomInt(0, oDefP.stamina); if (oAtkChance > oDefChance + 3) { //awayGoals++; // Already accounted for in overall simulation } else if (oDefChance > oAtkChance + 5) { // Defensive action (for match log details) } } // Update league table homeTeam.played += 1; awayTeam.played += 1; homeTeam.goalsFor += homeGoals; homeTeam.goalsAgainst += awayGoals; awayTeam.goalsFor += awayGoals; awayTeam.goalsAgainst += homeGoals; if (homeGoals > awayGoals) { homeTeam.points += 3; homeTeam.wins += 1; awayTeam.losses += 1; } else if (homeGoals < awayGoals) { awayTeam.points += 3; awayTeam.wins += 1; homeTeam.losses += 1; } else { homeTeam.points += 1; awayTeam.points += 1; homeTeam.draws += 1; awayTeam.draws += 1; } // If this is the user's match, log details and handle rewards if (homeIdx === userTeamIdx || awayIdx === userTeamIdx) { userMatchIdx = m; var userGoals = homeIdx === userTeamIdx ? homeGoals : awayGoals; var oppGoals = homeIdx === userTeamIdx ? awayGoals : homeGoals; var oppIdx = homeIdx === userTeamIdx ? awayIdx : homeIdx; var oppName = leagueTeams[oppIdx].name; for (var turn = 0; turn < 5; turn++) { // User attack var atkP = squad[turn]; var defP = homeIdx === userTeamIdx ? awayPlayers[turn] : homePlayers[turn]; // Check if players are defined before accessing their properties if (!atkP || !defP) { // Skip this turn if a player is missing continue; } var atkChance = atkP.attack + randomInt(0, atkP.stamina); var defChance = defP.defense + randomInt(0, defP.stamina); if (atkChance > defChance + 5 && Math.random() < 0.5) { // Harder to score, require bigger difference and add randomness matchLog.push("Minute " + (turn * 18 + 5) + ": " + atkP.name + " scores!"); } else if (defChance > atkChance + 3) { matchLog.push("Minute " + (turn * 18 + 8) + ": " + defP.name + " makes a key tackle."); } // Opponent attack var oAtkP = homeIdx === userTeamIdx ? awayPlayers[turn] : homePlayers[turn]; var oDefP = squad[turn]; // Check if players are defined before accessing their properties if (!oAtkP || !oDefP) { // Skip this turn if a player is missing continue; } var oAtkChance = oAtkP.attack + randomInt(0, oAtkP.stamina); var oDefChance = oDefP.defense + randomInt(0, oDefP.stamina); if (oAtkChance > oDefChance + 5 && Math.random() < 0.5) { // Harder to score, require bigger difference and add randomness matchLog.push("Minute " + (turn * 18 + 12) + ": " + oAtkP.name + " scores!"); } else if (oDefChance > oAtkChance + 3) { matchLog.push("Minute " + (turn * 18 + 15) + ": " + oDefP.name + " blocks a shot."); } } matchLog.push("Full Time: You " + userGoals + " - " + oppGoals + " " + oppName); // Rewards if (userGoals > oppGoals) { matchResult = "win"; matchLog.push("You win! +$20M"); budget += 20; } else if (userGoals < oppGoals) { matchResult = "lose"; matchLog.push("You lose."); } else { matchResult = "draw"; matchLog.push("Draw. +$5M"); budget += 5; } } } // Advance fixture pointer by number of fixtures played this matchday currentFixtureIdx += matchdayFixtures.length; // Restore stamina a bit after match for (var i = 0; i < homePlayers.length; i++) { if (homeIdx === userTeamIdx) { homePlayers[i].stamina = Math.max(0, homePlayers[i].stamina - randomInt(3, 6)); // Decrease stamina after playing homePlayers[i].stamina = Math.min(homePlayers[i].maxStamina, homePlayers[i].stamina + randomInt(1, 3)); // Partial recovery } } for (var i = 0; i < awayPlayers.length; i++) { if (awayIdx === userTeamIdx) { awayPlayers[i].stamina = Math.max(0, awayPlayers[i].stamina - randomInt(3, 6)); // Decrease stamina after playing awayPlayers[i].stamina = Math.min(awayPlayers[i].maxStamina, awayPlayers[i].stamina + randomInt(1, 3)); // Partial recovery } } updateBudgetText(); showMatchLog(); matchInProgress = false; } function refreshUI() { clearAllUI(); // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } // Add extra vertical space between all sections by adjusting guiY and section Y positions // Squad section updateSquadLabels(); // Bench section (move further down) guiY = 0; // reset updateBenchLabels(); // Transfer section (move further down) updateTransferLabels(); // Opponent and league table section (move further down) updateOpponentLabels(); updateBudgetText(); showInfo("Pick lineup, buy/sell, then Play Match!"); // --- YOUTH ACADEMY UI --- clearArray(youthLabels); clearArray(promoteBtns); clearArray(sellYouthBtns); // Place youth academy to the right of the buy buttons in the transfer market var youthX = 80 + 750 + 300; // sectionX + buyBtn offset + extra margin var youthY = guiY + 600; // align vertically with transfer section var youthHeader = makeLabel("Youth Academy", youthX, youthY, 54, "#81ecec"); game.addChild(youthHeader); youthLabels.push(youthHeader); for (var i = 0; i < youthAcademy.length; i++) { var yp = youthAcademy[i]; var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", youthX, youthY + 70 + i * 60, 40, "#fff"); game.addChild(t); youthLabels.push(t); // Promote button var promoteBtn = makeLabel("Promote", youthX + 420, t.y, 36, "#00b894"); promoteBtn.idx = i; promoteBtn.interactive = true; promoteBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to promote."); return; } // Allow promoting a player as long as the total number of players is less than the maximum allowed if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) { showInfo("Squad full! Sell a player first."); return; } allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null)); updateSquadAndBench(); showInfo("Promoted " + p.name + " to your team!"); youthAcademy.splice(idx, 1); refreshUI(); }; }(i); game.addChild(promoteBtn); promoteBtns.push(promoteBtn); // Sell button var sellBtn = makeLabel("Sell", youthX + 600, t.y, 36, "#fdcb6e"); sellBtn.idx = i; sellBtn.interactive = true; sellBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to sell."); return; } budget += p.value; updateBudgetText(); showInfo("Sold " + p.name + " for $" + p.value + "M"); youthAcademy.splice(idx, 1); refreshUI(); }; }(i); game.addChild(sellBtn); sellYouthBtns.push(sellBtn); } // --- TRANSFER OFFERS UI (now under youth academy) --- clearArray(offerLabels); clearArray(acceptOfferBtns); clearArray(rejectOfferBtns); var offerX = youthX; var offerY = youthY + 70 + Math.max(1, youthAcademy.length) * 60 + 40; // place below youth academy if (transferOffers.length > 0) { var offerHeader = makeLabel("Transfer Offers", offerX, offerY, 54, "#fdcb6e"); game.addChild(offerHeader); offerLabels.push(offerHeader); for (var i = 0; i < transferOffers.length; i++) { var offer = transferOffers[i]; var p = offer.player; // Only show player name and offer amount, hide stats var txt = offer.club + " offers $" + offer.offerValue + "M for " + p.name; var t = makeLabel(txt, offerX, offerY + 70 + i * 60, 40, "#fff"); game.addChild(t); offerLabels.push(t); // Accept button var acceptBtn = makeLabel("Accept", offerX + 420, t.y, 36, "#00b894"); acceptBtn.idx = i; acceptBtn.interactive = true; acceptBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var offer = transferOffers[idx]; var p = offer.player; // Remove player from allPlayers, squad/bench var allIdx = allPlayers.indexOf(p); if (allIdx !== -1) { budget += offer.offerValue; allPlayers.splice(allIdx, 1); updateSquadAndBench(); updateBudgetText(); showInfo("Sold " + p.name + " to " + offer.club + " for $" + offer.offerValue + "M"); transferOffers.splice(idx, 1); refreshUI(); } else { showInfo("Player not found."); } }; }(i); game.addChild(acceptBtn); acceptOfferBtns.push(acceptBtn); // Reject button var rejectBtn = makeLabel("Reject", offerX + 600, t.y, 36, "#ff7675"); rejectBtn.idx = i; rejectBtn.interactive = true; rejectBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var offer = transferOffers[idx]; showInfo("Rejected offer for " + offer.player.name + "."); transferOffers.splice(idx, 1); refreshUI(); }; }(i); game.addChild(rejectBtn); rejectOfferBtns.push(rejectBtn); } } // --- YOUTH ACADEMY UI --- clearArray(youthLabels); clearArray(promoteBtns); clearArray(sellYouthBtns); // Place youth academy to the right of the buy buttons in the transfer market var youthX = 80 + 750 + 300; // sectionX + buyBtn offset + extra margin var youthY = guiY + 600; // align vertically with transfer section var youthHeader = makeLabel("Youth Academy", youthX, youthY, 54, "#81ecec"); game.addChild(youthHeader); youthLabels.push(youthHeader); for (var i = 0; i < youthAcademy.length; i++) { var yp = youthAcademy[i]; var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", youthX, youthY + 70 + i * 60, 40, "#fff"); game.addChild(t); youthLabels.push(t); // Promote button var promoteBtn = makeLabel("Promote", youthX + 420, t.y, 36, "#00b894"); promoteBtn.idx = i; promoteBtn.interactive = true; promoteBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to promote."); return; } if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) { showInfo("Squad full! Sell a player first."); return; } allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null)); updateSquadAndBench(); showInfo("Promoted " + p.name + " to your team!"); youthAcademy.splice(idx, 1); refreshUI(); }; }(i); game.addChild(promoteBtn); promoteBtns.push(promoteBtn); // Sell button var sellBtn = makeLabel("Sell", youthX + 600, t.y, 36, "#fdcb6e"); sellBtn.idx = i; sellBtn.interactive = true; sellBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to sell."); return; } budget += p.value; updateBudgetText(); showInfo("Sold " + p.name + " for $" + p.value + "M"); youthAcademy.splice(idx, 1); refreshUI(); }; }(i); game.addChild(sellBtn); sellYouthBtns.push(sellBtn); } // --- YOUTH ACADEMY GENERATION TIMER --- if (!youthTimer) { youthTimer = LK.setInterval(function () { if (youthAcademy.length < YOUTH_MAX) { // Generate a young player (attributes 1-10) var atk = randomInt(1, 10); var def = randomInt(1, 10); var sta = randomInt(1, 10); // Calculate base stat sum and average var statSum = atk + def + sta; var statAvg = Math.floor(statSum / 3); // Most players: value 1-5M, some: 6-10M, all <= 10M var val; // 80% chance for 1-5M, 20% for 6-10M (if stats are high enough) if (Math.random() < 0.8) { // Value 1-5M, based on statAvg, but never below 1M val = Math.max(1, Math.min(5, statAvg + randomInt(0, 1))); } else { // Value 6-10M, only if statAvg is high enough val = Math.max(6, Math.min(10, statAvg + randomInt(2, 4))); // If statAvg is too low, fallback to 5M if (val < 6) val = 5; } if (val > 10) val = 10; // Cap value at 10M for youth academy players var p = new Player(randomName(), atk, def, sta, val, null); youthAcademy.push(p); showInfo("A new youth player has joined your academy!"); refreshUI(); } }, YOUTH_TIMER_INTERVAL); } // --- TRANSFER OFFER GENERATION TIMER REMOVED --- // Transfer offers are now only generated at end of season, see next change_block. // Play match button (bottom middle, with extra margin from all sections) var playBtnX = 2048 / 2 - 200; // Centered horizontally, adjust for button width var playBtnY = 2048 - 200; // 200px from bottom playBtn = makeLabel("Play Match", playBtnX, playBtnY, 70, "#00cec9"); playBtn.interactive = true; playBtn.down = function (x, y, obj) { if (matchInProgress) { return; } simulateMatch(); playBtn.destroy(); playBtn = null; // Next match button (bottom middle, below Play Match) var nextBtnX = 2048 / 2 - 200; var nextBtnY = playBtnY + 120; nextBtn = makeLabel("Next Match", nextBtnX, nextBtnY, 60, "#fdcb6e"); nextBtn.interactive = true; nextBtn.down = function (x, y, obj) { // Restore stamina a bit for (var i = 0; i < allPlayers.length; i++) { allPlayers[i].stamina = Math.min(allPlayers[i].maxStamina, allPlayers[i].stamina + randomInt(1, 3)); } // Check if season is over if (isSeasonOver()) { // Calculate final league position for user var sortedLeague = leagueTeams.slice().sort(function (a, b) { if (b.points !== a.points) { return b.points - a.points; } var gdA = a.goalsFor - a.goalsAgainst; var gdB = b.goalsFor - b.goalsAgainst; if (gdB !== gdA) { return gdB - gdA; } return b.goalsFor - a.goalsFor; }); var userFinalPos = 1; for (var i = 0; i < sortedLeague.length; i++) { if (sortedLeague[i].name === "You") { userFinalPos = i + 1; break; } } // Prize money by position var prize = 5; if (userFinalPos === 1) { prize = 50; } else if (userFinalPos === 2) { prize = 30; } else if (userFinalPos === 3) { prize = 20; } else if (userFinalPos === 4) { prize = 10; } // Award prize budget += prize; showInfo("Season finished! You placed #" + userFinalPos + ". Prize: $" + prize + "M. Table resets for new season."); updateBudgetText(); // Decrement seasonsRemaining for transfer market players, remove those at 0 for (var i = allPlayers.length - 1; i >= 0; i--) { var p = allPlayers[i]; if (typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null) { p.seasonsRemaining--; if (p.seasonsRemaining <= 0) { allPlayers.splice(i, 1); showInfo("Player " + p.name + " has retired/left after 3 seasons."); } } } updateSquadAndBench(); // --- Generate up to 3 transfer offers for squad/bench players at end of season --- transferOffers = []; var candidates = squad.concat(bench).slice(); // copy // Shuffle candidates for (var i = candidates.length - 1; i > 0; i--) { var j = randomInt(0, i); var temp = candidates[i]; candidates[i] = candidates[j]; candidates[j] = temp; } var offersToMake = Math.min(3, candidates.length); for (var i = 0; i < offersToMake; i++) { var p = candidates[i]; // Offer value: 90% to 120% of player value var offerVal = Math.floor(p.value * (randomInt(90, 120) / 100)); // Pick a random club var club = OFFER_CLUBS[randomInt(0, OFFER_CLUBS.length - 1)]; transferOffers.push({ player: p, offerValue: offerVal, club: club }); } // Only show info if there are offers if (transferOffers.length > 0) { showInfo("You have received " + transferOffers.length + " transfer offer(s) for your players!"); } // Reset league and start new season initLeague(); // Do NOT reset allPlayers, squad, or bench here; keep current team for next season // Only reset transfer market for new season initTransferList(); // Set first opponent var oppIdx = getCurrentOpponentIdx(); if (oppIdx !== null) { // Generate new opponent team for this club opponentTeam = makeOpponentTeam(); opponentTeam.name = leagueTeams[oppIdx].name; } clearMatchText(); nextBtn.destroy(); nextBtn = null; refreshUI(); return; } // Next opponent in league var oppIdx = getCurrentOpponentIdx(); if (oppIdx !== null) { opponentTeam = makeOpponentTeam(); opponentTeam.name = leagueTeams[oppIdx].name; } clearMatchText(); nextBtn.destroy(); nextBtn = null; refreshUI(); }; game.addChild(nextBtn); }; game.addChild(playBtn); } // --- INIT UI --- var currentScreen = "main"; // "main", "transfer", "league", "youth" var navBtns = []; function showScreen(screen) { currentScreen = screen; clearAllUI(); // Remove cancel button if present if (swapBtns.cancelBtn) { swapBtns.cancelBtn.destroy(); swapBtns.cancelBtn = null; } // Always show nav buttons showNavButtons(); if (screen === "main") { updateSquadLabels(); updateBenchLabels(); updateOpponentLabels(); updateBudgetText(); showInfo("Pick lineup, buy/sell, then Play Match!"); // Play Match button var playBtnX = 2048 / 2 - 200; var playBtnY = 2048 - 200; playBtn = makeLabel("Play Match", playBtnX, playBtnY, 70, "#00cec9"); playBtn.interactive = true; playBtn.down = function (x, y, obj) { if (matchInProgress) return; simulateMatch(); playBtn.destroy(); playBtn = null; // Next match button var nextBtnX = 2048 / 2 - 200; var nextBtnY = playBtnY + 120; nextBtn = makeLabel("Next Match", nextBtnX, nextBtnY, 60, "#fdcb6e"); nextBtn.interactive = true; nextBtn.down = function (x, y, obj) { // Restore stamina a bit for (var i = 0; i < allPlayers.length; i++) { allPlayers[i].stamina = Math.min(allPlayers[i].maxStamina, allPlayers[i].stamina + randomInt(1, 3)); } // Check if season is over if (isSeasonOver()) { // Calculate final league position for user var sortedLeague = leagueTeams.slice().sort(function (a, b) { if (b.points !== a.points) return b.points - a.points; var gdA = a.goalsFor - a.goalsAgainst; var gdB = b.goalsFor - b.goalsAgainst; if (gdB !== gdA) return gdB - gdA; return b.goalsFor - a.goalsFor; }); var userFinalPos = 1; for (var i = 0; i < sortedLeague.length; i++) { if (sortedLeague[i].name === "You") { userFinalPos = i + 1; break; } } // Prize money by position var prize = 5; if (userFinalPos === 1) prize = 50;else if (userFinalPos === 2) prize = 30;else if (userFinalPos === 3) prize = 20;else if (userFinalPos === 4) prize = 10; // Award prize budget += prize; showInfo("Season finished! You placed #" + userFinalPos + ". Prize: $" + prize + "M. Table resets for new season."); updateBudgetText(); // Decrement seasonsRemaining for transfer market players, remove those at 0 for (var i = allPlayers.length - 1; i >= 0; i--) { var p = allPlayers[i]; if (typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null) { p.seasonsRemaining--; if (p.seasonsRemaining <= 0) { allPlayers.splice(i, 1); showInfo("Player " + p.name + " has retired/left after 3 seasons."); } } } updateSquadAndBench(); // --- Generate up to 3 transfer offers for squad/bench players at end of season --- transferOffers = []; var candidates = squad.concat(bench).slice(); for (var i = candidates.length - 1; i > 0; i--) { var j = randomInt(0, i); var temp = candidates[i]; candidates[i] = candidates[j]; candidates[j] = temp; } var offersToMake = Math.min(3, candidates.length); for (var i = 0; i < offersToMake; i++) { var p = candidates[i]; var offerVal = Math.floor(p.value * (randomInt(90, 120) / 100)); var club = OFFER_CLUBS[randomInt(0, OFFER_CLUBS.length - 1)]; transferOffers.push({ player: p, offerValue: offerVal, club: club }); } if (transferOffers.length > 0) { showInfo("You have received " + transferOffers.length + " transfer offer(s) for your players!"); } initLeague(); initTransferList(); var oppIdx = getCurrentOpponentIdx(); if (oppIdx !== null) { opponentTeam = makeOpponentTeam(); opponentTeam.name = leagueTeams[oppIdx].name; } clearMatchText(); nextBtn.destroy(); nextBtn = null; showScreen("main"); return; } // Next opponent in league var oppIdx = getCurrentOpponentIdx(); if (oppIdx !== null) { opponentTeam = makeOpponentTeam(); opponentTeam.name = leagueTeams[oppIdx].name; } clearMatchText(); nextBtn.destroy(); nextBtn = null; showScreen("main"); }; game.addChild(nextBtn); }; game.addChild(playBtn); } else if (screen === "transfer") { updateTransferLabels(); updateBudgetText(); showInfo("Buy top players for your team!"); } else if (screen === "league") { updateOpponentLabels(); showInfo("Check the league table and your next opponent."); } else if (screen === "youth") { // Only show youth academy and transfer offers clearArray(youthLabels); clearArray(promoteBtns); clearArray(sellYouthBtns); // --- Centered Youth Academy Layout --- var sectionWidth = 1100; var youthX = (2048 - sectionWidth) / 2; var rowHeight = 64; var youthY = 400; // Centered header var youthHeader = makeLabel("Youth Academy", 2048 / 2, youthY, 54, "#81ecec"); youthHeader.anchor.set(0.5, 0); game.addChild(youthHeader); youthLabels.push(youthHeader); // Calculate X positions for player info and buttons var playerInfoX = youthX + 40; var promoteBtnX = youthX + sectionWidth - 320; var sellBtnX = youthX + sectionWidth - 160; for (var i = 0; i < youthAcademy.length; i++) { var yp = youthAcademy[i]; var rowY = youthY + 70 + i * rowHeight; var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", playerInfoX, rowY, 40, "#fff"); t.anchor.set(0, 0); game.addChild(t); youthLabels.push(t); // Promote button var promoteBtn = makeLabel("Promote", promoteBtnX, rowY, 36, "#00b894"); promoteBtn.idx = i; promoteBtn.interactive = true; promoteBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to promote."); return; } // Allow promoting a player as long as the total number of players is less than the maximum allowed if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) { showInfo("Squad full! Sell a player first."); return; } allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null)); updateSquadAndBench(); showInfo("Promoted " + p.name + " to your team!"); youthAcademy.splice(idx, 1); showScreen("youth"); }; }(i); game.addChild(promoteBtn); promoteBtns.push(promoteBtn); // Sell button var sellBtn = makeLabel("Sell", sellBtnX, rowY, 36, "#fdcb6e"); sellBtn.idx = i; sellBtn.interactive = true; sellBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var p = youthAcademy[idx]; if (!p) { showInfo("No youth player to sell."); return; } budget += p.value; updateBudgetText(); showInfo("Sold " + p.name + " for $" + p.value + "M"); youthAcademy.splice(idx, 1); showScreen("youth"); }; }(i); game.addChild(sellBtn); sellYouthBtns.push(sellBtn); } // Transfer offers clearArray(offerLabels); clearArray(acceptOfferBtns); clearArray(rejectOfferBtns); var offerX = youthX + 40; var offerY = youthY + 70 + Math.max(1, youthAcademy.length) * rowHeight + 40; if (transferOffers.length > 0) { var offerHeader = makeLabel("Transfer Offers", 2048 / 2, offerY, 54, "#fdcb6e"); offerHeader.anchor.set(0.5, 0); game.addChild(offerHeader); offerLabels.push(offerHeader); for (var i = 0; i < transferOffers.length; i++) { var offer = transferOffers[i]; var p = offer.player; var rowY = offerY + 70 + i * rowHeight; var txt = offer.club + " offers $" + offer.offerValue + "M for " + p.name; var t = makeLabel(txt, offerX, rowY, 40, "#fff"); t.anchor.set(0, 0); game.addChild(t); offerLabels.push(t); // Accept button var acceptBtn = makeLabel("Accept", promoteBtnX, rowY, 36, "#00b894"); acceptBtn.idx = i; acceptBtn.interactive = true; acceptBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var offer = transferOffers[idx]; var p = offer.player; var allIdx = allPlayers.indexOf(p); if (allIdx !== -1) { budget += offer.offerValue; allPlayers.splice(allIdx, 1); updateSquadAndBench(); updateBudgetText(); showInfo("Sold " + p.name + " to " + offer.club + " for $" + offer.offerValue + "M"); transferOffers.splice(idx, 1); showScreen("youth"); } else { showInfo("Player not found."); } }; }(i); game.addChild(acceptBtn); acceptOfferBtns.push(acceptBtn); // Reject button var rejectBtn = makeLabel("Reject", sellBtnX, rowY, 36, "#ff7675"); rejectBtn.idx = i; rejectBtn.interactive = true; rejectBtn.down = function (idxCopy) { return function (x, y, obj) { var idx = idxCopy; var offer = transferOffers[idx]; showInfo("Rejected offer for " + offer.player.name + "."); transferOffers.splice(idx, 1); showScreen("youth"); }; }(i); game.addChild(rejectBtn); rejectOfferBtns.push(rejectBtn); } } updateBudgetText(); showInfo("Manage your youth academy and transfer offers."); } } function showNavButtons() { clearArray(navBtns); // Button positions - move to very bottom of screen, with spacing and not touching each other or the edge var btnY = 2732 - 100; // 100px from bottom edge for safe area var btnCount = 4; var btnWidth = 320; // estimated width for button label var btnSpacing = 60; // space between buttons var sideMargin = 60; // margin from left/right edge var totalWidth = btnCount * btnWidth + (btnCount - 1) * btnSpacing; var btnXStart = Math.max(sideMargin, (2048 - totalWidth) / 2); // center all buttons horizontally, but never touch edge var btns = [{ label: "Main", screen: "main", color: 0x00CEC9 }, { label: "Transfer Market", screen: "transfer", color: 0x00B894 }, { label: "League Table", screen: "league", color: 0xFDCB6E }, { label: "Youth Academy", screen: "youth", color: 0x81ECEC }]; for (var i = 0; i < btns.length; i++) { var b = btns[i]; var btnX = btnXStart + i * (btnWidth + btnSpacing); var navBtn = makeLabel(b.label, btnX, btnY, 48, b.color); navBtn.interactive = true; navBtn.screen = b.screen; navBtn.down = function (screenName) { return function (x, y, obj) { showScreen(screenName); }; }(b.screen); game.addChild(navBtn); navBtns.push(navBtn); } } function initUI() { guiY = 0; // Title var title = new Text2("Mini Football Manager", { size: 90, fill: 0x00CEC9 }); title.x = 80; title.y = guiY + 40; game.addChild(title); // Budget budgetText = new Text2("Budget: $" + budget + "M", { size: 60, fill: "#fff" }); budgetText.x = 80; budgetText.y = guiY + 120; game.addChild(budgetText); // Info infoText = new Text2("", { size: 54, fill: 0xFDCB6E }); infoText.x = 600; infoText.y = guiY + 120; game.addChild(infoText); showScreen("main"); } // --- GAME START --- function newGame() { budget = INITIAL_BUDGET; initLeague(); initPlayers(); initTransferList(); // --- YOUTH ACADEMY RESET --- youthAcademy = []; if (youthTimer) { LK.clearInterval(youthTimer); youthTimer = null; } // --- TRANSFER OFFERS RESET --- transferOffers = []; if (OFFER_TIMER) { LK.clearInterval(OFFER_TIMER); OFFER_TIMER = null; } clearArray(offerLabels); clearArray(acceptOfferBtns); clearArray(rejectOfferBtns); // Set first opponent in league var oppIdx = getCurrentOpponentIdx(); if (oppIdx !== null) { opponentTeam = makeOpponentTeam(); opponentTeam.name = leagueTeams[oppIdx].name; } else { opponentTeam = makeOpponentTeam(); } matchInProgress = false; matchLog = []; matchResult = null; selectedPlayerIdx = null; selectedBenchIdx = null; initUI(); } newGame(); // --- END ---
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a3d2f
});
/****
* Game Code
****/
// Player class: represents a footballer
// --- CONSTANTS ---
var Player = function Player(name, attack, defense, stamina, value, seasonsRemaining) {
var self = {};
self.name = name;
self.attack = attack;
self.defense = defense;
self.stamina = stamina;
self.value = value;
self.maxStamina = stamina;
self.inSquad = false; // true if in starting 5
self.seasonsRemaining = typeof seasonsRemaining === "number" ? seasonsRemaining : null; // null for non-transfer players, or integer for transfer market
return self;
};
// Team class: holds a list of players
var Team = function Team(name, players) {
var self = {};
self.name = name;
self.players = players; // array of Player
return self;
};
var SQUAD_SIZE = 5;
var BENCH_SIZE = 3;
var INITIAL_BUDGET = 100;
var PLAYER_MIN_VALUE = 10;
var PLAYER_MAX_VALUE = 40;
// --- GLOBALS ---
var allPlayers = []; // All players owned by user
var squad = []; // Starting 5
var bench = []; // Bench 3
var transferList = []; // Players available to buy
var budget = INITIAL_BUDGET;
var opponentTeam = null;
var matchInProgress = false;
var matchLog = [];
var matchResult = null;
var selectedPlayerIdx = null; // For swapping
var selectedBenchIdx = null; // For swapping
var infoText = null;
var budgetText = null;
var matchText = null;
var transferText = null;
var transferBtns = [];
var swapBtns = [];
var playBtn = null;
var nextBtn = null;
var sellBtns = [];
var buyBtns = [];
var squadLabels = [];
var benchLabels = [];
var opponentLabels = [];
var guiY = 0;
// --- YOUTH ACADEMY ---
var youthAcademy = []; // Array of young players waiting for promotion/sale
var youthLabels = [];
var promoteBtns = [];
var sellYouthBtns = [];
var youthTimer = null;
var YOUTH_TIMER_INTERVAL = 10000; // 10 seconds for demo (tweak as needed)
var YOUTH_MAX = 3; // Max youth in academy at once
// --- TRANSFER OFFERS SYSTEM ---
// Each offer: {player: Player, offerValue: number, club: string}
var transferOffers = [];
var offerLabels = [];
var acceptOfferBtns = [];
var rejectOfferBtns = [];
var OFFER_TIMER = null;
var OFFER_INTERVAL = 15000; // 15 seconds for demo
var OFFER_CLUBS = ["Galatasaray", "Fenerbahce", "Besiktas", "Trabzonspor", "Basaksehir", "Sivasspor", "Konyaspor", "Antalyaspor", "Alanyaspor", "Denizlispor"];
// --- UTILS ---
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function randomName() {
var first = ["Ahmet", "Mehmet", "Mustafa", "Ali", "Hüseyin", "Hasan", "Cesur", "Osman", "Yusuf", "Murat", "Emre", "Burak", "Fatih", "Serkan", "Onur", "Barış", "Cem", "Eren", "Kaan", "Deniz", "Çınar", "Aziz", "Ege", "Miraç"];
var last = ["Yılmaz", "Kaya", "Demir", "Şahin", "Çelik", "Yıldız", "Yıldırım", "Aydın", "Öztürk", "Arslan", "Doğan", "Kılıç", "Aslan", "Polat", "Koç", "Kurt", "Özdemir", "Aksoy", "Güneş", "Bozkurt", "Bozbalak", "Sakız", "Fizikli"];
return first[randomInt(0, first.length - 1)] + " " + last[randomInt(0, last.length - 1)];
}
function makeRandomPlayer() {
var atk = randomInt(5, 15);
var def = randomInt(5, 15);
var sta = randomInt(10, 20);
var val = Math.floor((atk + def + sta) / 3) + randomInt(PLAYER_MIN_VALUE, PLAYER_MAX_VALUE);
return new Player(randomName(), atk, def, sta, val);
}
// Real-life Turkish Super Lig squads (2023/24, main players, 5 per team for demo)
var realSquads = {
"Galatasaray": [new Player("Mauro Icardi", 18, 8, 16, 40), new Player("Dries Mertens", 16, 7, 15, 36), new Player("Lucas Torreira", 10, 16, 17, 34), new Player("Kerem Aktürkoğlu", 15, 8, 15, 32), new Player("Fernando Muslera", 7, 18, 16, 35)],
"Fenerbahce": [new Player("Edin Dzeko", 17, 7, 15, 38), new Player("Dusan Tadic", 16, 8, 15, 36), new Player("Fred", 12, 14, 16, 33), new Player("Sebastian Szymanski", 15, 9, 15, 32), new Player("Dominik Livakovic", 6, 17, 16, 34)],
"Besiktas": [new Player("Cenk Tosun", 16, 7, 15, 34), new Player("Rachid Ghezzal", 15, 8, 14, 32), new Player("Salih Uçan", 12, 13, 15, 30), new Player("Omar Colley", 8, 16, 15, 31), new Player("Mert Günok", 6, 17, 15, 30)],
"Trabzonspor": [new Player("Edin Visca", 15, 8, 15, 32), new Player("Anastasios Bakasetas", 15, 9, 15, 32), new Player("Uğurcan Çakır", 6, 17, 16, 33), new Player("Enis Bardhi", 14, 8, 14, 29), new Player("Joaquin Fernandez", 8, 15, 14, 28)],
"Basaksehir": [new Player("Danijel Aleksic", 14, 8, 14, 28), new Player("Leo Duarte", 8, 15, 14, 27), new Player("Serdar Gürler", 13, 8, 14, 27), new Player("Mahmut Tekdemir", 9, 14, 14, 26), new Player("Volkan Babacan", 6, 16, 14, 25)],
"Sivasspor": [new Player("Mustapha Yatabare", 14, 8, 14, 27), new Player("Max Gradel", 13, 8, 14, 27), new Player("Hakan Arslan", 10, 13, 14, 25), new Player("Uğur Çiftçi", 8, 14, 14, 24), new Player("Ali Şaşal Vural", 6, 16, 14, 24)],
"Konyaspor": [new Player("Sokol Cikalleshi", 14, 8, 14, 27), new Player("Amir Hadziahmetovic", 11, 13, 14, 25), new Player("Guilherme", 10, 13, 14, 25), new Player("Francisco Calvo", 8, 15, 14, 25), new Player("Ibrahim Sehic", 6, 16, 14, 24)],
"Antalyaspor": [new Player("Haji Wright", 14, 8, 14, 27), new Player("Fernando", 11, 13, 14, 25), new Player("Bünyamin Balcı", 10, 13, 14, 24), new Player("Veysel Sarı", 8, 15, 14, 24), new Player("Helton Leite", 6, 16, 14, 24)],
"Alanyaspor": [new Player("Efecan Karaca", 14, 8, 14, 27), new Player("Famara Diedhiou", 13, 8, 14, 26), new Player("Yusuf Özdemir", 10, 13, 14, 24), new Player("Fidan Aliti", 8, 15, 14, 24), new Player("Runar Runarsson", 6, 16, 14, 24)],
"Denizlispor": [new Player("Ömer Şişmanoğlu", 13, 8, 14, 25), new Player("Mustafa Yumlu", 8, 15, 14, 24), new Player("Gökhan Süzen", 10, 13, 14, 23), new Player("Oğuz Yılmaz", 8, 14, 14, 23), new Player("Adam Stachowiak", 6, 16, 14, 23)]
};
function makeOpponentTeam() {
// List of realistic Turkish club names
var clubNames = ["Denizlispor", "Sivasspor", "Galatasaray", "Fenerbahce", "Trabzonspor", "Besiktas", "Basaksehir", "Konyaspor", "Antalyaspor", "Alanyaspor"];
// Pick a random club name for the opponent
var clubName = clubNames[randomInt(0, clubNames.length - 1)];
var oppPlayers;
if (realSquads[clubName]) {
// Use real squad, clone to avoid reference issues
oppPlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
var p = realSquads[clubName][i];
oppPlayers.push(clonePlayer(p));
}
} else {
// Fallback to random
oppPlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
oppPlayers.push(makeRandomPlayer());
}
}
return new Team(clubName, oppPlayers);
}
function clonePlayer(p) {
return new Player(p.name, p.attack, p.defense, p.stamina, p.value, p.seasonsRemaining);
}
// --- INIT DATA ---
function initPlayers() {
allPlayers = [];
for (var i = 0; i < SQUAD_SIZE + BENCH_SIZE; i++) {
// For initial squad, generate lower stats (attack, defense, stamina)
var atk = randomInt(4, 8);
var def = randomInt(4, 8);
var sta = randomInt(8, 13);
var val = Math.floor((atk + def + sta) / 3) + randomInt(PLAYER_MIN_VALUE, PLAYER_MIN_VALUE + 5);
allPlayers.push(new Player(randomName(), atk, def, sta, val));
}
updateSquadAndBench();
}
function updateSquadAndBench() {
squad = [];
bench = [];
// Ensure squad has at most SQUAD_SIZE players and bench has remaining
for (var i = 0; i < allPlayers.length; i++) {
if (i < SQUAD_SIZE) {
allPlayers[i].inSquad = true;
// Ensure we don't add more than SQUAD_SIZE players to the squad
if (squad.length < SQUAD_SIZE) {
squad.push(allPlayers[i]);
} else {
// If somehow we have too many players marked as squad, put them on bench
allPlayers[i].inSquad = false;
bench.push(allPlayers[i]);
}
} else {
allPlayers[i].inSquad = false;
bench.push(allPlayers[i]);
}
}
// If allPlayers has less than SQUAD_SIZE, squad will naturally have fewer players.
// No need to fill empty slots, the updateSquadLabels function handles this.
}
function initTransferList() {
transferList = [];
// List of latest, highest-valued real-world football players (2024, top market values, demo)
var topPlayers = [new Player("Kylian Mbappé", 20, 12, 19, 180), new Player("Erling Haaland", 21, 10, 18, 170), new Player("Jude Bellingham", 18, 14, 18, 150), new Player("Vinícius Júnior", 19, 12, 18, 150), new Player("Phil Foden", 17, 13, 17, 130), new Player("Bukayo Saka", 17, 12, 17, 120), new Player("Rodri", 14, 18, 17, 120), new Player("Jamal Musiala", 17, 12, 17, 120), new Player("Victor Osimhen", 19, 10, 17, 110), new Player("Florian Wirtz", 16, 12, 17, 110), new Player("Pedri", 15, 13, 17, 100), new Player("Declan Rice", 13, 17, 17, 100), new Player("Harry Kane", 20, 10, 16, 100), new Player("Martin Ødegaard", 16, 13, 16, 100), new Player("Rafael Leão", 18, 10, 16, 90), new Player("Khvicha Kvaratskhelia", 17, 11, 16, 90), new Player("Josko Gvardiol", 10, 18, 16, 90), new Player("Gavi", 14, 14, 16, 90), new Player("Alejandro Balde", 12, 15, 16, 80), new Player("William Saliba", 9, 18, 16, 80), new Player("Son Heung Min", 19, 11, 17, 110)];
// Always show 6 random top players in the transfer market, no duplicates
var usedIdx = [];
for (var i = 0; i < 6; i++) {
var idx;
do {
idx = randomInt(0, topPlayers.length - 1);
} while (usedIdx.indexOf(idx) !== -1);
usedIdx.push(idx);
// When adding to transferList, set seasonsRemaining=3 for transfer market players
var p = topPlayers[idx];
transferList.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, 3));
}
}
// --- UI HELPERS ---
function clearArray(arr) {
while (arr.length > 0) {
var el = arr.pop();
if (el && el.destroy) {
el.destroy();
}
}
}
function makeLabel(txt, x, y, size, color) {
var t = new Text2(txt, {
size: size || 60,
fill: color || "#fff"
});
t.x = x;
t.y = y;
return t;
}
function updateBudgetText() {
budgetText.setText("Budget: $" + budget + "M");
}
function showInfo(msg) {
infoText.setText(msg);
}
function updateSquadLabels() {
clearArray(squadLabels);
// Add extra margin at the top for squad section
var startY = guiY + 240; // Keep top margin for squad section
var squadX = 80; // left margin
var swapBtnX = squadX + 700; // move swap arrow much closer to name
var sellBtnX = squadX + 800; // move sell button just after swap arrow
var rowSpacing = 50; // reduced for almost zero vertical space between squad texts
for (var i = 0; i < SQUAD_SIZE; i++) {
var p = squad[i];
// Check if player exists at this index
if (!p) {
// Display an empty slot if player is missing
var t = makeLabel(i + 1 + ". Empty Slot", squadX, startY + i * rowSpacing, 48, "#aaaaaa");
game.addChild(t);
squadLabels.push(t);
// Do not add swap or sell buttons for empty slots
continue;
}
var seasonsTxt = typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null ? " (" + p.seasonsRemaining + "s)" : "";
var t = makeLabel(i + 1 + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]" + seasonsTxt, squadX, startY + i * rowSpacing, 48, "#ffe066");
game.addChild(t);
squadLabels.push(t);
// Add swap button
var btn = makeLabel("↔", swapBtnX, t.y, 48, "#fff");
btn.idx = i;
btn.interactive = true;
btn.down = function (x, y, obj) {
selectedPlayerIdx = obj.idx;
if (selectedPlayerIdx !== null && squad[selectedPlayerIdx]) {
showInfo("Tap a bench player to swap with " + squad[selectedPlayerIdx].name + " or tap 'Cancel'");
// Add a cancel button if not already present
if (!swapBtns.cancelBtn) {
var cancelBtn = makeLabel("Cancel", swapBtnX + 80, btn.y, 40, "#fdcb6e");
cancelBtn.interactive = true;
cancelBtn.down = function (x, y, obj) {
selectedPlayerIdx = null;
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
showInfo("Substitution cancelled.");
refreshUI();
};
game.addChild(cancelBtn);
swapBtns.cancelBtn = cancelBtn;
}
} else {
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
showInfo("Tap a bench player to swap.");
}
};
game.addChild(btn);
swapBtns.push(btn);
// Add sell button
var sellBtn = makeLabel("Sell", sellBtnX, t.y, 40, "#ff7675");
sellBtn.idx = i;
sellBtn.interactive = true;
sellBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = squad[idx];
if (!p) {
showInfo("Player not available.");
return;
}
// Find the player in allPlayers by reference, not by index
var allIdx = allPlayers.indexOf(p);
if (allIdx !== -1) {
budget += p.value;
allPlayers.splice(allIdx, 1);
updateSquadAndBench();
updateBudgetText();
showInfo("Sold " + p.name + " for $" + p.value + "M");
refreshUI();
} else {
showInfo("Player not found in squad.");
}
};
}(i);
game.addChild(sellBtn);
sellBtns.push(sellBtn);
}
}
function updateBenchLabels() {
clearArray(benchLabels);
// Add extra margin at the top for bench section
var startY = guiY + 240; // Increased for more top margin
var benchX = 1100; // moved closer to squad
var rowSpacing = 48; // reduced for almost zero vertical space between bench texts
for (var i = 0; i < BENCH_SIZE; i++) {
var p = bench[i];
if (!p) {
// Display an empty slot if player is missing
var t = makeLabel("B" + (i + 1) + ". Empty Slot", benchX, startY + i * rowSpacing, 48, "#aaaaaa");
game.addChild(t);
benchLabels.push(t);
continue;
}
var seasonsTxt = typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null ? " (" + p.seasonsRemaining + "s)" : "";
var t = makeLabel("B" + (i + 1) + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]" + seasonsTxt, benchX, startY + i * rowSpacing, 48, "#b2bec3");
game.addChild(t);
benchLabels.push(t);
// Add swap handler
t.idx = i;
t.interactive = true;
t.down = function (x, y, obj) {
if (selectedPlayerIdx !== null) {
// Swap squad[selectedPlayerIdx] with bench[obj.idx]
var sIdx = selectedPlayerIdx;
var bIdx = obj.idx;
// Ensure both slots have a player before swapping
if (squad[sIdx] && bench[bIdx]) {
var temp = squad[sIdx];
squad[sIdx] = bench[bIdx];
bench[bIdx] = temp;
} else if (!squad[sIdx] && bench[bIdx]) {
// Move bench player to empty squad slot
squad[sIdx] = bench[bIdx];
bench[bIdx] = undefined; // Or null, or remove from array if it's a sparse array
} else if (squad[sIdx] && !bench[bIdx]) {
// Move squad player to empty bench slot
bench[bIdx] = squad[sIdx];
squad[sIdx] = undefined; // Or null, or remove from array
} else {
// Both are empty or other unexpected state, do nothing
selectedPlayerIdx = null; // Clear selection
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
showInfo("Cannot swap with empty slots.");
refreshUI();
return;
}
// Update allPlayers order - Reconstruct allPlayers from squad and bench
allPlayers = [];
for (var j = 0; j < squad.length; j++) {
if (squad[j]) allPlayers.push(squad[j]);
}
for (var j = 0; j < bench.length; j++) {
if (bench[j]) allPlayers.push(bench[j]);
}
// Recalculate squad and bench based on new allPlayers order
updateSquadAndBench();
selectedPlayerIdx = null;
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
showInfo("Swapped players.");
refreshUI();
return;
}
};
}
}
function updateTransferLabels() {
clearArray(transferBtns);
clearArray(buyBtns);
// --- Centered Transfer Market Layout ---
// Calculate center X for the section
var sectionWidth = 1100;
var sectionX = (2048 - sectionWidth) / 2;
var rowHeight = 64;
var sectionHeight = (transferList.length + 1) * rowHeight + 120;
var startY = 400; // Start well below the top for visual balance
// Remove old transferText if present
if (transferText) {
transferText.destroy();
}
// Centered header
transferText = makeLabel("Transfer Market", 2048 / 2, startY - 90, 56, "#00b894");
transferText.anchor.set(0.5, 0); // Center header horizontally
game.addChild(transferText);
// Calculate X positions for player info and buy button
var playerInfoX = sectionX + 40;
var buyBtnX = sectionX + sectionWidth - 180;
for (var i = 0; i < transferList.length; i++) {
var p = transferList[i];
// Centered row Y
var rowY = startY + i * rowHeight;
// Player info label, left-aligned in section
var t = makeLabel(p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "] $" + p.value + "M", playerInfoX, rowY, 44, "#fff");
t.anchor.set(0, 0); // Left align in section
game.addChild(t);
transferBtns.push(t);
// Buy button, right-aligned in section
var buyBtn = makeLabel("Buy", buyBtnX, rowY, 40, "#00b894");
buyBtn.idx = i;
buyBtn.interactive = true;
buyBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = transferList[idx];
if (!p) {
showInfo("Player not available.");
return;
}
if (budget < p.value) {
showInfo("Not enough budget!");
return;
}
// Allow buying a player as long as the total number of players is less than the maximum allowed
if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) {
showInfo("Squad full! Sell a player first.");
return;
}
budget -= p.value;
// When buying, always set seasonsRemaining=3
allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, 3));
updateSquadAndBench();
updateBudgetText();
showInfo("Bought " + p.name + " for $" + p.value + "M");
// Remove from transfer list, add new
transferList.splice(idx, 1, makeRandomPlayer());
refreshUI();
};
}(i);
game.addChild(buyBtn);
buyBtns.push(buyBtn);
}
}
function updateOpponentLabels() {
clearArray(opponentLabels);
// Position opponent section at bottom-left (for reference, but now only for opponent info)
var oppStartY = 2048 - (SQUAD_SIZE + 2) * 120 - 200; // increased row height and more margin for opponent section
if (oppStartY < guiY + 1800) {
oppStartY = guiY + 1800;
} // push down if needed for more space
// --- League Table: show all teams, slightly larger, and moved to the left ---
// Place league table just above the opponent section, but below the transfer market
var leagueWidth = 600; // slightly larger
var leagueX = 80; // move to the left side of the screen
var leagueY = oppStartY - 650; // place above opponent section, below transfer market
if (leagueY < guiY + 600) leagueY = guiY + 600;
var leagueHeader = makeLabel("League Table", leagueX, leagueY, 54, "#fdcb6e"); // slightly larger font
game.addChild(leagueHeader);
opponentLabels.push(leagueHeader);
// Sort league by points, then goal difference, then goals for
var sortedLeague = leagueTeams.slice().sort(function (a, b) {
if (b.points !== a.points) {
return b.points - a.points;
}
var gdA = a.goalsFor - a.goalsAgainst;
var gdB = b.goalsFor - b.goalsAgainst;
if (gdB !== gdA) {
return gdB - gdA;
}
return b.goalsFor - a.goalsFor;
});
for (var i = 0; i < sortedLeague.length; i++) {
var team = sortedLeague[i];
var color = team.name === "You" ? "#00cec9" : "#fff";
var gd = team.goalsFor - team.goalsAgainst;
var labelTxt = i + 1 + ". " + team.name + " Pts:" + team.points + " GP:" + team.played + " W:" + team.wins + " D:" + team.draws + " L:" + team.losses + " GD:" + gd;
var teamLabel = makeLabel(labelTxt, leagueX, leagueY + 70 + i * 48, 38, color); // slightly larger font and spacing
game.addChild(teamLabel);
opponentLabels.push(teamLabel);
}
// Now show opponent section below league table
var t = makeLabel("Next Opponent: " + opponentTeam.name, 80, oppStartY, 56, "#fab1a0");
game.addChild(t);
opponentLabels.push(t);
// Reduce vertical spacing between opponent team player names to minimum without overlap
var oppPlayerFontSize = 40;
var oppPlayerSpacing = oppPlayerFontSize + 2; // 2px gap to avoid touching
for (var i = 0; i < SQUAD_SIZE; i++) {
var p = opponentTeam.players[i];
var pt = makeLabel(i + 1 + ". " + p.name + " [A:" + p.attack + " D:" + p.defense + " S:" + p.stamina + "]", 80, oppStartY + 120 + i * oppPlayerSpacing, oppPlayerFontSize, "#fff");
game.addChild(pt);
opponentLabels.push(pt);
}
}
function clearMatchText() {
if (matchText) {
matchText.destroy();
matchText = null;
}
}
function showMatchLog() {
clearMatchText();
var log = matchLog.join("\n");
matchText = new Text2(log, {
size: 48,
fill: "#fff",
wordWrap: true,
wordWrapWidth: 1800
});
// Position match summary directly underneath the Play Match button
var playBtnX = 2048 / 2 - 200; // Same as playBtn X
var playBtnY = 2048 - 200; // Same as playBtn Y
matchText.x = playBtnX;
matchText.y = playBtnY + 180; // 180px below Play Match button for extra separation
game.addChild(matchText);
}
function clearAllUI() {
clearArray(squadLabels);
clearArray(benchLabels);
clearArray(transferBtns);
clearArray(buyBtns);
clearArray(swapBtns);
clearArray(sellBtns);
clearArray(opponentLabels);
// --- YOUTH ACADEMY UI ---
clearArray(youthLabels);
clearArray(promoteBtns);
clearArray(sellYouthBtns);
if (transferText) {
transferText.destroy();
}
transferText = null;
// --- CLEAR TRANSFER OFFER UI ---
clearArray(offerLabels);
clearArray(acceptOfferBtns);
clearArray(rejectOfferBtns);
clearMatchText();
if (playBtn) {
playBtn.destroy();
}
playBtn = null;
if (nextBtn) {
nextBtn.destroy();
}
nextBtn = null;
}
// --- LEAGUE SYSTEM ---
// League teams: user + 10 Turkish clubs
var leagueClubNames = ["Denizlispor", "Sivasspor", "Galatasaray", "Fenerbahce", "Trabzonspor", "Besiktas", "Basaksehir", "Konyaspor", "Antalyaspor", "Alanyaspor"];
var leagueTeams = []; // [{name, points, played, wins, draws, losses, goalsFor, goalsAgainst}]
var leagueFixtures = []; // [{homeIdx, awayIdx}]
var currentFixtureIdx = 0;
var userTeamIdx = 0; // always 0
function initLeague() {
leagueTeams = [];
// User team
leagueTeams.push({
name: "You",
points: 0,
played: 0,
wins: 0,
draws: 0,
losses: 0,
goalsFor: 0,
goalsAgainst: 0
});
// Opponent clubs
for (var i = 0; i < leagueClubNames.length; i++) {
var clubName = leagueClubNames[i];
leagueTeams.push({
name: clubName,
points: 0,
played: 0,
wins: 0,
draws: 0,
losses: 0,
goalsFor: 0,
goalsAgainst: 0,
// Attach real squad if available for league simulation
realSquad: realSquads[clubName] ? realSquads[clubName].map(function (p) {
return clonePlayer(p);
}) : null
});
}
// Generate fixtures: each team plays every other team twice (home/away)
leagueFixtures = [];
var n = leagueTeams.length;
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
if (i !== j) {
// Only add each pair twice (home/away)
if (i < j) {
leagueFixtures.push({
homeIdx: i,
awayIdx: j
});
leagueFixtures.push({
homeIdx: j,
awayIdx: i
});
}
}
}
}
// Shuffle fixtures for variety
for (var k = leagueFixtures.length - 1; k > 0; k--) {
var r = randomInt(0, k);
var temp = leagueFixtures[k];
leagueFixtures[k] = leagueFixtures[r];
leagueFixtures[r] = temp;
}
currentFixtureIdx = 0;
}
function getCurrentOpponentIdx() {
// Find the next fixture where user is home or away
for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) {
var f = leagueFixtures[i];
if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) {
return f.homeIdx === userTeamIdx ? f.awayIdx : f.homeIdx;
}
}
return null;
}
function getCurrentFixture() {
for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) {
var f = leagueFixtures[i];
if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) {
return {
idx: i,
fixture: f
};
}
}
return null;
}
function advanceFixture() {
// Move to next user fixture
for (var i = currentFixtureIdx + 1; i < leagueFixtures.length; i++) {
var f = leagueFixtures[i];
if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) {
currentFixtureIdx = i;
return;
}
}
// No more fixtures: season over
currentFixtureIdx = leagueFixtures.length;
}
function isSeasonOver() {
// If all user fixtures played
for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) {
var f = leagueFixtures[i];
if (f.homeIdx === userTeamIdx || f.awayIdx === userTeamIdx) {
return false;
}
}
return true;
}
// --- GAME LOGIC ---
function simulateMatch() {
matchLog = [];
matchResult = null;
matchInProgress = true;
// --- Add a random number of youth players after each match ---
var numNewYouth = randomInt(0, 3);
if (youthAcademy.length < YOUTH_MAX && numNewYouth > 0) {
for (var i = 0; i < numNewYouth; i++) {
if (youthAcademy.length >= YOUTH_MAX) break; // Don't add more than max
// Generate a young player (attributes 1-10)
var atk = randomInt(1, 10);
var def = randomInt(1, 10);
var sta = randomInt(1, 10);
// Calculate base stat sum and average
var statSum = atk + def + sta;
var statAvg = Math.floor(statSum / 3);
// Most players: value 1-5M, some: 6-10M, all <= 10M
var val;
if (Math.random() < 0.8) {
val = Math.max(1, Math.min(5, statAvg + randomInt(0, 1)));
} else {
val = Math.max(6, Math.min(10, statAvg + randomInt(2, 4)));
if (val < 6) val = 5;
}
if (val > 10) val = 10; // Cap value at 10M for youth academy players
var p = new Player(randomName(), atk, def, sta, val, null);
youthAcademy.push(p);
}
if (numNewYouth === 1) {
showInfo("A new youth player has joined your academy!");
} else if (numNewYouth > 1) {
showInfo(numNewYouth + " new youth players have joined your academy!");
}
refreshUI();
}
// Find all fixtures for this matchday (all teams play one match)
if (currentFixtureIdx >= leagueFixtures.length) {
matchLog.push("Season is over!");
showMatchLog();
matchInProgress = false;
return;
}
// Gather all fixtures for this matchday (each team plays once)
var nTeams = leagueTeams.length;
var matchdayFixtures = [];
var teamsPlayed = {};
for (var i = currentFixtureIdx; i < leagueFixtures.length; i++) {
var f = leagueFixtures[i];
if (!teamsPlayed[f.homeIdx] && !teamsPlayed[f.awayIdx]) {
matchdayFixtures.push({
idx: i,
fixture: f
});
teamsPlayed[f.homeIdx] = true;
teamsPlayed[f.awayIdx] = true;
if (Object.keys(teamsPlayed).length >= nTeams) {
break;
}
}
}
// Simulate all matches in this matchday
var userMatchIdx = -1;
for (var m = 0; m < matchdayFixtures.length; m++) {
var fixtureObj = matchdayFixtures[m];
var fixture = fixtureObj.fixture;
var homeIdx = fixture.homeIdx;
var awayIdx = fixture.awayIdx;
var homeTeam = leagueTeams[homeIdx];
var awayTeam = leagueTeams[awayIdx];
// Prepare teams
var homePlayers, awayPlayers;
if (homeIdx === userTeamIdx) {
homePlayers = squad;
} else {
// Use real squad if available, else generate random team
if (homeTeam.realSquad) {
homePlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
homePlayers.push(clonePlayer(homeTeam.realSquad[i]));
}
} else {
homePlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
homePlayers.push(makeRandomPlayer());
}
}
}
if (awayIdx === userTeamIdx) {
awayPlayers = squad;
} else {
if (awayTeam.realSquad) {
awayPlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
awayPlayers.push(clonePlayer(awayTeam.realSquad[i]));
}
} else {
awayPlayers = [];
for (var i = 0; i < SQUAD_SIZE; i++) {
awayPlayers.push(makeRandomPlayer());
}
}
}
// Calculate stats
// Determine team strengths
var homeStrength = 0;
for (var i = 0; i < homePlayers.length; i++) {
homeStrength += homePlayers[i].attack + homePlayers[i].defense + homePlayers[i].stamina;
}
var awayStrength = 0;
for (var i = 0; i < awayPlayers.length; i++) {
awayStrength += awayPlayers[i].attack + awayPlayers[i].defense + awayPlayers[i].stamina;
}
var homeGoals = 0,
awayGoals = 0;
// Simulate match based on strength and randomness
// A simple model: higher strength means more chances to score
// Reduce number of chances and scoring probability for more realistic scores
var homeChances = Math.max(1, Math.floor(homeStrength / 40) + randomInt(-1, 1)); // Fewer chances, less randomness
var awayChances = Math.max(1, Math.floor(awayStrength / 40) + randomInt(-1, 1)); // Fewer chances, less randomness
for (var i = 0; i < homeChances; i++) {
if (Math.random() < 0.38) {
// Lower chance to score per chance
homeGoals++;
}
}
for (var i = 0; i < awayChances; i++) {
if (Math.random() < 0.38) {
// Lower chance to score per chance
awayGoals++;
}
}
for (var turn = 0; turn < 5; turn++) {
// Home attack (for match log details)
var atkP = homePlayers[turn];
var defP = awayPlayers[turn];
// Check if players are defined before accessing their properties
if (!atkP || !defP) {
// Skip this turn if a player is missing
continue;
}
var atkChance = atkP.attack + randomInt(0, atkP.stamina);
var defChance = defP.defense + randomInt(0, defP.stamina);
if (atkChance > defChance + 3) {
//homeGoals++; // Already accounted for in overall simulation
} else if (defChance > atkChance + 5) {
// Defensive action (for match log details)
}
// Away attack (for match log details)
var oAtkP = awayPlayers[turn];
var oDefP = homePlayers[turn];
// Check if players are defined before accessing their properties
if (!oAtkP || !oDefP) {
// Skip this turn if a player is missing
continue;
}
var oAtkChance = oAtkP.attack + randomInt(0, oAtkP.stamina);
var oDefChance = oDefP.defense + randomInt(0, oDefP.stamina);
if (oAtkChance > oDefChance + 3) {
//awayGoals++; // Already accounted for in overall simulation
} else if (oDefChance > oAtkChance + 5) {
// Defensive action (for match log details)
}
}
// Update league table
homeTeam.played += 1;
awayTeam.played += 1;
homeTeam.goalsFor += homeGoals;
homeTeam.goalsAgainst += awayGoals;
awayTeam.goalsFor += awayGoals;
awayTeam.goalsAgainst += homeGoals;
if (homeGoals > awayGoals) {
homeTeam.points += 3;
homeTeam.wins += 1;
awayTeam.losses += 1;
} else if (homeGoals < awayGoals) {
awayTeam.points += 3;
awayTeam.wins += 1;
homeTeam.losses += 1;
} else {
homeTeam.points += 1;
awayTeam.points += 1;
homeTeam.draws += 1;
awayTeam.draws += 1;
}
// If this is the user's match, log details and handle rewards
if (homeIdx === userTeamIdx || awayIdx === userTeamIdx) {
userMatchIdx = m;
var userGoals = homeIdx === userTeamIdx ? homeGoals : awayGoals;
var oppGoals = homeIdx === userTeamIdx ? awayGoals : homeGoals;
var oppIdx = homeIdx === userTeamIdx ? awayIdx : homeIdx;
var oppName = leagueTeams[oppIdx].name;
for (var turn = 0; turn < 5; turn++) {
// User attack
var atkP = squad[turn];
var defP = homeIdx === userTeamIdx ? awayPlayers[turn] : homePlayers[turn];
// Check if players are defined before accessing their properties
if (!atkP || !defP) {
// Skip this turn if a player is missing
continue;
}
var atkChance = atkP.attack + randomInt(0, atkP.stamina);
var defChance = defP.defense + randomInt(0, defP.stamina);
if (atkChance > defChance + 5 && Math.random() < 0.5) {
// Harder to score, require bigger difference and add randomness
matchLog.push("Minute " + (turn * 18 + 5) + ": " + atkP.name + " scores!");
} else if (defChance > atkChance + 3) {
matchLog.push("Minute " + (turn * 18 + 8) + ": " + defP.name + " makes a key tackle.");
}
// Opponent attack
var oAtkP = homeIdx === userTeamIdx ? awayPlayers[turn] : homePlayers[turn];
var oDefP = squad[turn];
// Check if players are defined before accessing their properties
if (!oAtkP || !oDefP) {
// Skip this turn if a player is missing
continue;
}
var oAtkChance = oAtkP.attack + randomInt(0, oAtkP.stamina);
var oDefChance = oDefP.defense + randomInt(0, oDefP.stamina);
if (oAtkChance > oDefChance + 5 && Math.random() < 0.5) {
// Harder to score, require bigger difference and add randomness
matchLog.push("Minute " + (turn * 18 + 12) + ": " + oAtkP.name + " scores!");
} else if (oDefChance > oAtkChance + 3) {
matchLog.push("Minute " + (turn * 18 + 15) + ": " + oDefP.name + " blocks a shot.");
}
}
matchLog.push("Full Time: You " + userGoals + " - " + oppGoals + " " + oppName);
// Rewards
if (userGoals > oppGoals) {
matchResult = "win";
matchLog.push("You win! +$20M");
budget += 20;
} else if (userGoals < oppGoals) {
matchResult = "lose";
matchLog.push("You lose.");
} else {
matchResult = "draw";
matchLog.push("Draw. +$5M");
budget += 5;
}
}
}
// Advance fixture pointer by number of fixtures played this matchday
currentFixtureIdx += matchdayFixtures.length;
// Restore stamina a bit after match
for (var i = 0; i < homePlayers.length; i++) {
if (homeIdx === userTeamIdx) {
homePlayers[i].stamina = Math.max(0, homePlayers[i].stamina - randomInt(3, 6)); // Decrease stamina after playing
homePlayers[i].stamina = Math.min(homePlayers[i].maxStamina, homePlayers[i].stamina + randomInt(1, 3)); // Partial recovery
}
}
for (var i = 0; i < awayPlayers.length; i++) {
if (awayIdx === userTeamIdx) {
awayPlayers[i].stamina = Math.max(0, awayPlayers[i].stamina - randomInt(3, 6)); // Decrease stamina after playing
awayPlayers[i].stamina = Math.min(awayPlayers[i].maxStamina, awayPlayers[i].stamina + randomInt(1, 3)); // Partial recovery
}
}
updateBudgetText();
showMatchLog();
matchInProgress = false;
}
function refreshUI() {
clearAllUI();
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
// Add extra vertical space between all sections by adjusting guiY and section Y positions
// Squad section
updateSquadLabels();
// Bench section (move further down)
guiY = 0; // reset
updateBenchLabels();
// Transfer section (move further down)
updateTransferLabels();
// Opponent and league table section (move further down)
updateOpponentLabels();
updateBudgetText();
showInfo("Pick lineup, buy/sell, then Play Match!");
// --- YOUTH ACADEMY UI ---
clearArray(youthLabels);
clearArray(promoteBtns);
clearArray(sellYouthBtns);
// Place youth academy to the right of the buy buttons in the transfer market
var youthX = 80 + 750 + 300; // sectionX + buyBtn offset + extra margin
var youthY = guiY + 600; // align vertically with transfer section
var youthHeader = makeLabel("Youth Academy", youthX, youthY, 54, "#81ecec");
game.addChild(youthHeader);
youthLabels.push(youthHeader);
for (var i = 0; i < youthAcademy.length; i++) {
var yp = youthAcademy[i];
var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", youthX, youthY + 70 + i * 60, 40, "#fff");
game.addChild(t);
youthLabels.push(t);
// Promote button
var promoteBtn = makeLabel("Promote", youthX + 420, t.y, 36, "#00b894");
promoteBtn.idx = i;
promoteBtn.interactive = true;
promoteBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to promote.");
return;
}
// Allow promoting a player as long as the total number of players is less than the maximum allowed
if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) {
showInfo("Squad full! Sell a player first.");
return;
}
allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null));
updateSquadAndBench();
showInfo("Promoted " + p.name + " to your team!");
youthAcademy.splice(idx, 1);
refreshUI();
};
}(i);
game.addChild(promoteBtn);
promoteBtns.push(promoteBtn);
// Sell button
var sellBtn = makeLabel("Sell", youthX + 600, t.y, 36, "#fdcb6e");
sellBtn.idx = i;
sellBtn.interactive = true;
sellBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to sell.");
return;
}
budget += p.value;
updateBudgetText();
showInfo("Sold " + p.name + " for $" + p.value + "M");
youthAcademy.splice(idx, 1);
refreshUI();
};
}(i);
game.addChild(sellBtn);
sellYouthBtns.push(sellBtn);
}
// --- TRANSFER OFFERS UI (now under youth academy) ---
clearArray(offerLabels);
clearArray(acceptOfferBtns);
clearArray(rejectOfferBtns);
var offerX = youthX;
var offerY = youthY + 70 + Math.max(1, youthAcademy.length) * 60 + 40; // place below youth academy
if (transferOffers.length > 0) {
var offerHeader = makeLabel("Transfer Offers", offerX, offerY, 54, "#fdcb6e");
game.addChild(offerHeader);
offerLabels.push(offerHeader);
for (var i = 0; i < transferOffers.length; i++) {
var offer = transferOffers[i];
var p = offer.player;
// Only show player name and offer amount, hide stats
var txt = offer.club + " offers $" + offer.offerValue + "M for " + p.name;
var t = makeLabel(txt, offerX, offerY + 70 + i * 60, 40, "#fff");
game.addChild(t);
offerLabels.push(t);
// Accept button
var acceptBtn = makeLabel("Accept", offerX + 420, t.y, 36, "#00b894");
acceptBtn.idx = i;
acceptBtn.interactive = true;
acceptBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var offer = transferOffers[idx];
var p = offer.player;
// Remove player from allPlayers, squad/bench
var allIdx = allPlayers.indexOf(p);
if (allIdx !== -1) {
budget += offer.offerValue;
allPlayers.splice(allIdx, 1);
updateSquadAndBench();
updateBudgetText();
showInfo("Sold " + p.name + " to " + offer.club + " for $" + offer.offerValue + "M");
transferOffers.splice(idx, 1);
refreshUI();
} else {
showInfo("Player not found.");
}
};
}(i);
game.addChild(acceptBtn);
acceptOfferBtns.push(acceptBtn);
// Reject button
var rejectBtn = makeLabel("Reject", offerX + 600, t.y, 36, "#ff7675");
rejectBtn.idx = i;
rejectBtn.interactive = true;
rejectBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var offer = transferOffers[idx];
showInfo("Rejected offer for " + offer.player.name + ".");
transferOffers.splice(idx, 1);
refreshUI();
};
}(i);
game.addChild(rejectBtn);
rejectOfferBtns.push(rejectBtn);
}
}
// --- YOUTH ACADEMY UI ---
clearArray(youthLabels);
clearArray(promoteBtns);
clearArray(sellYouthBtns);
// Place youth academy to the right of the buy buttons in the transfer market
var youthX = 80 + 750 + 300; // sectionX + buyBtn offset + extra margin
var youthY = guiY + 600; // align vertically with transfer section
var youthHeader = makeLabel("Youth Academy", youthX, youthY, 54, "#81ecec");
game.addChild(youthHeader);
youthLabels.push(youthHeader);
for (var i = 0; i < youthAcademy.length; i++) {
var yp = youthAcademy[i];
var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", youthX, youthY + 70 + i * 60, 40, "#fff");
game.addChild(t);
youthLabels.push(t);
// Promote button
var promoteBtn = makeLabel("Promote", youthX + 420, t.y, 36, "#00b894");
promoteBtn.idx = i;
promoteBtn.interactive = true;
promoteBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to promote.");
return;
}
if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) {
showInfo("Squad full! Sell a player first.");
return;
}
allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null));
updateSquadAndBench();
showInfo("Promoted " + p.name + " to your team!");
youthAcademy.splice(idx, 1);
refreshUI();
};
}(i);
game.addChild(promoteBtn);
promoteBtns.push(promoteBtn);
// Sell button
var sellBtn = makeLabel("Sell", youthX + 600, t.y, 36, "#fdcb6e");
sellBtn.idx = i;
sellBtn.interactive = true;
sellBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to sell.");
return;
}
budget += p.value;
updateBudgetText();
showInfo("Sold " + p.name + " for $" + p.value + "M");
youthAcademy.splice(idx, 1);
refreshUI();
};
}(i);
game.addChild(sellBtn);
sellYouthBtns.push(sellBtn);
}
// --- YOUTH ACADEMY GENERATION TIMER ---
if (!youthTimer) {
youthTimer = LK.setInterval(function () {
if (youthAcademy.length < YOUTH_MAX) {
// Generate a young player (attributes 1-10)
var atk = randomInt(1, 10);
var def = randomInt(1, 10);
var sta = randomInt(1, 10);
// Calculate base stat sum and average
var statSum = atk + def + sta;
var statAvg = Math.floor(statSum / 3);
// Most players: value 1-5M, some: 6-10M, all <= 10M
var val;
// 80% chance for 1-5M, 20% for 6-10M (if stats are high enough)
if (Math.random() < 0.8) {
// Value 1-5M, based on statAvg, but never below 1M
val = Math.max(1, Math.min(5, statAvg + randomInt(0, 1)));
} else {
// Value 6-10M, only if statAvg is high enough
val = Math.max(6, Math.min(10, statAvg + randomInt(2, 4)));
// If statAvg is too low, fallback to 5M
if (val < 6) val = 5;
}
if (val > 10) val = 10; // Cap value at 10M for youth academy players
var p = new Player(randomName(), atk, def, sta, val, null);
youthAcademy.push(p);
showInfo("A new youth player has joined your academy!");
refreshUI();
}
}, YOUTH_TIMER_INTERVAL);
}
// --- TRANSFER OFFER GENERATION TIMER REMOVED ---
// Transfer offers are now only generated at end of season, see next change_block.
// Play match button (bottom middle, with extra margin from all sections)
var playBtnX = 2048 / 2 - 200; // Centered horizontally, adjust for button width
var playBtnY = 2048 - 200; // 200px from bottom
playBtn = makeLabel("Play Match", playBtnX, playBtnY, 70, "#00cec9");
playBtn.interactive = true;
playBtn.down = function (x, y, obj) {
if (matchInProgress) {
return;
}
simulateMatch();
playBtn.destroy();
playBtn = null;
// Next match button (bottom middle, below Play Match)
var nextBtnX = 2048 / 2 - 200;
var nextBtnY = playBtnY + 120;
nextBtn = makeLabel("Next Match", nextBtnX, nextBtnY, 60, "#fdcb6e");
nextBtn.interactive = true;
nextBtn.down = function (x, y, obj) {
// Restore stamina a bit
for (var i = 0; i < allPlayers.length; i++) {
allPlayers[i].stamina = Math.min(allPlayers[i].maxStamina, allPlayers[i].stamina + randomInt(1, 3));
}
// Check if season is over
if (isSeasonOver()) {
// Calculate final league position for user
var sortedLeague = leagueTeams.slice().sort(function (a, b) {
if (b.points !== a.points) {
return b.points - a.points;
}
var gdA = a.goalsFor - a.goalsAgainst;
var gdB = b.goalsFor - b.goalsAgainst;
if (gdB !== gdA) {
return gdB - gdA;
}
return b.goalsFor - a.goalsFor;
});
var userFinalPos = 1;
for (var i = 0; i < sortedLeague.length; i++) {
if (sortedLeague[i].name === "You") {
userFinalPos = i + 1;
break;
}
}
// Prize money by position
var prize = 5;
if (userFinalPos === 1) {
prize = 50;
} else if (userFinalPos === 2) {
prize = 30;
} else if (userFinalPos === 3) {
prize = 20;
} else if (userFinalPos === 4) {
prize = 10;
}
// Award prize
budget += prize;
showInfo("Season finished! You placed #" + userFinalPos + ". Prize: $" + prize + "M. Table resets for new season.");
updateBudgetText();
// Decrement seasonsRemaining for transfer market players, remove those at 0
for (var i = allPlayers.length - 1; i >= 0; i--) {
var p = allPlayers[i];
if (typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null) {
p.seasonsRemaining--;
if (p.seasonsRemaining <= 0) {
allPlayers.splice(i, 1);
showInfo("Player " + p.name + " has retired/left after 3 seasons.");
}
}
}
updateSquadAndBench();
// --- Generate up to 3 transfer offers for squad/bench players at end of season ---
transferOffers = [];
var candidates = squad.concat(bench).slice(); // copy
// Shuffle candidates
for (var i = candidates.length - 1; i > 0; i--) {
var j = randomInt(0, i);
var temp = candidates[i];
candidates[i] = candidates[j];
candidates[j] = temp;
}
var offersToMake = Math.min(3, candidates.length);
for (var i = 0; i < offersToMake; i++) {
var p = candidates[i];
// Offer value: 90% to 120% of player value
var offerVal = Math.floor(p.value * (randomInt(90, 120) / 100));
// Pick a random club
var club = OFFER_CLUBS[randomInt(0, OFFER_CLUBS.length - 1)];
transferOffers.push({
player: p,
offerValue: offerVal,
club: club
});
}
// Only show info if there are offers
if (transferOffers.length > 0) {
showInfo("You have received " + transferOffers.length + " transfer offer(s) for your players!");
}
// Reset league and start new season
initLeague();
// Do NOT reset allPlayers, squad, or bench here; keep current team for next season
// Only reset transfer market for new season
initTransferList();
// Set first opponent
var oppIdx = getCurrentOpponentIdx();
if (oppIdx !== null) {
// Generate new opponent team for this club
opponentTeam = makeOpponentTeam();
opponentTeam.name = leagueTeams[oppIdx].name;
}
clearMatchText();
nextBtn.destroy();
nextBtn = null;
refreshUI();
return;
}
// Next opponent in league
var oppIdx = getCurrentOpponentIdx();
if (oppIdx !== null) {
opponentTeam = makeOpponentTeam();
opponentTeam.name = leagueTeams[oppIdx].name;
}
clearMatchText();
nextBtn.destroy();
nextBtn = null;
refreshUI();
};
game.addChild(nextBtn);
};
game.addChild(playBtn);
}
// --- INIT UI ---
var currentScreen = "main"; // "main", "transfer", "league", "youth"
var navBtns = [];
function showScreen(screen) {
currentScreen = screen;
clearAllUI();
// Remove cancel button if present
if (swapBtns.cancelBtn) {
swapBtns.cancelBtn.destroy();
swapBtns.cancelBtn = null;
}
// Always show nav buttons
showNavButtons();
if (screen === "main") {
updateSquadLabels();
updateBenchLabels();
updateOpponentLabels();
updateBudgetText();
showInfo("Pick lineup, buy/sell, then Play Match!");
// Play Match button
var playBtnX = 2048 / 2 - 200;
var playBtnY = 2048 - 200;
playBtn = makeLabel("Play Match", playBtnX, playBtnY, 70, "#00cec9");
playBtn.interactive = true;
playBtn.down = function (x, y, obj) {
if (matchInProgress) return;
simulateMatch();
playBtn.destroy();
playBtn = null;
// Next match button
var nextBtnX = 2048 / 2 - 200;
var nextBtnY = playBtnY + 120;
nextBtn = makeLabel("Next Match", nextBtnX, nextBtnY, 60, "#fdcb6e");
nextBtn.interactive = true;
nextBtn.down = function (x, y, obj) {
// Restore stamina a bit
for (var i = 0; i < allPlayers.length; i++) {
allPlayers[i].stamina = Math.min(allPlayers[i].maxStamina, allPlayers[i].stamina + randomInt(1, 3));
}
// Check if season is over
if (isSeasonOver()) {
// Calculate final league position for user
var sortedLeague = leagueTeams.slice().sort(function (a, b) {
if (b.points !== a.points) return b.points - a.points;
var gdA = a.goalsFor - a.goalsAgainst;
var gdB = b.goalsFor - b.goalsAgainst;
if (gdB !== gdA) return gdB - gdA;
return b.goalsFor - a.goalsFor;
});
var userFinalPos = 1;
for (var i = 0; i < sortedLeague.length; i++) {
if (sortedLeague[i].name === "You") {
userFinalPos = i + 1;
break;
}
}
// Prize money by position
var prize = 5;
if (userFinalPos === 1) prize = 50;else if (userFinalPos === 2) prize = 30;else if (userFinalPos === 3) prize = 20;else if (userFinalPos === 4) prize = 10;
// Award prize
budget += prize;
showInfo("Season finished! You placed #" + userFinalPos + ". Prize: $" + prize + "M. Table resets for new season.");
updateBudgetText();
// Decrement seasonsRemaining for transfer market players, remove those at 0
for (var i = allPlayers.length - 1; i >= 0; i--) {
var p = allPlayers[i];
if (typeof p.seasonsRemaining === "number" && p.seasonsRemaining !== null) {
p.seasonsRemaining--;
if (p.seasonsRemaining <= 0) {
allPlayers.splice(i, 1);
showInfo("Player " + p.name + " has retired/left after 3 seasons.");
}
}
}
updateSquadAndBench();
// --- Generate up to 3 transfer offers for squad/bench players at end of season ---
transferOffers = [];
var candidates = squad.concat(bench).slice();
for (var i = candidates.length - 1; i > 0; i--) {
var j = randomInt(0, i);
var temp = candidates[i];
candidates[i] = candidates[j];
candidates[j] = temp;
}
var offersToMake = Math.min(3, candidates.length);
for (var i = 0; i < offersToMake; i++) {
var p = candidates[i];
var offerVal = Math.floor(p.value * (randomInt(90, 120) / 100));
var club = OFFER_CLUBS[randomInt(0, OFFER_CLUBS.length - 1)];
transferOffers.push({
player: p,
offerValue: offerVal,
club: club
});
}
if (transferOffers.length > 0) {
showInfo("You have received " + transferOffers.length + " transfer offer(s) for your players!");
}
initLeague();
initTransferList();
var oppIdx = getCurrentOpponentIdx();
if (oppIdx !== null) {
opponentTeam = makeOpponentTeam();
opponentTeam.name = leagueTeams[oppIdx].name;
}
clearMatchText();
nextBtn.destroy();
nextBtn = null;
showScreen("main");
return;
}
// Next opponent in league
var oppIdx = getCurrentOpponentIdx();
if (oppIdx !== null) {
opponentTeam = makeOpponentTeam();
opponentTeam.name = leagueTeams[oppIdx].name;
}
clearMatchText();
nextBtn.destroy();
nextBtn = null;
showScreen("main");
};
game.addChild(nextBtn);
};
game.addChild(playBtn);
} else if (screen === "transfer") {
updateTransferLabels();
updateBudgetText();
showInfo("Buy top players for your team!");
} else if (screen === "league") {
updateOpponentLabels();
showInfo("Check the league table and your next opponent.");
} else if (screen === "youth") {
// Only show youth academy and transfer offers
clearArray(youthLabels);
clearArray(promoteBtns);
clearArray(sellYouthBtns);
// --- Centered Youth Academy Layout ---
var sectionWidth = 1100;
var youthX = (2048 - sectionWidth) / 2;
var rowHeight = 64;
var youthY = 400;
// Centered header
var youthHeader = makeLabel("Youth Academy", 2048 / 2, youthY, 54, "#81ecec");
youthHeader.anchor.set(0.5, 0);
game.addChild(youthHeader);
youthLabels.push(youthHeader);
// Calculate X positions for player info and buttons
var playerInfoX = youthX + 40;
var promoteBtnX = youthX + sectionWidth - 320;
var sellBtnX = youthX + sectionWidth - 160;
for (var i = 0; i < youthAcademy.length; i++) {
var yp = youthAcademy[i];
var rowY = youthY + 70 + i * rowHeight;
var t = makeLabel(yp.name + " [A:" + yp.attack + " D:" + yp.defense + " S:" + yp.stamina + "] $" + yp.value + "M", playerInfoX, rowY, 40, "#fff");
t.anchor.set(0, 0);
game.addChild(t);
youthLabels.push(t);
// Promote button
var promoteBtn = makeLabel("Promote", promoteBtnX, rowY, 36, "#00b894");
promoteBtn.idx = i;
promoteBtn.interactive = true;
promoteBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to promote.");
return;
}
// Allow promoting a player as long as the total number of players is less than the maximum allowed
if (allPlayers.length >= SQUAD_SIZE + BENCH_SIZE) {
showInfo("Squad full! Sell a player first.");
return;
}
allPlayers.push(new Player(p.name, p.attack, p.defense, p.stamina, p.value, null));
updateSquadAndBench();
showInfo("Promoted " + p.name + " to your team!");
youthAcademy.splice(idx, 1);
showScreen("youth");
};
}(i);
game.addChild(promoteBtn);
promoteBtns.push(promoteBtn);
// Sell button
var sellBtn = makeLabel("Sell", sellBtnX, rowY, 36, "#fdcb6e");
sellBtn.idx = i;
sellBtn.interactive = true;
sellBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var p = youthAcademy[idx];
if (!p) {
showInfo("No youth player to sell.");
return;
}
budget += p.value;
updateBudgetText();
showInfo("Sold " + p.name + " for $" + p.value + "M");
youthAcademy.splice(idx, 1);
showScreen("youth");
};
}(i);
game.addChild(sellBtn);
sellYouthBtns.push(sellBtn);
}
// Transfer offers
clearArray(offerLabels);
clearArray(acceptOfferBtns);
clearArray(rejectOfferBtns);
var offerX = youthX + 40;
var offerY = youthY + 70 + Math.max(1, youthAcademy.length) * rowHeight + 40;
if (transferOffers.length > 0) {
var offerHeader = makeLabel("Transfer Offers", 2048 / 2, offerY, 54, "#fdcb6e");
offerHeader.anchor.set(0.5, 0);
game.addChild(offerHeader);
offerLabels.push(offerHeader);
for (var i = 0; i < transferOffers.length; i++) {
var offer = transferOffers[i];
var p = offer.player;
var rowY = offerY + 70 + i * rowHeight;
var txt = offer.club + " offers $" + offer.offerValue + "M for " + p.name;
var t = makeLabel(txt, offerX, rowY, 40, "#fff");
t.anchor.set(0, 0);
game.addChild(t);
offerLabels.push(t);
// Accept button
var acceptBtn = makeLabel("Accept", promoteBtnX, rowY, 36, "#00b894");
acceptBtn.idx = i;
acceptBtn.interactive = true;
acceptBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var offer = transferOffers[idx];
var p = offer.player;
var allIdx = allPlayers.indexOf(p);
if (allIdx !== -1) {
budget += offer.offerValue;
allPlayers.splice(allIdx, 1);
updateSquadAndBench();
updateBudgetText();
showInfo("Sold " + p.name + " to " + offer.club + " for $" + offer.offerValue + "M");
transferOffers.splice(idx, 1);
showScreen("youth");
} else {
showInfo("Player not found.");
}
};
}(i);
game.addChild(acceptBtn);
acceptOfferBtns.push(acceptBtn);
// Reject button
var rejectBtn = makeLabel("Reject", sellBtnX, rowY, 36, "#ff7675");
rejectBtn.idx = i;
rejectBtn.interactive = true;
rejectBtn.down = function (idxCopy) {
return function (x, y, obj) {
var idx = idxCopy;
var offer = transferOffers[idx];
showInfo("Rejected offer for " + offer.player.name + ".");
transferOffers.splice(idx, 1);
showScreen("youth");
};
}(i);
game.addChild(rejectBtn);
rejectOfferBtns.push(rejectBtn);
}
}
updateBudgetText();
showInfo("Manage your youth academy and transfer offers.");
}
}
function showNavButtons() {
clearArray(navBtns);
// Button positions - move to very bottom of screen, with spacing and not touching each other or the edge
var btnY = 2732 - 100; // 100px from bottom edge for safe area
var btnCount = 4;
var btnWidth = 320; // estimated width for button label
var btnSpacing = 60; // space between buttons
var sideMargin = 60; // margin from left/right edge
var totalWidth = btnCount * btnWidth + (btnCount - 1) * btnSpacing;
var btnXStart = Math.max(sideMargin, (2048 - totalWidth) / 2); // center all buttons horizontally, but never touch edge
var btns = [{
label: "Main",
screen: "main",
color: 0x00CEC9
}, {
label: "Transfer Market",
screen: "transfer",
color: 0x00B894
}, {
label: "League Table",
screen: "league",
color: 0xFDCB6E
}, {
label: "Youth Academy",
screen: "youth",
color: 0x81ECEC
}];
for (var i = 0; i < btns.length; i++) {
var b = btns[i];
var btnX = btnXStart + i * (btnWidth + btnSpacing);
var navBtn = makeLabel(b.label, btnX, btnY, 48, b.color);
navBtn.interactive = true;
navBtn.screen = b.screen;
navBtn.down = function (screenName) {
return function (x, y, obj) {
showScreen(screenName);
};
}(b.screen);
game.addChild(navBtn);
navBtns.push(navBtn);
}
}
function initUI() {
guiY = 0;
// Title
var title = new Text2("Mini Football Manager", {
size: 90,
fill: 0x00CEC9
});
title.x = 80;
title.y = guiY + 40;
game.addChild(title);
// Budget
budgetText = new Text2("Budget: $" + budget + "M", {
size: 60,
fill: "#fff"
});
budgetText.x = 80;
budgetText.y = guiY + 120;
game.addChild(budgetText);
// Info
infoText = new Text2("", {
size: 54,
fill: 0xFDCB6E
});
infoText.x = 600;
infoText.y = guiY + 120;
game.addChild(infoText);
showScreen("main");
}
// --- GAME START ---
function newGame() {
budget = INITIAL_BUDGET;
initLeague();
initPlayers();
initTransferList();
// --- YOUTH ACADEMY RESET ---
youthAcademy = [];
if (youthTimer) {
LK.clearInterval(youthTimer);
youthTimer = null;
}
// --- TRANSFER OFFERS RESET ---
transferOffers = [];
if (OFFER_TIMER) {
LK.clearInterval(OFFER_TIMER);
OFFER_TIMER = null;
}
clearArray(offerLabels);
clearArray(acceptOfferBtns);
clearArray(rejectOfferBtns);
// Set first opponent in league
var oppIdx = getCurrentOpponentIdx();
if (oppIdx !== null) {
opponentTeam = makeOpponentTeam();
opponentTeam.name = leagueTeams[oppIdx].name;
} else {
opponentTeam = makeOpponentTeam();
}
matchInProgress = false;
matchLog = [];
matchResult = null;
selectedPlayerIdx = null;
selectedBenchIdx = null;
initUI();
}
newGame();
// --- END ---