Fichiers
LodeRunner_TotalRecall/lodeRunner.main.js
T
simon_hung dc96a5ac8d Lode Runner version 2.11a, AI_VERSION=4
(1) Modified for AI VERSION = 4
   (1.1) When guard failing in hole, will drop gold before guard failing into hole totally
   (1.2) Shake time extension when guard in hole.
         NOW the runner can dig three hold for three guards and pass through them. (MUST quickly)
	 ==> The behavior almost same as original lode runner (APPLE-II version).
   Modified files: LodeRunner/lodeRunner.guard.js

(2) New Demo Data all ai_version = 4
    modified files: lodeRunner.demoData1.js

(3) Slow down play speed:
                            //slow normal fast
    change from speedMode = [15, 20, 25, 30, 35];
             to speedMode = [14, 18, 23, 29, 35];
    Modified files: lodeRunner.main.js

(4) Keep ai version don't overflow:
    Modified files: lodeRunner.preload.js
2016-06-06 22:10:32 +08:00

1610 lignes
40 KiB
JavaScript

/**
* @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
*
* Source Code: https://github.com/SimonHung/LodeRunner
*
* by Simon Hung 2014/06/20, 2015/06/13 (http://simonsays-tw.com)
* =============================================================================
*/
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 = [15, 20, 25, 30, 35]; //slow normal fast
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 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;
//loadDataJS(); //load demo data file
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 loadDataJS()
{
var arg = getUrlArgument();
var js = document.createElement('script');
js.type = "text/javascript";
////js.src = "lodeRunner.wData.jss" + ((arg == null)?"": ("?" + arg));
js.src = "lodeRunner.wData.jss" + ("?dbName=" + dbName) + ((arg == null)? "" : ("&" + arg)); //add set dbName
//console.log(js.src);
js.onload = function() {
loadStoreVariable(); //load data from localStorage
initMenuVariable(); //init menu variable
initDemoModeVariable();
debug('demo data load complete');
};
//document.body.appendChild(js);
document.getElementsByTagName('head')[0].appendChild(js);
}
*/
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();
getRepeatAction();
}
function canvasReSize()
{
var iconSizeX;
for (var scale = MAX_SCALE*100; scale >= MIN_SCALE*100; scale -= 25) {
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";
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,
//xMove and yMove initial by setSpeedByAiVersion()
//xMove = 4 * tileScale * 2;
//yMove = 4 * tileScale * 2;
}
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 = "#301050";
}
function showCoverPage()
{
menuIconDisable(1);
clearIdleDemoTimer();
mainStage.removeAllChildren();
mainStage.addChild(coverBitmap);
mainStage.addChild(signetBitmap);
mainStage.addChild(remakeBitmap);
mainStage.update();
waitIdleDemo(3000);
}
var idleTimer=null, startIdleTime;
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();
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 clearIdleDemoTimer()
{
if(idleTimer) clearInterval(idleTimer);
idleTimer = null;
}
function noKeyDown()
{
return false;
}
function anyKeyDown()
{
//if(changingLevel) return false;
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) )
){
//(playData != PLAY_DATA_1 && playData != PLAY_DATA_2 && playData != PLAY_DATA_3 && 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(speedMode[speedMode.length-1]); //very fast
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)
{
//(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] = {};
}
}
//(2) draw map
/*
var 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 index = NO_OF_TILES_Y * NO_OF_TILES_X - 1;
for(var y = NO_OF_TILES_Y-1; y >= 0; y--) {
for(var x = NO_OF_TILES_X-1; x >= 0; 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 = new createjs.Bitmap(getThemeImage("brick"));
break;
case '@': //Solid Brick
map[x][y].base = SOLID_T;
map[x][y].act = SOLID_T;
curTile = map[x][y].bitmap = new createjs.Bitmap(getThemeImage("solid"));
break;
case 'H': //Ladder
map[x][y].base =LADDR_T;
map[x][y].act =LADDR_T;
curTile = map[x][y].bitmap = new createjs.Bitmap(getThemeImage("ladder"));
break;
case '-': //Line of rope
map[x][y].base = BAR_T;
map[x][y].act = BAR_T;
curTile = map[x][y].bitmap = new createjs.Bitmap(getThemeImage("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 = new createjs.Bitmap(getThemeImage("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 = new createjs.Bitmap(getThemeImage("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 = new createjs.Bitmap(getThemeImage("gold"));
goldCount++;
break;
case '0': //Guard
map[x][y].base = EMPTY_T;
map[x][y].act = GUARD_T;
map[x][y].bitmap = null;
if(guardCount >= maxGuard) {
map[x][y].act = EMPTY_T;
continue; //too many guard , set this tile as empty
}
/*
guard[guardCount] = {};
curTile = guard[guardCount].sprite = new createjs.Sprite(guardData, "runLeft");
guard[guardCount].pos = { x:x, y:y, xOffset:0, yOffset:0};
guard[guardCount].action = ACT_STOP;
guard[guardCount].shape = "runLeft";
guard[guardCount].lastLeftRight = "ACT_LEFT";
guard[guardCount].hasGold = 0;
*/
//for backward compatible guard order must same as old, so add to beginning of array
curTile = new createjs.Sprite(guardData, "runLeft");
guard.unshift({
sprite: curTile,
pos: { x:x, y:y, xOffset:0, yOffset:0},
action: ACT_STOP,
shape: "runLeft",
lastLeftRight: "ACT_LEFT",
hasGold: 0
});
guardCount++;
//curTile.gotoAndPlay();
curTile.stop();
//curTile.framerate = 60;
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.gotoAndPlay();
curTile.stop();
//curTile.framerate = 60;
break;
}
curTile.setTransform(x * tileWScale, y * tileHScale, tileScale, tileScale); //x,y, scaleX, scaleY
mainStage.addChild(curTile);
}
}
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(arguments.callee.name, "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(levelData);
}
var groundTile;
function drawGround()
{
groundTile = [];
for(var x = 0; x < NO_OF_TILES_X; x++) {
groundTile[x] = new createjs.Bitmap(getThemeImage("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;
//if(playMode == PLAY_CLASSIC || playMode == PLAY_AUTO) xOffset = 20;
//else xOffset = 19;
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]);
//if(playMode == PLAY_CLASSIC || playMode == PLAY_AUTO) digitNo = 7;
//else digitNo = 6
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;
}
//runner.xMove = 4 * tileScale * 2;
//runner.yMove = 4 * tileScale * 2;
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 = new createjs.Bitmap(getThemeImage("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_MODERN || playMode == PLAY_EDIT) {
curScore = 0; curGetGold = 0; curGuardDeadNo = 0;
}
*/
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();
}
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);
}
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, null);
setFirstPlayInfo();
} else {
initForPlay();
}
}
/* Don't show main menu
var first = 1
function showMainMenu()
{
if(firstPlay && first) {
mainMenu(null);
} else {
showHelpMenu();
}
first = 0;
}
*/
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 {
/* Don't display GAME VERSION SELECTION , 6/7/2015
if(playerName == "") {
inputPlayerName(mainStage, showMainMenu);
} else {
showMainMenu();
}
*/
if(playerName == "") {
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, null)
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:
//if(demoDataLoading) { showGameLoading(); break }
//if(playMode == PLAY_AUTO) initPlayDemo();
//if(recordMode) initRecordVariable();
countAutoDemoTimer();
if(keyAction != ACT_STOP && keyAction != ACT_UNKNOWN) {
disableAutoDemoTimer();
gameState = GAME_RUNNING;
//if(playMode != PLAY_DEMO && playMode != PLAY_DEMO_ONCE) themeIconObj.disable(1);
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:
//mainStage.update();
//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 {
//stopAllSpriteObj();
setTimeout(function() {gameState = GAME_NEW_LEVEL; }, 500);
gameState = GAME_WAITING;
if(playMode == PLAY_CLASSIC) setClassicInfo(0);
}
break;
case PLAY_DEMO:
error(arguments.callee.name, "DEMO dead level=" + curLevel);
setTimeout(function() {incLevel(1,0); gameState = GAME_NEW_LEVEL; }, 500);
gameState = GAME_WAITING;
break;
case PLAY_DEMO_ONCE:
error(arguments.callee.name, "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:
//if(playMode == PLAY_CLASSIC) clearClassicInfo();
break;
case GAME_OVER:
////getClassicInfo();
scoreInfo = null;
if(playMode == PLAY_CLASSIC && !sometimePlayInGodMode) {
//try to set hi-score record
//scoreInfo = {s:curScore, l:(curLevel>maxLevel)?curLevel:maxLevel};
scoreInfo = {s:curScore, l: passedLevel+1 };
}
showScoreTable(playData, scoreInfo , function() { showCoverPage();});
//setTimeout(function(){ showCoverPage();}, 2000);
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(arguments.callee.name, "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();
}