/** * @license ================================================================================== * Lode Runner main program * * This program is a HTML5 remake of the Lode Runner games (APPLE II & C64 version). * * The program code base on CreateJS JavaScript libraries ! * http://www.createjs.com/ * * The AI algorithm reference book: * http://www.kingstone.com.tw/book/book_page.asp?kmcode=2014710650538 * http://www.amazon.co.jp/Lode-Runnerで学ぶ実践C言語-ビー・エヌ・エヌ企画部/dp/4893690116 * * Source Code: https://github.com/SimonHung/LodeRunner_TotalRecall * Web page: http://LodeRunnerWebGame.com * * by Simon Hung 06/20/2014, 06/13/2015, 09/28/2016 * ================================================================================== */ window.name = 'lodeRunnerParent'; //for world high score switch back 5/31/2015 var screenX1, screenY1; var canvasX, canvasY; var screenBorder; var tileW, tileH; //tile width & tile height var tileWScale, tileHScale; //tile width/height with scale var W2, W4; //W2: 1/2 tile-width, W4: 1/4 tile width var H2, H4; //H2: 1/2 tile-height, H4: 1/4 tile height var mainStageX, mainStageY; var scroeStageX, scoreStageY; var canvas; var mainStage, scoreStage; var loadingTxt; var gameState, lastGameState; var tileScale, xMove, yMove; var speedMode = [14, 18, 23, 29, 35]; //slow normal fast , slow down all speed 6/2/2016 var speedText = ["VERY SLOW", "SLOW", "NORMAL", "FAST", "VERY FAST"]; var speed = 2; //normal var demoSpeed = 35; var levelData = defaultLevelData(); //Classic Lode Runner var curLevel = 1, maxLevel = 1, passedLevel = 0; var playMode = PLAY_CLASSIC; var playData = 1; //classic lode runner var curTime = 0; //count from 0 to MAX_TIME_COUNT var backgroundColor = "#250535"; //background color var playerName = ""; var playerUId = ""; var curTheme = THEME_APPLE2; //support 2 themes: apple2 & C64 var dbName = "LodeRunner"; function init() { var screenSize = getScreenSize(); screenX1 = screenSize.x; screenY1 = screenSize.y; canvasReSize(); createStage(); setBackground(); initAutoDemoRnd(); //init auto demo random levels loadStoreVariable(); //load data from localStorage initMenuVariable(); //init menu variable getLastPlayInfo(); initDemoData(); //get demo data from server ////genUserLevel(MAX_EDIT_LEVEL); //for debug only getEditLevelInfo(); //load edit levels showLoadingPage(); //preload function } function loadStoreVariable() { playerName = getPlayerName(); if( ((playerUid = getUid()) == "" || playerUid.length != 32) && typeof(uId) != "undefined" ) { playerUid = uId; //uId variable in lodeRunner.wData.jss setUid(playerUid); } curTheme = getThemeMode(); getThemeColor(); getRepeatAction(); if(getGamepadMode()) gamepadEnable(); } function canvasReSize() { var iconSizeX; for (var scale = MAX_SCALE*100; scale >= MIN_SCALE*100; scale -= 5) { tileScale = scale / 100; canvasX = BASE_SCREEN_X * tileScale; canvasY = BASE_SCREEN_Y * tileScale; //if (canvasX <= screenX1 && canvasY <= screenY1 || tileScale <= MIN_SCALE) break; iconSizeX = BASE_ICON_X * 2 * tileScale; if( (canvasX+iconSizeX) <= screenX1 && canvasY <= screenY1 || tileScale <= MIN_SCALE) break; } debug("SCALE=" + tileScale); //debug("screenX1 = " + screenX1 + " screenY1 = " + screenY1 + "scale = " + scale); screenBorder = (screenX1 - (canvasX+iconSizeX))/2; if(screenBorder > ICON_BORDER*2) screenBorder = ICON_BORDER*2; else if (screenBorder < 0) screenBorder = 0; screenBorder = (screenBorder * tileScale) | 0; canvas = document.getElementById('canvas'); canvas.width = canvasX; canvas.height = canvasY; //Set canvas top left position var left = ((screenX1 - canvasX)/2|0), top = ((screenY1 - canvasY)/2|0); canvas.style.left = (left>0?left:0) + "px"; canvas.style.top = (top>0?top:0) + "px"; canvas.style.position = "absolute"; canvas.style.cursor = "default"; tileW = BASE_TILE_X; //tileW and tileH for detection so don't change scale tileH = BASE_TILE_Y; tileWScale = BASE_TILE_X * tileScale; tileHScale = BASE_TILE_Y * tileScale; W2 = (tileW/2|0); //20, 15, 10, H2 = (tileH/2|0); //22, 16, 11 W4 = (tileW/4|0); //10, 7, 5, H4 = (tileH/4|0); //11, 8, 5, } function createStage() { mainStage = new createjs.Stage(canvas); loadingTxt = new createjs.Text(" ", "36px Arial", "#FF0000"); loadingTxt.x = (canvas.width - loadingTxt.getBounds().width) / 2 | 0; loadingTxt.y = (canvas.height - loadingTxt.getBounds().height) / 2 | 0; mainStage.addChild(loadingTxt); mainStage.update(); } function setBackground() { //set background color var background = new createjs.Shape(); background.graphics.beginFill("#000000").drawRect(0, 0, canvas.width, canvas.height); mainStage.addChild(background); document.body.style.background = backgroundColor; } function showCoverPage() { menuIconDisable(1); clearIdleDemoTimer(); mainStage.removeAllChildren(); mainStage.addChild(titleBackground); //colorful background mainStage.addChild(coverBitmap); mainStage.addChild(signetBitmap); mainStage.addChild(remakeBitmap); mainStage.update(); waitIdleDemo(3000); } var idleTimer=null, startIdleTime; function clearIdleDemoTimer() { if(idleTimer) clearInterval(idleTimer); idleTimer = null; } function waitIdleDemo(maxIdleTime) { startIdleTime = new Date(); idleTimer = setInterval(function(){ checkIdleTime(maxIdleTime);}, 200); anyKeyStopDemo(); } function anyKeyStopDemo() { document.onkeydown = anyKeyDown; //any key press enableStageClickEvent(); } function stopDemoAndPlay() { var showStartMsg = 1; if(changingLevel) return false; clearIdleDemoTimer(); disableStageClickEvent(); soundStop(soundFall); stopAllSpriteObj(); resumeAudioContext(); //05/15/2018, chrome 66 default mute autoplay, need resume it if(playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) selectIconObj.disable(1); if(playMode == PLAY_DEMO_ONCE) showStartMsg = 0; ////genUserLevel(MAX_EDIT_LEVEL); //for debug only ////getEditLevelInfo(); //load edit levels selectGame(showStartMsg); } var stageClickListener = null, stagePressListener = null; function enableStageClickEvent() { disableStageClickEvent(); //createjs.Touch.enable(mainStage); stageClickListener = mainStage.on("click", function(evt) { stopDemoAndPlay(); }); //stagePressListener = mainStage.on("press", function(evt) { stopDemoAndPlay(); }); } function disableStageClickEvent() { var rc = 0; if(stageClickListener) { rc = 1; mainStage.off("click", stageClickListener); } //if(stagePressListener) { rc = 1; mainStage.off("press", stagePressListener); } stageClickListener = stagePressListener = null; //createjs.Touch.disable(mainStage); return rc; } function noKeyDown() { return false; } function anyKeyDown() { stopDemoAndPlay(); } function checkIdleTime(maxIdleTime) { var idleTime = (new Date() - startIdleTime); if(idleTime > maxIdleTime){ //start demo clearIdleDemoTimer(); playMode = PLAY_AUTO; anyKeyStopDemo(); startGame(); } } //========================== // Get playMode & playData //========================== function getLastPlayInfo() { var infoJSON = getStorage(STORAGE_LASTPLAY_MODE); playMode = PLAY_NONE; if(infoJSON) { var infoObj = JSON.parse(infoJSON); playMode = infoObj.m; //mode= 1: classic, 2:time playData = infoObj.d; //1: classic lode runner, 2: professional lode runner, 3: lode runner 3 .... } if( (playMode != PLAY_CLASSIC && playMode != PLAY_MODERN) || (playData < 1 || (playData > maxPlayId && playData != PLAY_DATA_USERDEF) ) ){ playMode = PLAY_CLASSIC; playData = 1; //classic lode runner } } function selectGame(showDataMsg) { getLastPlayInfo(); playData2GameVersionMenuId(); document.onkeydown = handleKeyDown; document.onkeyup = handleKeyUp; initShowDataMsg(showDataMsg); startGame(); } var gameTicker = null; var changingLevel = 0; function startPlayTicker() { stopPlayTicker(); //createjs.Ticker.timingMode = createjs.Ticker.RAF; if(playMode == PLAY_AUTO || playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) { createjs.Ticker.setFPS(demoSpeed); //06/12/2014 } else { createjs.Ticker.setFPS(speedMode[speed]); } gameTicker = createjs.Ticker.on("tick", mainTick); } function stopPlayTicker() { if(gameTicker) { createjs.Ticker.off("tick", gameTicker); gameTicker = null; } } function startGame(noCycle) { var levelMap; gameState = GAME_WAITING; startPlayTicker(); changingLevel = 1; curAiVersion = AI_VERSION; //07/04/2014 initHotKeyVariable(); //07/09/2014 switch(playMode) { case PLAY_CLASSIC: getClassicInfo(); levelMap = levelData[curLevel-1]; if(curLevel >= levelData.length && (passedLevel+1) >= levelData.length) { loadEndingMusic(); //6/15/2015, music prepare for winner } break; case PLAY_MODERN: getModernInfo(); levelMap = levelData[curLevel-1]; break; case PLAY_TEST: levelMap = getTestLevelMap(); break; case PLAY_DEMO: getDemoInfo(); levelMap = levelData[curLevel-1]; break; case PLAY_DEMO_ONCE: getDemoOnceInfo(); levelMap = levelData[curLevel-1]; break; case PLAY_AUTO: getAutoDemoLevel(1); levelMap = levelData[curLevel-1]; break; } showLevel(levelMap); if(noCycle) { beginPlay(); } else { addCycScreen(); setTimeout(function() { openingScreen(cycDiff*2);}, 5); } } var maxTileX = NO_OF_TILES_X - 1, maxTileY = NO_OF_TILES_Y - 1; var runner = null, guard= []; var map; //[x][y] = { base: base map, act : active map, state:, bitmap: } var guardCount, goldCount, goldComplete; function initVariable() { guard = []; keyAction = holeObj.action = ACT_STOP; goldCount = guardCount = goldComplete = 0; runner = null; dspTrapTile = 0; initRnd(); initModernVariable(); initGuardVariable(); initInfoVariable(); initCycVariable(); initStillFrameVariable(); //05/01/2015 replace sprite with still frame image setSpeedByAiVersion(); //07/04/2014 debug("curAiVersion = " + curAiVersion); } function buildLevelMap(levelMap) { var index = 0; var mapGuardCount = 0; //Number of original guards //(1) create empty map[x][y] array; map = []; for(var x = 0; x < NO_OF_TILES_X; x++) { map[x] = []; for(var y = 0; y < NO_OF_TILES_Y; y++) { map[x][y] = {}; if(levelMap.charAt(index++) == '0') mapGuardCount++; } } //(2) draw map index = 0; for(var y = 0; y < NO_OF_TILES_Y; y++) { for(var x = 0; x < NO_OF_TILES_X; x++) { var id = levelMap.charAt(index++); var curTile; switch(id) { default: case ' ': //empty map[x][y].base = EMPTY_T; map[x][y].act = EMPTY_T; map[x][y].bitmap = null; continue; case '#': //Normal Brick map[x][y].base = BLOCK_T; map[x][y].act = BLOCK_T; curTile = map[x][y].bitmap = getThemeBitmap("brick"); break; case '@': //Solid Brick map[x][y].base = SOLID_T; map[x][y].act = SOLID_T; curTile = map[x][y].bitmap = getThemeBitmap("solid"); break; case 'H': //Ladder map[x][y].base =LADDR_T; map[x][y].act =LADDR_T; curTile = map[x][y].bitmap = getThemeBitmap("ladder"); break; case '-': //Line of rope map[x][y].base = BAR_T; map[x][y].act = BAR_T; curTile = map[x][y].bitmap = getThemeBitmap("rope"); break; case 'X': //False brick map[x][y].base = TRAP_T; //behavior same as empty map[x][y].act = TRAP_T; curTile = map[x][y].bitmap = getThemeBitmap("brick"); break; case 'S': //Ladder appears at end of level map[x][y].base = HLADR_T; //behavior same as empty before end of level map[x][y].act = EMPTY_T; //behavior same as empty before end of level curTile = map[x][y].bitmap = getThemeBitmap("ladder"); curTile.set({alpha:0}); //hide the laddr break; case '$': //Gold chest map[x][y].base = GOLD_T; //keep gold on base map map[x][y].act = EMPTY_T; curTile = map[x][y].bitmap = getThemeBitmap("gold"); goldCount++; break; case '0': //Guard map[x][y].base = EMPTY_T; map[x][y].act = GUARD_T; map[x][y].bitmap = null; if(--mapGuardCount >= maxGuard) { map[x][y].act = EMPTY_T; continue; //too many guards, set this tile as empty } curTile = new createjs.Sprite(guardData, "runLeft"); guard[guardCount] = { sprite: curTile, pos: { x:x, y:y, xOffset:0, yOffset:0}, action: ACT_STOP, shape: "runLeft", lastLeftRight: "ACT_LEFT", hasGold: 0 }; guardCount++; curTile.stop(); break; case '&': //Player map[x][y].base = EMPTY_T; map[x][y].act = RUNNER_T; map[x][y].bitmap = null; if(runner != null) { map[x][y].act = EMPTY_T; continue; //too many runner, set this tile as empty } runner = {}; curTile = runner.sprite = new createjs.Sprite(runnerData, "runRight"); runner.pos = { x:x, y:y, xOffset:0, yOffset:0}; runner.action = ACT_UNKNOWN; runner.shape = "runRight"; runner.lastLeftRight = "ACT_RIGHT"; curTile.stop(); break; } curTile.setTransform(x * tileWScale, y * tileHScale, tileScale, tileScale); //x,y, scaleX, scaleY mainStage.addChild(curTile); } } assert(mapGuardCount == 0, "Error: mapCuardCount design error !" ); moveSprite2Top(); } function moveSprite2Top() { //move guard to top (z index) for(var i = 0; i < guardCount; i++) { moveChild2Top(mainStage, guard[i].sprite); } if(runner == null) { error("Without runner ???"); } else { //move runner to top (z index) moveChild2Top(mainStage, runner.sprite); } //move fill hole object to top moveFillHoleObj2Top(); //move debug text to top moveChild2Top(mainStage, loadingTxt); //for debug } function buildGroundInfo() { drawGround(); drawInfo(); } var groundTile; function drawGround() { groundTile = []; for(var x = 0; x < NO_OF_TILES_X; x++) { groundTile[x] = getThemeBitmap("ground"); groundTile[x].setTransform(x * tileWScale, NO_OF_TILES_Y * tileHScale, tileScale, tileScale); mainStage.addChild(groundTile[x]); } } var runnerLife = RUNNER_LIFE; var curScore = 0; var curGetGold = 0, curGuardDeadNo = 0; //for modern mode var sometimePlayInGodMode = 0; //if sometime play in god mode then don't save to hi-scoe, 12/23/2014 var infoY; var scoreTxt, scoreTile, lifeTxt, lifeTile, levelTxt, levelTile, demoTxt; var goldTxt, goldTile, guardTxt, guardTile, timeTxt, timeTile; //============================= // initial modern mode variable //============================= function initModernVariable() { //curTime = MAX_TIME_COUNT; curTime = curGetGold = curGuardDeadNo = 0; } function initInfoVariable() { infoY = (NO_OF_TILES_Y * BASE_TILE_Y + GROUND_TILE_Y) * tileScale; scoreTxt = []; scoreTile = []; lifeTxt = []; lifeTile = []; demoTxt = []; levelTxt = []; levelTile = []; goldTxt = []; goldTile = []; guardTxt = []; guardTile = []; timeTxt = []; timeTile = []; } function drawInfo() { if(playMode == PLAY_CLASSIC || playMode == PLAY_AUTO || playMode == PLAY_DEMO) { //SCORE drawScoreTxt(); drawScore(0); if(playMode == PLAY_DEMO) { drawDemoTxt(); } else { //MEN drawLifeTxt(); drawLife(); } } else { //GOLD drawGoldTxt(); drawGold(0); //GUARD drawGuardTxt(); drawGuard(0); //TIME drawTimeTxt(); drawTime(0); } //LEVEL drawLevelTxt(); drawLevel(); } //for classic & auto demo mode function drawScoreTxt() { scoreTxt = drawText(0, infoY, "SCORE", mainStage); } function drawLifeTxt() { lifeTxt = drawText(13*tileWScale, infoY, "MEN", mainStage); } function drawLevelTxt() { var xOffset = 20; levelTxt = drawText(xOffset*tileWScale, infoY, "LEVEL", mainStage); } //for demo mode function drawDemoTxt() { demoTxt = drawText(14*tileWScale, infoY, "DEMO", mainStage); } //for time & edit mode function drawGoldTxt() { goldTxt = drawText(0*tileWScale, infoY, "@", mainStage); } function drawGuardTxt() { guardTxt = drawText((5+2/3)*tileWScale, infoY, "#", mainStage); } function drawTimeTxt() { timeTxt = drawText((11+1/3)*tileWScale, infoY, "TIME", mainStage); } // draw score number function drawScore(addScore) { var digitNo; curScore += addScore; for(var i = 0; i < scoreTile.length; i++) mainStage.removeChild(scoreTile[i]); scoreTile = drawText(5*tileWScale, infoY, ("000000"+curScore).slice(-7), mainStage); } function drawLife() { for(var i = 0; i < lifeTile.length; i++) mainStage.removeChild(lifeTile[i]); lifeTile = drawText(16*tileWScale, infoY, ("00"+runnerLife).slice(-3), mainStage); } function drawLevel() { for(var i = 0; i < levelTile.length; i++) mainStage.removeChild(levelTile[i]); switch(playMode) { case PLAY_AUTO: levelTile = drawText(25*tileWScale, infoY, ("00"+demoLevel).slice(-3), mainStage); break; case PLAY_CLASSIC: default: levelTile = drawText(25*tileWScale, infoY, ("00"+curLevel).slice(-3), mainStage); break; } } function drawGold(addGold) { curGetGold += addGold; for(var i = 0; i < goldTile.length; i++) mainStage.removeChild(goldTile[i]); goldTile = drawText(1*tileWScale, infoY, ("00"+curGetGold).slice(-3), mainStage); } function drawGuard(addGuard) { curGuardDeadNo += addGuard; if(curGuardDeadNo > 100) curGuardDeadNo = 100; for(var i = 0; i < guardTile.length; i++) mainStage.removeChild(guardTile[i]); guardTile = drawText((6+2/3)*tileWScale, infoY, ("00"+curGuardDeadNo).slice(-3), mainStage); } function countTime(addTime) { if(curTime >= MAX_TIME_COUNT) return; if(addTime) curTime++; if(curTime > MAX_TIME_COUNT) { curTime = MAX_TIME_COUNT;} } function drawTime(addTime) { countTime(addTime); for(var i = 0; i < timeTile.length; i++) mainStage.removeChild(timeTile[i]); timeTile = drawText((15+1/3)*tileWScale, infoY, ("00"+curTime).slice(-3), mainStage); } function setGroundInfoOrder() { var i; for(i = 0; i < groundTile.length; i++) moveChild2Top(mainStage, groundTile[i]); if(playMode == PLAY_CLASSIC || playMode == PLAY_AUTO || playMode == PLAY_DEMO) { for(i = 0; i < scoreTxt.length; i++) moveChild2Top(mainStage, scoreTxt[i]); for(i = 0; i < scoreTile.length; i++) moveChild2Top(mainStage, scoreTile[i]); if(playMode == PLAY_DEMO) { for(i = 0; i < demoTxt.length; i++) moveChild2Top(mainStage, demoTxt[i]); } else { for(i = 0; i < lifeTxt.length; i++) moveChild2Top(mainStage, lifeTxt[i]); for(i = 0; i < lifeTile.length; i++) moveChild2Top(mainStage, lifeTile[i]); } } else { //PLAY_MODERN, PLAY_DEMO_ONCE for(i = 0; i < goldTxt.length; i++) moveChild2Top(mainStage, goldTxt[i]); for(i = 0; i < goldTile.length; i++) moveChild2Top(mainStage, goldTile[i]); for(i = 0; i < guardTxt.length; i++) moveChild2Top(mainStage, guardTxt[i]); for(i = 0; i < guardTile.length; i++) moveChild2Top(mainStage, guardTile[i]); for(i = 0; i < timeTxt.length; i++) moveChild2Top(mainStage, timeTxt[i]); for(i = 0; i < timeTile.length; i++) moveChild2Top(mainStage, timeTile[i]); } for(i = 0; i < levelTxt.length; i++) moveChild2Top(mainStage, levelTxt[i]); for(i = 0; i < levelTile.length; i++) moveChild2Top(mainStage, levelTile[i]); } function drawText(x, y, str, parentObj, numberType) { var text = str.toUpperCase(); var textTile = []; if(typeof numberType == "undefined") numberType = "N"; for(var i = 0; i < text.length; i++) { var code = text.charCodeAt(i); switch(true) { case (code >=48 && code <=57): //N0 ~ N9 or D0 ~ D9 textTile[i] = new createjs.Sprite(textData, numberType+String.fromCharCode(code)); break; case (code >=65 && code <= 90): textTile[i] = new createjs.Sprite(textData, String.fromCharCode(code)); break; case (code == 46): //'.' textTile[i] = new createjs.Sprite(textData, "DOT"); break; case (code == 60): //'<' textTile[i] = new createjs.Sprite(textData, "LT"); break; case (code == 62): //'>' textTile[i] = new createjs.Sprite(textData, "GT"); break; case (code == 45): //'-' textTile[i] = new createjs.Sprite(textData, "DASH"); break; case (code == 58): //':' textTile[i] = new createjs.Sprite(textData, "COLON"); break; case (code == 95): //'_' textTile[i] = new createjs.Sprite(textData, "UNDERLINE"); break; case (code == 35): //'#': guard dead in trap hole textTile[i] = new createjs.Sprite(textData, String.fromCharCode(code)); break; case (code == 64): //'@': gold textTile[i] = new createjs.Sprite(textData, String.fromCharCode(code)); break; default: //space textTile[i] = new createjs.Sprite(textData, "SPACE"); break; } textTile[i].setTransform(x + i*tileWScale, y, tileScale, tileScale).stop(); parentObj.addChild(textTile[i]); } return textTile; } var playTickTimer = 0; function playGame(deltaS) { if(goldComplete && runner.pos.y == 0 && runner.pos.yOffset == 0) { gameState = GAME_FINISH; return; } if(++playTickTimer >= TICK_COUNT_PER_TIME) { if(playMode != PLAY_CLASSIC && playMode != PLAY_AUTO && playMode != PLAY_DEMO) drawTime(1); else countTime(1); playTickTimer = 0; } if(playMode == PLAY_AUTO || playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) playDemo(); if(recordMode) processRecordKey(); if(!isDigging()) moveRunner(); else processDigHole(); if(gameState != GAME_RUNNER_DEAD) moveGuard(); if(curAiVersion >= 3) { processGuardShake(); processFillHole(); processReborn(); } } //*********************** // BEGIN show new level * //*********************** function showLevel(levelMap) { mainStage.removeAllChildren(); loadingTxt.text = ""; //loadingTxt.text = tileScale; //for debug mainStage.addChild(loadingTxt); //for debug initVariable(); setBackground(); buildLevelMap(levelMap); buildGroundInfo(); } var tipsText = null, tipsRect = null; var tipsText1 = null, tipsRect1 = null; function showTipsText(text, time, text1) { var x, y, width, height; if(tipsText != null) { mainStage.removeChild(tipsText); } if(tipsRect != null) { mainStage.removeChild(tipsRect); } if(tipsText1 != null) { mainStage.removeChild(tipsText1); tipsText1 = null; } if(tipsRect1 != null) { mainStage.removeChild(tipsRect1); tipsRect1 = null; } tipsText = new createjs.Text("test", "bold " + (48*tileScale) + "px Helvetica", "#ee1122"); tipsText.text = text; tipsText.set({alpha:1}); if(text.length) { width = tipsText.getBounds().width; height = tipsText.getBounds().height; } else { width = height = 0; } x = tipsText.x = (canvas.width - width) / 2 | 0; y = tipsText.y = (NO_OF_TILES_Y*tileHScale - height) / 2 | 0; tipsText.shadow = new createjs.Shadow("white", 2, 2, 1); tipsRect = new createjs.Shape(); tipsRect.graphics.beginFill("#020722"); tipsRect.graphics.drawRect(-1, -1,width+2, height+2); tipsRect.setTransform(x, y).set({alpha:0.8}); mainStage.addChild(tipsRect); mainStage.addChild(tipsText); if(time){ createjs.Tween.get(tipsRect,{override:true}).set({alpha:0.8}).to({alpha:0}, time); createjs.Tween.get(tipsText,{override:true}).set({alpha:1}).to({alpha:0}, time); } if(text1 != null) { //second tips tipsText1 = new createjs.Text("test", "bold " + (48*tileScale) + "px Helvetica", "#ee1122"); tipsText1.text = text1; tipsText1.set({alpha:1}); if(text1.length) { width = tipsText1.getBounds().width; height = tipsText1.getBounds().height; } else { width = height = 0; } x = tipsText1.x = (canvas.width - width) / 2 | 0; y = tipsText1.y = (NO_OF_TILES_Y*tileHScale - height) / 2 + tipsText.getBounds().height*2 | 0; tipsText1.shadow = new createjs.Shadow("white", 2, 2, 1); tipsRect1 = new createjs.Shape(); tipsRect1.graphics.beginFill("#020722"); tipsRect1.graphics.drawRect(-1, -1,width+2, height+2); tipsRect1.setTransform(x, y).set({alpha:0.8}); mainStage.addChild(tipsRect1); mainStage.addChild(tipsText1); if(time){ createjs.Tween.get(tipsRect1,{override:true}).set({alpha:0.8}).to({alpha:0}, time); createjs.Tween.get(tipsText1,{override:true}).set({alpha:1}).to({alpha:0}, time); } } mainStage.update(); } var dspTrapTile = 0; function toggleTrapTile() { dspTrapTile ^= 1; for(var y = 0; y < NO_OF_TILES_Y; y++) { for(var x = 0; x < NO_OF_TILES_X; x++) { if( map[x][y].base == TRAP_T) { if(dspTrapTile) { map[x][y].bitmap.set({alpha:0.5}); //show trap tile } else { map[x][y].bitmap.set({alpha:1}); //hide trap tile } } } } if(dspTrapTile) { showTipsText("SHOW TRAP TILE", 2000); } else { showTipsText("HIDE TRAP TILE", 2000); } } function startAllSpriteObj() { //(1) runner stop if(runner && !runner.paused) runner.sprite.play(); //(2) guard stop for(var i = 0; i < guardCount; i++) { if(!guard[i].paused) guard[i].sprite.play(); } if(curAiVersion < 3) { //for sprite only //(3) fill hole stop for(var i = 0; i < fillHoleObj.length; i++) fillHoleObj[i].play(); //(4) hole digging if(holeObj.action == ACT_DIGGING) holeObj.sprite.play(); } } function stopAllSpriteObj() { //(1) runner stop if(runner) { runner.paused = runner.sprite.paused; runner.sprite.stop(); } //(2) guard stop for(var i = 0; i < guardCount; i++) { guard[i].paused = guard[i].sprite.paused; guard[i].sprite.stop(); } if(curAiVersion < 3) { //for sprite only //(3) fill hole stop for(var i = 0; i < fillHoleObj.length; i++) fillHoleObj[i].stop(); //(4) hole digging if(holeObj.action == ACT_DIGGING) holeObj.sprite.stop(); } } function gameOverAnimation() { var gameOverImage = getThemeBitmap("over"); var bound = gameOverImage.getBounds(); var x = (NO_OF_TILES_X*tileWScale)/2|0; var y = (NO_OF_TILES_Y*tileHScale)/2|0; var regX = (bound.width)/2|0; var regY = (bound.height)/2|0; var rectBlock = new createjs.Shape(); rectBlock.graphics.beginFill("black"); rectBlock.graphics.drawRect(-1, -1,bound.width+2, bound.height+2); rectBlock.setTransform(x, y, tileScale, tileScale).set({regX:regX, regY:regY}); gameOverImage.setTransform(x, y, tileScale, tileScale).set({regX:regX, regY:regY}); createjs.Tween.get(gameOverImage) .to({scaleY:-tileScale},80) .to({scaleY:tileScale},80) .to({scaleY:-tileScale},100) .to({scaleY:tileScale},100) .to({scaleY:-tileScale},150) .to({scaleY:tileScale},150) .to({scaleY:-tileScale},300) .to({scaleY:tileScale},300) .to({scaleY:-tileScale},450) .to({scaleY:tileScale},450) .to({scaleY:-tileScale},750) .to({scaleY:tileScale},750) .wait(1500) .call(function(){ if(gameState == GAME_OVER_ANIMATION) gameState = GAME_OVER;}); /* BUG: while in PLAY_AUTO MODE and demo dead into the gameOverAnimation() At this time if player press any key or click mouse will cause gameState changed to "GAME_START" and start play the game, and after the TWEEN function into final "call( function() { gameState = GAME_OVER;})" will cause program orderless and want player record hiscore table BUG FIXED: 9/15/2015 if TWEEN complete and into call() func need check gameState MUST = "GAME_OVER_ANIMATION" ==> call(function(){ if(gameState == GAME_OVER_ANIMATION) gameState = GAME_OVER;}); */ mainStage.addChild(rectBlock); mainStage.addChild(gameOverImage); //stopAllSpriteObj(); } var cycScreen, cycMaxRadius, cycDiff, cycX, cycY function initCycVariable() { cycX = NO_OF_TILES_X * tileWScale/2; cycY = NO_OF_TILES_Y * tileHScale/2; cycMaxRadius = Math.sqrt(cycX*cycX+cycY*cycY)|0+1; cycDiff = (cycMaxRadius/CLOSE_SCREEN_SPEED)|0; } function addCycScreen() { cycScreen = new createjs.Shape(); mainStage.addChild(cycScreen); setGroundInfoOrder(); } function removeCycScreen() { mainStage.removeChild(cycScreen); } function newLevel(r) { changingLevel = 1; //menuIconDisable(0); addCycScreen(); //close screen setTimeout(function() { closingScreen(cycMaxRadius);}, 100); } function closingScreen(r) { removeCycScreen(); addCycScreen(); cycScreen.graphics.beginFill("black").arc( cycX, cycY, r, 0, 2*Math.PI, true) cycScreen.graphics.arc( cycX, cycY, cycMaxRadius, 0, 2*Math.PI, false); mainStage.update(); if(r > 0) { r -= cycDiff; if(r < cycDiff*2) r = 0; setTimeout(function() { closingScreen(r);}, 5); } else { var levelMap; curAiVersion = AI_VERSION; //07/04/2014 initHotKeyVariable(); //07/09/2014 if(playMode == PLAY_AUTO) getAutoDemoLevel(0); if(playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) getNextDemoLevel(); if(playMode == PLAY_TEST) { levelMap = getTestLevelMap(); } else { levelMap = levelData[curLevel-1]; } showLevel(levelMap); addCycScreen(); setTimeout(function() { openingScreen(cycDiff*2);}, 5); } } function menuIconEnable() { mainMenuIconObj.enable(); if(playMode == PLAY_MODERN || playMode == PLAY_DEMO) { selectIconObj.enable(); } if(playMode == PLAY_MODERN) demoIconObj.enable(); if(playMode != PLAY_EDIT) { soundIconObj.enable(); soundIconObj.updateSoundImage(); repeatActionIconObj.enable(); themeColorObj.enable(); } else { if(!editInNarrowScreen) themeColorObj.enable(); } infoIconObj.enable(); helpIconObj.enable(); themeIconObj.enable(); } function menuIconDisable(hidden) { mainMenuIconObj.disable(hidden); if(playMode == PLAY_MODERN) { selectIconObj.disable(hidden); } demoIconObj.disable(hidden); soundIconObj.disable(hidden); infoIconObj.disable(hidden); helpIconObj.disable(hidden); repeatActionIconObj.disable(hidden); themeIconObj.disable(hidden); themeColorObj.disable(hidden); } var showStartTipsMsg = 1; function initShowDataMsg(showMsg) { if(typeof showMsg == "undefined") showMsg = 1; showStartTipsMsg = showMsg; } function showDataMsg() { if(showStartTipsMsg) { var nameTxt = null; var nameTxt1 = null; nameTxt = playDataToTitleName(playData); switch(playMode) { case PLAY_EDIT: nameTxt1 = "Edit Mode"; break; case PLAY_TEST: nameTxt1 = "Test Mode"; break; case PLAY_DEMO: nameTxt1 = "Demo Mode"; break; case PLAY_CLASSIC: if(playData != PLAY_DATA_USERDEF) nameTxt1 = "Challenge Mode"; else nameTxt1 = "Play Mode"; break; case PLAY_MODERN: if(playData != PLAY_DATA_USERDEF) nameTxt1 = "Training Mode"; else nameTxt1 = "Play Mode"; break; } if(nameTxt) showTipsMsg(nameTxt, mainStage, tileScale, nameTxt1); showStartTipsMsg = 0; } } function showHelpMenu() { if(firstPlay) { helpObj.showHelp(0, initForPlay, tileScale, null); setFirstPlayInfo(); } else { initForPlay(); } } function initForPlay() { menuIconEnable(); showDataMsg(); } function openingScreen(r) { removeCycScreen(); addCycScreen(); cycScreen.graphics.beginFill("black").arc( cycX, cycY, r, 0, 2*Math.PI, true) cycScreen.graphics.arc( cycX, cycY, cycMaxRadius, 0, 2*Math.PI, false); mainStage.update(); if(r < cycMaxRadius) { r += cycDiff; if(r > cycMaxRadius) r = cycMaxRadius; setTimeout(function() { openingScreen(r);}, 5); } else { removeCycScreen(); beginPlay(); } } function beginPlay() { gameState = GAME_START; keyAction = ACT_STOP; runner.sprite.gotoAndPlay(); changingLevel = 0; if(recordMode) initRecordVariable(); if(playMode == PLAY_AUTO || playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) { initPlayDemo(); if(playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) initForPlay(); } else { if(playerName == "" || playerName.length <= 1) { inputPlayerName(mainStage, showHelpMenu); } else { showHelpMenu(); } if(playMode != PLAY_TEST && playMode != PLAY_EDIT) { enableAutoDemoTimer(); //while start game and idle too long will into demo mode } } } function incLevel(incValue, passed) { var wrap = 0; curLevel += incValue; while (curLevel > levelData.length) { curLevel-= levelData.length; wrap = 1; } if(playMode == PLAY_CLASSIC) setClassicInfo(passed); if(playMode == PLAY_MODERN) setModernInfo(); return wrap; } function decLevel(decValue) { curLevel -= decValue while (curLevel <= 0) curLevel += levelData.length; if(playMode == PLAY_CLASSIC) setClassicInfo(0); if(playMode == PLAY_MODERN) setModernInfo(); } function updateModernScoreInfo() { var lastHiScore = modernScoreInfo[curLevel-1]; var levelScore = ((MAX_TIME_COUNT - curTime) + curGetGold + curGuardDeadNo) * SCORE_VALUE_PER_POINT; if(lastHiScore < levelScore) { modernScoreInfo[curLevel-1] = levelScore; setModernScoreInfo(); } if(lastHiScore < 0) lastHiScore = 0; return lastHiScore; } function gameFinishActiveNew(level) { curLevel = level; setModernInfo(); startGame(); } function gameFinishCloseIcon() { startGame(); } function gameFinishCallback(selectMode) { switch(selectMode) { case 0: //return (same level) gameState = GAME_NEW_LEVEL; break; case 1: //menu selection //incLevel(1); activeSelectMenu(gameFinishActiveNew, gameFinishCloseIcon); break; case 2: //new level incLevel(1,0); gameState = GAME_NEW_LEVEL; break; default: debug("design error !"); break; } } function gameFinishTestModeCallback() { back2EditMode(1); } var lastScoreTime, scoreDuration; var scoreIncValue, finalScore; function mainTick(event) { var deltaS = event.delta/1000; var scoreInfo; switch(gameState) { case GAME_START: countAutoDemoTimer(); if(keyAction != ACT_STOP && keyAction != ACT_UNKNOWN) { disableAutoDemoTimer(); gamepadClearId(); gameState = GAME_RUNNING; if(playMode == PLAY_MODERN) demoIconObj.disable(1); playTickTimer = 0; //modern mode time counter if(goldCount <= 0) showHideLaddr(); } break; case GAME_RUNNING: playGame(deltaS); break; case GAME_RUNNER_DEAD: //console.log("Time=" + curTime + ", Tick= " + playTickTimer); //if(recordMode) recordModeToggle(GAME_RUNNER_DEAD); //for debug only (if enable it must disable below statement) if(recordMode == RECORD_KEY) recordModeDump(GAME_RUNNER_DEAD); soundStop(soundFall); stopAllSpriteObj(); themeSoundPlay("dead"); switch(playMode) { case PLAY_CLASSIC: case PLAY_AUTO: --runnerLife; drawLife(); if(runnerLife <= 0) { gameOverAnimation(); menuIconDisable(1); if(playMode == PLAY_CLASSIC) clearClassicInfo(); gameState = GAME_OVER_ANIMATION; } else { setTimeout(function() {gameState = GAME_NEW_LEVEL; }, 500); gameState = GAME_WAITING; if(playMode == PLAY_CLASSIC) setClassicInfo(0); } break; case PLAY_DEMO: error("DEMO dead level=" + curLevel); setTimeout(function() {incLevel(1,0); gameState = GAME_NEW_LEVEL; }, 500); gameState = GAME_WAITING; break; case PLAY_DEMO_ONCE: error("DEMO dead level=" + curLevel); disableStageClickEvent(); document.onkeydown = handleKeyDown; setTimeout(function() {playMode = PLAY_MODERN; startGame(); }, 500); gameState = GAME_WAITING; break; case PLAY_MODERN: setTimeout(function() {gameState = GAME_NEW_LEVEL; }, 500); gameState = GAME_WAITING; break; case PLAY_TEST: setTimeout(function() { back2EditMode(0); }, 500); gameState = GAME_WAITING; break; default: debug("GAME_RUNNER_DEAD: desgin error !"); break; } break; case GAME_OVER_ANIMATION: break; case GAME_OVER: scoreInfo = null; if(playMode == PLAY_CLASSIC && !sometimePlayInGodMode) { scoreInfo = {s:curScore, l: passedLevel+1 }; } showScoreTable(playData, scoreInfo , function() { showCoverPage();}); gameState = GAME_WAITING; return; case GAME_FINISH: stopAllSpriteObj(); //console.log("Time=" + curTime + ", Tick= " + playTickTimer); switch(playMode) { case PLAY_CLASSIC: case PLAY_AUTO: case PLAY_DEMO: soundPlay(soundPass); finalScore = curScore + SCORE_COMPLETE_LEVEL; scoreDuration = ((soundPass.getDuration()) /(SCORE_COUNTER+1))| 0; lastScoreTime = event.time; scoreIncValue = SCORE_COMPLETE_LEVEL/SCORE_COUNTER|0; drawScore(scoreIncValue); gameState = GAME_FINISH_SCORE_COUNT; break; case PLAY_DEMO_ONCE: soundPlay(soundEnding); disableStageClickEvent(); document.onkeydown = handleKeyDown; setTimeout(function() {playMode = PLAY_MODERN; startGame(); }, 500); gameState = GAME_WAITING; break; case PLAY_MODERN: soundPlay(soundEnding); var lastHiScore = lastHiScore = updateModernScoreInfo(); levelPassDialog(curLevel, curGetGold, curGuardDeadNo, curTime, lastHiScore, returnBitmap, select1Bitmap, nextBitmap, mainStage, tileScale, gameFinishCallback); gameState = GAME_WAITING; break; case PLAY_TEST: soundPlay(soundEnding); setTimeout(function() { back2EditMode(1);},500); gameState = GAME_WAITING; break; default: error("design error, playMode =" + playMode); break; } //if(recordMode) recordModeToggle(GAME_FINISH); //for debug only (if enable it must comment below if statement) if(recordMode == RECORD_KEY) { recordModeDump(GAME_FINISH); if( (playMode == PLAY_CLASSIC || playMode == PLAY_MODERN) && playData <= maxPlayId ) { updatePlayerDemoData(playData, curDemoData); //update current player demo data } } break; case GAME_FINISH_SCORE_COUNT: if(event.time > lastScoreTime+ scoreDuration) { lastScoreTime += scoreDuration; if(curScore + scoreIncValue >= finalScore) { curScore = finalScore; drawScore(0); gameState = GAME_NEW_LEVEL; switch(playMode) { case PLAY_TEST: setTimeout(function() { back2EditMode(1);},500); break; case PLAY_CLASSIC: if(++runnerLife > RUNNER_MAX_LIFE) runnerLife = RUNNER_MAX_LIFE; break; case PLAY_AUTO: if(demoCount >= demoMaxCount) { setTimeout(function(){ showCoverPage();}, 500); gameState = GAME_WAITING; } break; } if(recordMode != RECORD_PLAY) { if(incLevel(1, 1) && playMode == PLAY_CLASSIC && passedLevel >= levelData.length) gameState = GAME_WIN; } } else { drawScore(scoreIncValue); } } break; case GAME_NEXT_LEVEL: soundStop(soundFall); stopAllSpriteObj(); incLevel(shiftLevelNum, 0); gameState = GAME_NEW_LEVEL; return; case GAME_PREV_LEVEL: soundStop(soundFall); stopAllSpriteObj(); decLevel(shiftLevelNum); gameState = GAME_NEW_LEVEL; return; case GAME_NEW_LEVEL: gameState = GAME_WAITING; newLevel(); break; case GAME_WIN: scoreInfo = {s:curScore, l: levelData.length, w:1 }; //winner menuIconDisable(1); clearClassicInfo(); showScoreTable(playData, scoreInfo , function() { showCoverPage();}); gameState = GAME_WAITING; return; case GAME_LOADING: break; case GAME_PAUSE: default: return; } mainStage.update(); }