From 236b5b8d67b0cba14451a7b632559c10e0da8dad Mon Sep 17 00:00:00 2001 From: Bateast Date: Sun, 9 Mar 2025 15:11:51 +0000 Subject: [PATCH] =?UTF-8?q?T=C3=A9l=C3=A9verser=20les=20fichiers=20vers=20?= =?UTF-8?q?"Sources"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/game.js | 902 +++++++++++++++++++++++++++++++++++++++++++++ Sources/index.html | 47 +++ Sources/style.css | 223 +++++++++++ 3 files changed, 1172 insertions(+) create mode 100644 Sources/game.js create mode 100644 Sources/index.html create mode 100644 Sources/style.css diff --git a/Sources/game.js b/Sources/game.js new file mode 100644 index 0000000..e8ba141 --- /dev/null +++ b/Sources/game.js @@ -0,0 +1,902 @@ +class Game { + constructor() { + this.menuScreen = document.getElementById('menuScreen'); + this.gameScreen = document.getElementById('gameScreen'); + this.canvas = document.getElementById('gameCanvas'); + + // Stats initialization + this.stats = { + beersServed: 0, + totalMoney: 0, + perfectPours: 0, + maxStreak: 0 + }; + + if (!this.canvas) { + console.error('Game canvas not found!'); + return; + } + + this.ctx = this.canvas.getContext('2d'); + + // Set canvas size + this.canvas.width = 600; + this.canvas.height = 600; + + // Colors + this.backgroundColor = '#1a1a1a'; + this.foregroundColor = '#e0e0e0'; + + // Game state + this.money = 0; + this.timer = 60; + this.currentLevel = 0; + this.targetLevel = 0; + this.isPouring = false; + this.gameActive = false; + this.lastTime = 0; + this.feedbackMessage = ''; + this.feedbackTimer = 0; + this.perfectStreak = 0; + + // Keg system + this.kegCapacity = 20; + this.currentKeg = this.kegCapacity; + this.kegPrice = 10; + this.kegsInStock = 0; // Add this line + + // Level system + this.level = 1; + this.levelTarget = 10; + this.currentLevelMoney = 0; + this.upgrades = { + pourSpeed: { level: 1, cost: 5, name: "Pour Speed" }, + accuracy: { level: 1, cost: 8, name: "Accuracy" }, + timer: { level: 1, cost: 10, name: "Extra Time" } + }; + this.pourSpeed = 0.005; + + // Background canvas setup + this.bgCanvas = document.getElementById('backgroundCanvas'); + if (this.bgCanvas) { + this.bgCtx = this.bgCanvas.getContext('2d'); + this.bgCanvas.width = window.innerWidth; + this.bgCanvas.height = window.innerHeight; + + // Bubbles setup + this.bubbles = Array.from({length: 50}, () => this.createBubble()); + this.backgroundAnimation(); + } + + // Initialize instructions + const instructionsCanvas = document.getElementById('instructionsCanvas'); + if (instructionsCanvas) { + instructionsCanvas.width = 100; + instructionsCanvas.height = 80; + const ictx = instructionsCanvas.getContext('2d'); + this.drawMouseIcon(ictx, 50, 40); + } + + this.setupEventListeners(); + } + + startGame() { + if (!this.menuScreen || !this.gameScreen) return; + if (!this.canvas || !this.ctx) return; + + this.menuScreen.classList.add('hidden'); + this.gameScreen.classList.remove('hidden'); + this.canvas.style.display = 'block'; + this.gameActive = true; + this.timer = 60 + (this.upgrades.timer.level - 1) * 10; + this.money = 0; + this.currentLevel = 0; + this.currentLevelMoney = 0; + this.level = 1; + this.levelTarget = 10; + this.lastTime = Date.now(); + this.resetLevel(); + + this.draw(); + this.gameLoop(); + } + + draw() { + this.ctx.fillStyle = this.backgroundColor; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // Dessiner le contour arrondi + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 4; + const radius = 15; + + this.ctx.beginPath(); + this.ctx.moveTo(radius, 0); + this.ctx.lineTo(this.canvas.width - radius, 0); + this.ctx.quadraticCurveTo(this.canvas.width, 0, this.canvas.width, radius); + this.ctx.lineTo(this.canvas.width, this.canvas.height - radius); + this.ctx.quadraticCurveTo(this.canvas.width, this.canvas.height, this.canvas.width - radius, this.canvas.height); + this.ctx.lineTo(radius, this.canvas.height); + this.ctx.quadraticCurveTo(0, this.canvas.height, 0, this.canvas.height - radius); + this.ctx.lineTo(0, radius); + this.ctx.quadraticCurveTo(0, 0, radius, 0); + this.ctx.stroke(); + + // Draw game elements + this.drawTap(); + this.drawGlass(); + this.drawMoneyBag(); + this.drawTimer(); + this.drawPrice(); + this.drawKegMeter(); // Add this line + this.drawKegStock(); // Ajout de l'indicateur de fûts en stock + + // Draw level info + this.ctx.font = '12px "Press Start 2P"'; + this.ctx.fillStyle = this.foregroundColor; + this.ctx.fillText(`Level ${this.level}`, 10, 30); + this.ctx.fillText(`Target: $${this.levelTarget}`, 10, 50); + this.ctx.fillText(`Progress: $${this.currentLevelMoney}`, 10, 70); + + if (this.isPouring) { + this.drawPourStream(); + } + + if (this.feedbackTimer > 0) { + this.drawFeedback(); + } + } + + drawFeedback() { + const animationProgress = 1 - (this.feedbackTimer / 1.5); + + this.ctx.font = '16px "Press Start 2P"'; + const centerX = this.canvas.width / 2; + const textWidth = this.ctx.measureText(this.feedbackMessage).width; + const feedbackY = 450; + + let shakeOffset = 0; + let verticalBounce = 0; + + if (this.feedbackMessage.includes('PERFECT!')) { + const shakeSpeed = Math.max(10, 30 - this.perfectStreak * 2); + const shakeAmount = 2 + (this.perfectStreak * 0.8); + verticalBounce = Math.sin(Date.now() / 200) * (this.perfectStreak * 2); + shakeOffset = Math.sin(Date.now() / shakeSpeed) * shakeAmount; + + // Ajout d'une rotation avec le streak + this.ctx.save(); + this.ctx.translate(centerX, feedbackY); + this.ctx.rotate(Math.sin(Date.now() / 200) * (this.perfectStreak * 0.02)); + this.ctx.translate(-centerX, -feedbackY); + } + + if (this.feedbackMessage.includes('PERFECT!')) { + const goldIntensity = Math.min(255, 218 + (this.perfectStreak * 5)); + this.ctx.fillStyle = `rgb(${goldIntensity}, ${Math.floor(goldIntensity * 0.84)}, 0)`; + } else { + this.ctx.fillStyle = `rgba(224, 224, 224, ${1 - animationProgress * 0.7})`; + } + + this.ctx.fillText(this.feedbackMessage, centerX - textWidth/2 + shakeOffset, feedbackY + verticalBounce); + + if (this.feedbackMessage.includes('PERFECT!')) { + this.ctx.restore(); + } + } + + drawTap() { + this.ctx.fillStyle = this.foregroundColor; + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + + // Corps principal du robinet + this.ctx.beginPath(); + this.ctx.rect(285, 25, 30, 25); // Ajusté pour le nouveau centre + this.ctx.fill(); + + // Bec verseur + this.ctx.beginPath(); + this.ctx.moveTo(295, 50); // Ajusté + this.ctx.lineTo(305, 50); // Ajusté + this.ctx.lineTo(300, 60); // Ajusté + this.ctx.closePath(); + this.ctx.fill(); + + // Base décorative + this.ctx.beginPath(); + this.ctx.rect(290, 20, 20, 5); // Ajusté + this.ctx.fill(); + + // Poignée latérale avec style rétro + const handleRotation = this.isPouring ? Math.PI / 6 : 0; + this.ctx.save(); + this.ctx.translate(320, 35); // Ajusté pour aligner avec le nouveau corps du robinet + this.ctx.rotate(handleRotation); + + // Tige de la poignée + this.ctx.beginPath(); + this.ctx.rect(0, -3, 15, 6); + this.ctx.fill(); + + // Embout de la poignée + this.ctx.beginPath(); + this.ctx.rect(15, -5, 5, 10); + this.ctx.fill(); + + this.ctx.restore(); + + // Détails décoratifs + this.ctx.beginPath(); + this.ctx.rect(285, 32, 30, 2); // Ajusté pour aligner avec le nouveau corps + this.ctx.rect(285, 40, 30, 2); // Ajusté pour aligner avec le nouveau corps + this.ctx.fill(); + } + + checkResult() { + const accuracy = Math.abs(this.currentLevel - this.targetLevel); + const accuracyBonus = this.upgrades.accuracy.level * 0.005; + + this.stats.beersServed++; + + if (accuracy < (0.02 + accuracyBonus)) { + const streakBonus = this.perfectStreak; // Get current streak before incrementing + this.money += 2 + streakBonus; // Add streak bonus to money + this.currentLevelMoney += 2 + streakBonus; + this.perfectStreak++; + this.stats.perfectPours++; + this.stats.maxStreak = Math.max(this.stats.maxStreak, this.perfectStreak); + this.stats.totalMoney += 2 + streakBonus; + this.feedbackMessage = this.perfectStreak > 1 ? + `PERFECT! x${this.perfectStreak} +$${2 + streakBonus}` : + 'PERFECT! +$2'; + } else { + this.perfectStreak = 0; + if (accuracy < (0.05 + accuracyBonus)) { + this.money += 1; + this.currentLevelMoney += 1; + this.feedbackMessage = 'GOOD! +$1'; + if (this.currentKeg <= 0) { + this.showKegEmptyMessage(); + return; + } + + this.currentKeg--; + } else if (this.currentLevel > this.targetLevel) { + this.money = Math.max(0, this.money - 1); + this.feedbackMessage = 'TOO MUCH! -$1'; + } else { + this.feedbackMessage = 'NOT ENOUGH!'; + + } + } + + this.feedbackTimer = 1.5; + setTimeout(() => { + if (this.currentLevelMoney >= this.levelTarget) { + this.showShop(); + } else { + this.resetLevel(); + } + }, 1000); + } + showKegEmptyMessage() { + this.gameActive = false; + const kegScreen = document.createElement('div'); + kegScreen.style.position = 'absolute'; + kegScreen.style.top = '50%'; + kegScreen.style.left = '50%'; + kegScreen.style.transform = 'translate(-50%, -50%)'; + kegScreen.style.backgroundColor = this.backgroundColor; + kegScreen.style.border = `2px solid ${this.foregroundColor}`; + kegScreen.style.padding = '20px'; + kegScreen.style.textAlign = 'center'; + kegScreen.style.color = this.foregroundColor; + kegScreen.style.fontFamily = '"Press Start 2P", monospace'; + + kegScreen.innerHTML = ` +

KEG EMPTY!

+

You need a new keg to continue.

+

Cost: $${this.kegPrice}

+ ${this.kegsInStock > 0 ? ` + + ` : ` + + `} + `; + + this.gameScreen.appendChild(kegScreen); + window.game = this; + } + buyNewKeg() { + if (this.money >= this.kegPrice) { + this.money -= this.kegPrice; + this.currentKeg = this.kegCapacity; + this.gameScreen.querySelector('div[style*="position: absolute"]')?.remove(); + this.gameActive = true; + this.lastTime = Date.now(); + this.gameLoop(); + } + } + resetLevel() { + this.currentLevel = 0; + + // Cible plus aléatoire avec des valeurs plus extrêmes + this.targetLevel = Math.random() * 0.8 + 0.1; + + // Calcul du bonus de vitesse basé sur le niveau + const levelSpeedBonus = Math.floor((this.level - 1) / 2) * 0.1; // Adjusted to reduce speed increase + + // Vitesses réduites pour les deux modes + const baseSpeed = Math.random() > 0.5 ? + (Math.random() * 0.004 + 0.003) : // Vitesse lente (était 0.008 + 0.005) + (Math.random() * 0.01 + 0.008); // Vitesse rapide (était 0.02 + 0.015) + + this.pourSpeed = baseSpeed * + (1 + levelSpeedBonus) * + (1 + (this.upgrades.pourSpeed.level - 1) * 0.1); // Adjusted to reduce speed increase + } + + showShop() { + this.gameActive = false; + + // Remove any existing shop screen first + const existingShop = this.gameScreen.querySelector('div[style*="position: absolute"]'); + if (existingShop) { + existingShop.remove(); + } + + const shopScreen = document.createElement('div'); + shopScreen.style.position = 'absolute'; + shopScreen.style.top = '50%'; + shopScreen.style.left = '50%'; + shopScreen.style.transform = 'translate(-50%, -50%)'; + shopScreen.style.backgroundColor = this.backgroundColor; + shopScreen.style.border = `2px solid ${this.foregroundColor}`; + shopScreen.style.padding = '20px'; + shopScreen.style.textAlign = 'center'; + shopScreen.style.color = this.foregroundColor; + shopScreen.style.fontFamily = '"Press Start 2P", monospace'; + + shopScreen.innerHTML = ` +

LEVEL ${this.level} COMPLETE!

+

Money: $${this.money}

+
+ ${Object.entries(this.upgrades).map(([key, upgrade]) => ` + + `).join('')} + +
+ + `; + + this.gameScreen.appendChild(shopScreen); + window.game = this; + } + + // Corriger la méthode buyUpgrade en retirant la méthode buyExtraKeg imbriquée + buyUpgrade(type) { + const upgrade = this.upgrades[type]; + if (this.money >= upgrade.cost) { + this.money -= upgrade.cost; + upgrade.level++; + upgrade.cost = Math.floor(upgrade.cost * 1.5); + + // Mettre à jour l'affichage de la boutique + this.showShop(); // Refresh the shop display after purchase + } + } + + // Ajouter buyExtraKeg comme méthode séparée de la classe + buyExtraKeg() { + if (this.money >= this.kegPrice) { + this.money -= this.kegPrice; + this.kegsInStock++; + + // Update shop display + const shopScreen = this.gameScreen.querySelector('div[style*="position: absolute"]'); + if (shopScreen) { + shopScreen.querySelector('p').textContent = `Money: $${this.money}`; + const buttons = shopScreen.querySelectorAll('button'); + buttons.forEach(button => { + if (button.textContent.includes('Buy Extra Keg')) { + button.disabled = this.money < this.kegPrice; + } + }); + } + } + } + + // Ajouter useStoredKeg comme méthode séparée de la classe + useStoredKeg() { + if (this.kegsInStock > 0) { + this.kegsInStock--; + this.currentKeg = this.kegCapacity; + this.gameScreen.querySelector('div[style*="position: absolute"]')?.remove(); + this.gameActive = true; + this.lastTime = Date.now(); + this.gameLoop(); + } + } + + nextLevel() { + // Prevent multiple executions + if (!this.gameActive) { + const shopScreen = this.gameScreen.querySelector('div[style*="position: absolute"]'); + if (shopScreen) { + shopScreen.remove(); + } + this.level++; + this.levelTarget = Math.floor(this.levelTarget * 1.5); + this.currentLevelMoney = 0; + this.timer = 60 + (this.upgrades.timer.level - 1) * 10; + this.gameActive = true; + this.resetLevel(); + this.lastTime = Date.now(); + this.gameLoop(); + } + } + + backgroundAnimation() { + this.updateBubbles(); + this.drawBackground(); + requestAnimationFrame(() => this.backgroundAnimation()); + } + + createBubble() { + return { + x: Math.random() * this.bgCanvas.width, + y: this.bgCanvas.height + Math.random() * 20, + size: Math.random() * 8 + 4, + speed: Math.random() * 3 + 1.5, // Vitesse augmentée (était 1.5 + 0.5) + opacity: Math.random() * 0.5 + 0.1 + }; + } + + updateBubbles() { + this.bubbles.forEach(bubble => { + bubble.y -= bubble.speed; + if (bubble.y < -20) { + Object.assign(bubble, this.createBubble()); + } + }); + } + + drawBackground() { + this.bgCtx.clearRect(0, 0, this.bgCanvas.width, this.bgCanvas.height); + + // Draw bubbles + this.bubbles.forEach(bubble => { + this.bgCtx.beginPath(); + this.bgCtx.strokeStyle = `rgba(224, 224, 224, ${bubble.opacity})`; + this.bgCtx.lineWidth = 2; + this.bgCtx.arc(bubble.x, bubble.y, bubble.size, 0, Math.PI * 2); + this.bgCtx.stroke(); + }); + } + + update() { + if (!this.gameActive) return; + + const currentTime = Date.now(); + const deltaTime = (currentTime - this.lastTime) / 1000; + this.lastTime = currentTime; + + this.timer -= deltaTime; + if (this.timer <= 0) { + this.timer = 0; + this.gameActive = false; + this.showGameOver(); + return; + } + + if (this.isPouring) { + this.currentLevel += this.pourSpeed; + if (this.currentLevel >= 1) { + this.currentLevel = 1; + this.isPouring = false; + this.checkResult(); + } + } + + if (this.feedbackTimer > 0) { + this.feedbackTimer -= deltaTime; + } + } + + showGameOver() { + const gameOverScreen = document.createElement('div'); + gameOverScreen.style.position = 'absolute'; + gameOverScreen.style.top = '50%'; + gameOverScreen.style.left = '50%'; + gameOverScreen.style.transform = 'translate(-50%, -50%)'; + gameOverScreen.style.backgroundColor = this.backgroundColor; + gameOverScreen.style.border = `2px solid ${this.foregroundColor}`; + gameOverScreen.style.padding = '20px'; + gameOverScreen.style.textAlign = 'center'; + gameOverScreen.style.color = this.foregroundColor; + gameOverScreen.style.fontFamily = '"Press Start 2P", monospace'; + + gameOverScreen.innerHTML = ` +

GAME OVER

+

Money earned: $${this.money}

+
+

STATS

+

Beers Served: ${this.stats.beersServed}

+

Total Money: $${this.stats.totalMoney}

+

Perfect Pours: ${this.stats.perfectPours}

+

Best Streak: ${this.stats.maxStreak}

+
+ + `; + + this.gameScreen.appendChild(gameOverScreen); + } + + gameLoop() { + if (this.gameActive) { + this.update(); + this.draw(); + requestAnimationFrame(() => this.gameLoop()); + } + } + + setupEventListeners() { + const startButton = document.getElementById('startButton'); + const patchNotesButton = document.getElementById('patchNotesButton'); + + if (startButton) { + startButton.addEventListener('click', () => this.startGame()); + } + + if (patchNotesButton) { + patchNotesButton.addEventListener('click', () => { + document.getElementById('patchNotesOverlay').classList.remove('hidden'); + }); + } + + if (!this.canvas) return; + + this.canvas.addEventListener('mousedown', () => this.startPouring()); + this.canvas.addEventListener('mouseup', () => this.stopPouring()); + this.canvas.addEventListener('touchstart', (e) => { + e.preventDefault(); + this.startPouring(); + }); + this.canvas.addEventListener('touchend', (e) => { + e.preventDefault(); + this.stopPouring(); + }); + } + + startPouring() { + if (this.gameActive && this.currentLevel < 1) { + this.isPouring = true; + } + } + + stopPouring() { + if (this.isPouring && this.gameActive) { + this.isPouring = false; + this.checkResult(); + } + } + drawMouseIcon(ctx, x, y) { + ctx.strokeStyle = this.foregroundColor; + ctx.fillStyle = this.foregroundColor; + ctx.lineWidth = 2; + + // Draw mouse outline + ctx.beginPath(); + ctx.moveTo(x - 12, y - 15); + ctx.lineTo(x - 12, y + 10); + ctx.quadraticCurveTo(x - 12, y + 20, x, y + 20); + ctx.quadraticCurveTo(x + 12, y + 20, x + 12, y + 10); + ctx.lineTo(x + 12, y - 15); + ctx.quadraticCurveTo(x + 12, y - 20, x, y - 20); + ctx.quadraticCurveTo(x - 12, y - 20, x - 12, y - 15); + ctx.stroke(); + + // Draw scroll wheel + ctx.beginPath(); + ctx.moveTo(x, y - 20); + ctx.lineTo(x, y - 5); + ctx.stroke(); + + // Draw left button + ctx.beginPath(); + ctx.moveTo(x - 12, y - 15); + ctx.lineTo(x, y - 15); + ctx.lineTo(x, y - 5); + ctx.lineTo(x - 12, y - 5); + ctx.closePath(); + ctx.fill(); + + // Draw scroll indicator + ctx.beginPath(); + ctx.rect(x - 2, y - 12, 4, 4); + ctx.stroke(); + + // Draw click animation + ctx.beginPath(); + ctx.moveTo(x, y - 20); + ctx.quadraticCurveTo(x, y - 35, x - 5, y - 35); + ctx.stroke(); + } + + drawGlass() { + const centerX = this.canvas.width / 2; + const glassTop = 200; + const glassBottom = 400; // Réduit pour un verre plus harmonieux + const glassWidth = 150; + + // Draw glass outline + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.moveTo(centerX - glassWidth/2, glassTop); + this.ctx.lineTo(centerX - glassWidth/2, glassBottom); + this.ctx.lineTo(centerX + glassWidth/2, glassBottom); + this.ctx.lineTo(centerX + glassWidth/2, glassTop); + this.ctx.stroke(); + + // Draw enlarged glass handle + const handleWidth = 60; + const handleHeight = 150; + this.ctx.beginPath(); + this.ctx.arc(centerX + glassWidth/2 + handleWidth/4, glassTop + handleHeight/2, handleWidth/2, Math.PI / 2, -Math.PI / 2, true); + this.ctx.stroke(); + + // Draw target line + this.ctx.setLineDash([4, 4]); + this.ctx.beginPath(); + const targetY = glassBottom - ((glassBottom - glassTop) * this.targetLevel); + this.ctx.moveTo(centerX - glassWidth/2, targetY); + this.ctx.lineTo(centerX + glassWidth/2, targetY); + this.ctx.stroke(); + this.ctx.setLineDash([]); + + // Draw liquid + if (this.currentLevel > 0) { + const liquidHeight = (glassBottom - glassTop) * this.currentLevel; + this.drawBeerPattern( + centerX - glassWidth/2, + glassBottom - liquidHeight, + glassWidth, + liquidHeight + ); + + // Adjust foam height based on pour speed + const baseFoamHeight = 10; + const maxFoamHeight = 25; + const foamHeight = baseFoamHeight + (maxFoamHeight - baseFoamHeight) * (this.pourSpeed / 0.01); + const foamWidth = glassWidth; + const foamY = glassBottom - liquidHeight - foamHeight; + this.ctx.fillStyle = this.foregroundColor; + + // Draw foam pattern with adjusted alignment + const startX = Math.floor(centerX - foamWidth/2) + 2; + for (let y = Math.floor(foamY); y < foamY + foamHeight; y += 4) { + for (let x = startX; x < centerX + foamWidth/2 - 2; x += 4) { + this.ctx.beginPath(); + this.ctx.arc(x, y, 2, 0, Math.PI * 2); + this.ctx.fill(); + } + } + } +} + + drawBeerPattern(x, y, width, height) { + this.ctx.fillStyle = this.foregroundColor; + const dotSize = 2; + const spacing = 4; + + for (let i = 0; i < width; i += spacing) { + for (let j = 0; j < height; j += spacing) { + this.ctx.fillRect(x + i, y + j, dotSize, dotSize); + } + } + } + + drawMoneyBag() { + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '24px "Press Start 2P"'; // Agrandi + this.ctx.fillText(`$${this.money}`, 50, 300); // Ajusté + } + + drawTimer() { + const centerX = 500; // Ajusté + const centerY = 300; // Ajusté + const radius = 35; // Agrandi + + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); + this.ctx.stroke(); + + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '16px "Press Start 2P"'; + const timerText = Math.ceil(this.timer).toString(); + const textWidth = this.ctx.measureText(timerText).width; + this.ctx.fillText(timerText, centerX - textWidth/2, centerY + 6); + } + + drawPrice() { + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '16px "Press Start 2P"'; // Agrandi + this.ctx.fillText('$1', this.canvas.width / 2 - 15, 180); // Ajusté + } + + drawPourStream() { + this.ctx.fillStyle = this.foregroundColor; + const centerX = this.canvas.width / 2; + const glassTop = 200; + const liquidTop = glassTop + ((400 - glassTop) * (1 - this.currentLevel)); // Ajusté pour la nouvelle hauteur + + this.ctx.beginPath(); + this.ctx.moveTo(centerX, 35); + this.ctx.lineTo(centerX + 4, liquidTop); + this.ctx.lineTo(centerX - 4, liquidTop); + this.ctx.closePath(); + this.ctx.fill(); + } + drawKegMeter() { + const y = 480; + const x = this.canvas.width / 2 - 100; + const width = 200; + const height = 30; + + // Draw keg outline and fill + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x, y, width, height); + + const fillWidth = (this.currentKeg / this.kegCapacity) * width; + this.ctx.fillStyle = this.foregroundColor; + this.ctx.fillRect(x, y, fillWidth, height); + + // Draw keg count above + this.ctx.font = '12px "Press Start 2P"'; + this.ctx.fillStyle = this.foregroundColor; + const countText = `${this.currentKeg}/${this.kegCapacity}`; + const countWidth = this.ctx.measureText(countText).width; + this.ctx.fillText(countText, x + (width/2) - (countWidth/2), y - 5); + + // Add "KEG METER" text below + const meterText = "KEG METER"; + const meterWidth = this.ctx.measureText(meterText).width; + this.ctx.fillText(meterText, x + (width/2) - (meterWidth/2), y + height + 20); + } + + // Ajouter cette nouvelle méthode + drawKegStock() { + if (this.kegsInStock > 0) { + const x = 500; // Garde l'alignement vertical avec le timer (centerX) + const y = 480; // Même hauteur que la jauge de fût + const kegWidth = 20; + const kegHeight = 30; + const lineSpacing = 8; + + // Dessiner l'icône du fût (rectangle simple) + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + + // Rectangle principal + this.ctx.strokeRect(x - kegWidth/2, y, kegWidth, kegHeight); + + // Lignes horizontales intérieures + this.ctx.beginPath(); + this.ctx.moveTo(x - kegWidth/2, y + lineSpacing); + this.ctx.lineTo(x + kegWidth/2, y + lineSpacing); + this.ctx.moveTo(x - kegWidth/2, y + kegHeight - lineSpacing); + this.ctx.lineTo(x + kegWidth/2, y + kegHeight - lineSpacing); + this.ctx.stroke(); + + // Afficher le nombre + this.ctx.font = '12px "Press Start 2P"'; + this.ctx.fillStyle = this.foregroundColor; + this.ctx.fillText(`x${this.kegsInStock}`, x + 15, y + 20); + } + } + + drawBeerPattern(x, y, width, height) { + this.ctx.fillStyle = this.foregroundColor; + const dotSize = 2; + const spacing = 4; + + for (let i = 0; i < width; i += spacing) { + for (let j = 0; j < height; j += spacing) { + this.ctx.fillRect(x + i, y + j, dotSize, dotSize); + } + } + } + + drawMoneyBag() { + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '24px "Press Start 2P"'; // Agrandi + this.ctx.fillText(`$${this.money}`, 50, 300); // Ajusté + } + + drawTimer() { + const centerX = 500; // Ajusté + const centerY = 300; // Ajusté + const radius = 35; // Agrandi + + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); + this.ctx.stroke(); + + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '16px "Press Start 2P"'; + const timerText = Math.ceil(this.timer).toString(); + const textWidth = this.ctx.measureText(timerText).width; + this.ctx.fillText(timerText, centerX - textWidth/2, centerY + 6); + } + + drawPrice() { + this.ctx.fillStyle = this.foregroundColor; + this.ctx.font = '16px "Press Start 2P"'; // Agrandi + this.ctx.fillText('$1', this.canvas.width / 2 - 15, 180); // Ajusté + } + + drawPourStream() { + this.ctx.fillStyle = this.foregroundColor; + const centerX = this.canvas.width / 2; + const glassTop = 200; + const liquidTop = glassTop + ((400 - glassTop) * (1 - this.currentLevel)); // Ajusté pour la nouvelle hauteur + + this.ctx.beginPath(); + this.ctx.moveTo(centerX, 35); + this.ctx.lineTo(centerX + 4, liquidTop); + this.ctx.lineTo(centerX - 4, liquidTop); + this.ctx.closePath(); + this.ctx.fill(); + } + drawKegMeter() { + const y = 480; + const x = this.canvas.width / 2 - 100; + const width = 200; + const height = 30; + + // Draw keg outline and fill + this.ctx.strokeStyle = this.foregroundColor; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x, y, width, height); + + const fillWidth = (this.currentKeg / this.kegCapacity) * width; + this.ctx.fillStyle = this.foregroundColor; + this.ctx.fillRect(x, y, fillWidth, height); + + // Draw keg count above + this.ctx.font = '12px "Press Start 2P"'; + this.ctx.fillStyle = this.foregroundColor; + const countText = `${this.currentKeg}/${this.kegCapacity}`; + const countWidth = this.ctx.measureText(countText).width; + this.ctx.fillText(countText, x + (width/2) - (countWidth/2), y - 5); + + // Add "KEG METER" text below + const meterText = "KEG METER"; + const meterWidth = this.ctx.measureText(meterText).width; + this.ctx.fillText(meterText, x + (width/2) - (meterWidth/2), y + height + 20); + } +} + +window.addEventListener('load', () => { + new Game(); +}); \ No newline at end of file diff --git a/Sources/index.html b/Sources/index.html new file mode 100644 index 0000000..d574a08 --- /dev/null +++ b/Sources/index.html @@ -0,0 +1,47 @@ + + + + + + Perfect Pour + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/style.css b/Sources/style.css new file mode 100644 index 0000000..02d91f4 --- /dev/null +++ b/Sources/style.css @@ -0,0 +1,223 @@ +body { + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; + background-color: #1a1a1a; + font-family: 'Press Start 2P', monospace; + color: #e0e0e0; +} + +#menuScreen, #gameScreen { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + padding: 20px; + box-sizing: border-box; +} + +.menu-content { + position: relative; + z-index: 1; + text-align: center; + width: 100%; + max-width: 600px; + padding: 20px; +} + +.game-title { + font-size: clamp(2rem, 8vw, 4rem); + line-height: 1.4; + margin-bottom: 2rem; +} + +.game-instructions { + font-size: clamp(0.8rem, 3vw, 1.2rem); + line-height: 1.6; + margin-bottom: 2rem; +} + +#gameCanvas { + max-width: 100%; + height: auto; + aspect-ratio: 1; +} + +#backgroundCanvas { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; +} + +#instructionsCanvas { + margin: 1rem auto; + display: block; + max-width: 100%; + height: auto; +} + +.button { + font-family: 'Press Start 2P', monospace; + background-color: transparent; + border: 2px solid #e0e0e0; + color: #e0e0e0; + padding: clamp(0.5rem, 2vw, 1rem) clamp(1rem, 4vw, 2rem); + cursor: pointer; + font-size: clamp(0.8rem, 2.5vw, 1rem); + transition: all 0.3s ease; +} + +.button:hover { + background-color: #e0e0e0; + color: #1a1a1a; +} + +.button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.hidden { + display: none !important; +} + +.footer { + text-align: center; + padding: 1rem; + font-size: clamp(0.4rem, 1.5vw, 0.6rem); + width: 100%; + box-sizing: border-box; +} + +.footer a { + color: #e0e0e0; + text-decoration: none; +} + +.footer a:hover { + text-decoration: underline; +} + +@media (max-width: 768px) { + .menu-content { + padding: 10px; + } + + .button { + width: 80%; + max-width: 300px; + } +} +.floating { + animation: float 6s cubic-bezier(0.37, 0, 0.63, 1) infinite; + filter: drop-shadow(0 0 15px rgba(224, 224, 224, 0.2)); + transform-origin: center; + perspective: 1000px; +} + +@keyframes float { + 0% { + transform: translateY(0) rotateX(0deg) scale(1); + filter: drop-shadow(0 0 15px rgba(224, 224, 224, 0.2)); + } + 25% { + transform: translateY(-10px) rotateX(2deg) scale(1.02); + filter: drop-shadow(0 0 20px rgba(224, 224, 224, 0.3)); + } + 50% { + transform: translateY(0) rotateX(0deg) scale(1); + filter: drop-shadow(0 0 15px rgba(224, 224, 224, 0.2)); + } + 75% { + transform: translateY(5px) rotateX(-1deg) scale(0.98); + filter: drop-shadow(0 0 10px rgba(224, 224, 224, 0.1)); + } + 100% { + transform: translateY(0) rotateX(0deg) scale(1); + filter: drop-shadow(0 0 15px rgba(224, 224, 224, 0.2)); + } +} +#patchNotesOverlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +#patchNotesOverlay.hidden { + display: none; +} + +.patch-notes-content { + background-color: #1a1a1a; + border: 2px solid #e0e0e0; + padding: 20px; + max-width: 600px; + width: 90%; + max-height: 80vh; + overflow-y: auto; + color: #e0e0e0; + font-family: 'Press Start 2P', monospace; +} + +.patch-notes-content h2 { + text-align: center; + margin-bottom: 20px; +} + +.patch-notes-list { + margin: 20px 0; +} + +.patch-notes-list ul { + list-style-type: none; + padding: 0; +} + +.patch-notes-list li { + margin: 10px 0; +} + +.patch-notes-content .button { + display: block; + margin: 20px auto 0; +} +.button { + font-family: 'Press Start 2P', monospace; + background-color: #1a1a1a; + border: 2px solid #e0e0e0; + color: #e0e0e0; + padding: 10px 20px; + cursor: pointer; + font-size: 16px; + width: 250px; + transition: all 0.3s ease; + display: inline-block; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.button:hover { + background-color: #e0e0e0; + color: #1a1a1a; +} + +.button:disabled { + opacity: 0.5; + cursor: not-allowed; +} \ No newline at end of file