GAME OVER
diff --git a/js/checking.js b/js/checking.js
index 800013709..c2ea05930 100644
--- a/js/checking.js
+++ b/js/checking.js
@@ -81,4 +81,6 @@ function consolidateBlocks(hex,side,index){
hex.texts.push(new Text(hex.x,hex.y,"+ "+adder.toString(),"bold Q ",deletedBlocks[0].color,fadeUpAndOut));
hex.lastColorScored = deletedBlocks[0].color;
score += adder;
+ window.progressCounter += adder; // accumulate for bar fill (200 per cycle)
+ updateProgressBar();
}
diff --git a/js/initialization.js b/js/initialization.js
index a22adf86f..669010e4e 100644
--- a/js/initialization.js
+++ b/js/initialization.js
@@ -120,7 +120,13 @@ function initialize(a) {
highscores = [];
}
}
+ // level progress saved in localStorage, default only level 1 unlocked
+ window.currentLevel = 1;
+ window.maxUnlockedLevel = parseInt(localStorage.getItem('maxUnlockedLevel')) || 1;
window.blocks = [];
+ // progress for bar (stays full green after 200 until '1' pressed; resets every 200)
+ window.progressCounter = 0;
+ window.barFull = false;
window.MainHex;
window.gdx = 0;
window.gdy = 0;
@@ -133,7 +139,7 @@ function initialize(a) {
window.importedHistory = undefined;
window.startTime = undefined;
window.gameState;
- setStartScreen();
+ showWelcome();
if (a != 1) {
window.canRestart = 1;
window.onblur = function(e) {
@@ -141,7 +147,7 @@ function initialize(a) {
pause();
}
};
- $('#startBtn').off();
+ $('#startBtn').off().hide();
if (settings.platform == 'mobile') {
$('#startBtn').on('touchstart', startBtnHandler);
} else {
@@ -176,6 +182,16 @@ function initialize(a) {
document.addEventListener("backbutton", handlePause, false);
document.addEventListener("menubutton", handlePause, false); //menu button on android
+ $('#welcomeStartBtn').off().on('click', function() {
+ showLevels();
+ });
+ $('#backToWelcomeBtn').off().on('click', function() {
+ showWelcome();
+ });
+ // complete screen buttons
+ $('#nextLevelBtn').off().on('click', nextLevel);
+ $('#replayLevelBtn').off().on('click', replayLevel);
+
setTimeout(function() {
if (settings.platform == "mobile") {
try {
@@ -290,3 +306,178 @@ function handleClickBefore(e) {
return;
}
}
+
+function getLevelTarget(level) {
+ return 250 * (level + 1);
+}
+
+function saveLevelProgress() {
+ localStorage.setItem('maxUnlockedLevel', maxUnlockedLevel);
+}
+
+function renderLevelsList() {
+ var list = $('#levelsList');
+ list.empty();
+ for(var i = 1; i <= 100; i++) {
+ var item = $('
' + i + '
');
+ if (i > maxUnlockedLevel) {
+ item.addClass('locked');
+ } else {
+ item.on('click', (function(lvl) {
+ return function() {
+ startLevel(lvl);
+ };
+ })(i));
+ }
+ list.append(item);
+ }
+ list.scrollTop(0);
+}
+
+function showWelcome() {
+ hideAllScreens();
+ $('#welcomeScreen').fadeIn(150, "linear");
+ $('#startBtn').hide();
+ init();
+ gameState = 0;
+ requestAnimFrame(animLoop);
+}
+
+function showLevels() {
+ hideAllScreens();
+ $('#levelsScreen').fadeIn(150, "linear");
+ renderLevelsList();
+ gameState = 0;
+ requestAnimFrame(animLoop);
+}
+
+function hideAllScreens() {
+ $('#welcomeScreen').fadeOut(150);
+ $('#levelsScreen').fadeOut(150);
+ $('#helpScreen').fadeOut(150);
+ $('#gameoverscreen').fadeOut(150);
+ $('#levelCompleteScreen').fadeOut(150);
+ $('#overlay').fadeOut(150);
+ $('#buttonCont').fadeOut(150);
+ $('.helpText').fadeOut(150);
+ updateLevelDisplay(false);
+}
+
+function startLevel(level) {
+ currentLevel = level;
+ hideAllScreens();
+ setTimeout(function() {
+ if (settings.platform == "mobile") {
+ try {
+ document.body.removeEventListener('touchstart', handleTapBefore, false);
+ } catch (e) {}
+ try {
+ document.body.removeEventListener('touchstart', handleTap, false);
+ } catch (e) {}
+ document.body.addEventListener('touchstart', handleTap, false);
+ } else {
+ try {
+ document.body.removeEventListener('mousedown', handleClickBefore, false);
+ } catch (e) {}
+ try {
+ document.body.removeEventListener('mousedown', handleClick, false);
+ } catch (e) {}
+ document.body.addEventListener('mousedown', handleClick, false);
+ }
+ }, 5);
+ if (!canRestart) return false;
+ // always full init for fresh level start (after complete or menu)
+ init(1);
+ checkVisualElements(0);
+ updateLevelDisplay(true);
+}
+
+function completeLevelIfQualified() {
+ var target = getLevelTarget(currentLevel);
+ if (score >= target) {
+ if (currentLevel + 1 > maxUnlockedLevel) {
+ maxUnlockedLevel = currentLevel + 1;
+ saveLevelProgress();
+ }
+ showLevelComplete();
+ }
+}
+
+function showLevelComplete() {
+ // stop game, clear save, dim canvas, show complete banner
+ gameState = 0;
+ clearSaveState();
+ importing = 0;
+ hideAllScreens();
+ var c = document.getElementById("canvas");
+ c.className = "blur";
+ $('#pauseBtn').hide();
+ $('#restartBtn').hide();
+ $('#levelCompleteScreen').fadeIn(150, "linear");
+ $('#completeLevelNum').text('LEVEL ' + currentLevel);
+ $('#completeScore').text('SCORE: ' + score);
+ // handlers set once in init
+}
+
+function updateLevelDisplay(show) {
+ if (show) {
+ $('#currentLevelNum').text(currentLevel);
+ $('#levelDisplay').show();
+ $('#progressContainer').show();
+ window.barFull = false;
+ window.progressCounter = 0;
+ window.currentProgress = 0;
+ updateProgressBar();
+ } else {
+ $('#levelDisplay').hide();
+ $('#progressContainer').hide();
+ }
+}
+
+function nextLevel() {
+ var next = currentLevel + 1;
+ if (next > 100) next = 100;
+ startLevel(next);
+}
+
+function replayLevel() {
+ startLevel(currentLevel);
+}
+
+function updateProgressBar() {
+ // progress fills/stays green after 200 until '1'; resets after clear
+ var mod = window.progressCounter % 200;
+ if (mod === 0 && window.progressCounter > 0) {
+ window.barFull = true;
+ } else if (!window.barFull) {
+ window.currentProgress = mod; // temp for calc
+ }
+ if (window.barFull) {
+ window.currentProgress = 200; // force stay full
+ } else {
+ window.currentProgress = mod;
+ }
+ // if full, stay 100% until cleared
+ var percent = (window.currentProgress / 200) * 100;
+ $('#progressBar').css('width', percent + '%');
+}
+
+function clearBlocksForSpace() {
+ // clear all falling/settled blocks to make space (called on '1' when bar full)
+ blocks = [];
+ for (var i = 0; i < MainHex.blocks.length; i++) {
+ MainHex.blocks[i] = [];
+ }
+ // bomb effect: boom text at center
+ if (MainHex) {
+ MainHex.texts.push(new Text(trueCanvas.width / 2, trueCanvas.height / 2 - 50, "💣 BOOM!", "bold 40px", "#e74c3c", fadeUpAndOut));
+ }
+ window.barFull = false;
+ window.progressCounter = 0;
+ window.currentProgress = 0;
+ updateProgressBar();
+ // slight delay for visual
+ setTimeout(function() {
+ if (gameState == 1) updateProgressBar();
+ }, 100);
+}
diff --git a/js/input.js b/js/input.js
index 190f66f1c..66dcc8ab1 100644
--- a/js/input.js
+++ b/js/input.js
@@ -103,8 +103,9 @@ function addKeyListeners() {
init(1);
}
if (gameState == 2) {
- init();
+ // after gameover, route to levels (follows full menu flow with progress etc)
$("#gameoverscreen").fadeOut();
+ showLevels();
}
if (gameState===0) {
resumeGame();
@@ -112,6 +113,16 @@ function addKeyListeners() {
}
});
+ // '1' clears blocks when progress bar full (every 200 score)
+ keypress.register_combo({
+ keys: "1",
+ on_keydown: function() {
+ if (gameState == 1 && window.currentProgress >= 200) {
+ clearBlocksForSpace();
+ }
+ }
+ });
+
$("#pauseBtn").on('touchstart mousedown', function() {
if (gameState != 1 && gameState != -1) {
return;
@@ -152,33 +163,37 @@ function addKeyListeners() {
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
$("#restart").on('touchstart', function() {
- init();
- canRestart = false;
+ // after gameover restart, route back to levels menu (follows welcome/levels/progress flow)
$("#gameoverscreen").fadeOut();
+ showLevels();
+ canRestart = false;
});
}
else {
$("#restart").on('mousedown', function() {
- init();
- canRestart = false;
+ // after gameover restart, route back to levels menu (follows welcome/levels/progress flow)
$("#gameoverscreen").fadeOut();
+ showLevels();
+ canRestart = false;
});
}
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
$("#restartBtn").on('touchstart', function() {
- init(1);
- canRestart = false;
+ // after gameover restart, route back to levels menu (follows welcome/levels/progress flow)
$("#gameoverscreen").fadeOut();
+ showLevels();
+ canRestart = false;
});
}
else {
$("#restartBtn").on('mousedown', function() {
- init(1);
- canRestart = false;
+ // after gameover restart, route back to levels menu (follows welcome/levels/progress flow)
$("#gameoverscreen").fadeOut();
+ showLevels();
+ canRestart = false;
});
diff --git a/js/main.js b/js/main.js
index 5d8aae365..477eea746 100644
--- a/js/main.js
+++ b/js/main.js
@@ -71,6 +71,7 @@ function resumeGame() {
}, 7000);
checkVisualElements(0);
+ updateLevelDisplay(true);
}
function checkVisualElements(arg) {
@@ -211,20 +212,8 @@ function exportHistory() {
}
function setStartScreen() {
- $('#startBtn').show();
- init();
- if (isStateSaved()) {
- importing = 0;
- } else {
- importing = 1;
- }
-
- $('#pauseBtn').hide();
- $('#restartBtn').hide();
- $('#startBtn').show();
-
- gameState = 0;
- requestAnimFrame(animLoop);
+ // now shows welcome page instead of original start button
+ showWelcome();
}
var spd = 1;
@@ -247,11 +236,16 @@ function animLoop() {
else{
MainHex.delay--;
}
+ // check after update if target reached; stop and show complete (before possible overflow)
+ if (score >= getLevelTarget(currentLevel)) {
+ completeLevelIfQualified();
+ }
}
lastTime = now;
- if (checkGameOver() && !importing) {
+ // skip gameover check if level completed this frame
+ if (gameState === 1 && checkGameOver() && !importing) {
var saveState = localStorage.getItem("saveState") || "{}";
saveState = JSONfn.parse(saveState);
gameState = 2;
diff --git a/js/view.js b/js/view.js
index 91a772f08..755e869e6 100644
--- a/js/view.js
+++ b/js/view.js
@@ -18,6 +18,10 @@ function renderText(x, y, fontSize, color, text, font) {
}
function drawScoreboard() {
+ // skip texts if any menu/complete screen visible
+ if ($('#welcomeScreen').is(':visible') || $('#levelsScreen').is(':visible') || $('#levelCompleteScreen').is(':visible')) {
+ return;
+ }
if (scoreOpacity < 1) {
scoreOpacity += 0.01;
textOpacity += 0.01;
@@ -159,6 +163,7 @@ function gameOverDisplay() {
$("#socialShare").fadeIn();
$("#restart").fadeIn();
set_score_pos();
+ updateLevelDisplay(false);
}
function updateHighScores (){
diff --git a/style/style.css b/style/style.css
index b57f23e85..a276d0197 100644
--- a/style/style.css
+++ b/style/style.css
@@ -431,6 +431,160 @@ body {
-ms-user-select:none;
user-select:none;
}
+
+.screen {
+ height:100%;
+ width:100%;
+ z-index:3001;
+ position:fixed;
+ top:0;
+ margin:0;
+ font-size:15px;
+ text-align:center;
+ display:none;
+ color:#232323;
+ background-color:rgba(236,240,241,1);
+}
+
+.welcomeContainer, .levelsContainer {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ -webkit-transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ width: 80%;
+ max-width: 400px;
+}
+
+#welcomeTitle {
+ font-size: 8vmin;
+ color: #2ecc71;
+ margin-bottom: 40px;
+ font-weight: bold;
+}
+
+.menuBtn {
+ background-color: #2c3e50;
+ color: #ecf0f1;
+ padding: 15px 30px;
+ font-size: 5vmin;
+ border-radius: 10px;
+ cursor: pointer;
+ margin: 10px auto;
+ width: 70%;
+ max-width: 300px;
+}
+
+#levelsHeader {
+ font-size: 6vmin;
+ color: #2c3e50;
+ margin-bottom: 20px;
+ font-weight: bold;
+}
+
+#levelsList {
+ height: 50vh;
+ overflow-y: auto;
+ background-color: #ecf0f1;
+ border: 2px solid #bdc3c7;
+ border-radius: 10px;
+ padding: 10px;
+ margin-bottom: 20px;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+ align-content: flex-start;
+}
+
+.level-item {
+ width: 30%;
+ margin: 5px;
+ padding: 15px 10px;
+ background-color: #2ecc71;
+ color: white;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 4vmin;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+
+.level-item.locked {
+ background-color: #95a5a6;
+ cursor: default;
+}
+
+.level-item.locked::after {
+ content: '🔒';
+ position: absolute;
+ font-size: 2vmin;
+ top: 5px;
+ right: 5px;
+}
+
+.level-item.completed {
+ background-color: #2ecc71;
+}
+
+#backToWelcomeBtn {
+ background-color: #2c3e50;
+ color: #ecf0f1;
+ padding: 15px 30px;
+ font-size: 5vmin;
+ border-radius: 10px;
+ cursor: pointer;
+ margin: 10px auto;
+ width: 70%;
+ max-width: 300px;
+}
+
+.completeContainer {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ -webkit-transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ width: 80%;
+ max-width: 400px;
+ text-align: center;
+}
+
+#completeTitle {
+ font-size: 7vmin;
+ color: #2ecc71;
+ margin-bottom: 20px;
+}
+
+#completeLevelNum {
+ font-size: 6vmin;
+ color: #2c3e50;
+ margin-bottom: 10px;
+}
+
+#completeScore {
+ font-size: 5vmin;
+ color: #2c3e50;
+ margin-bottom: 30px;
+}
+
+#nextLevelBtn, #replayLevelBtn {
+ background-color: #2c3e50;
+ color: #ecf0f1;
+ padding: 15px 30px;
+ font-size: 5vmin;
+ border-radius: 10px;
+ cursor: pointer;
+ margin: 10px auto;
+ width: 70%;
+ max-width: 300px;
+}
+
#afterhr {
margin:0;
padding:0;