//============================================================================= // AI reference book: "玩 Lode Runner 學 C 語言" // http://www.kingstone.com.tw/book/book_page.asp?kmcode=2014710650538 //============================================================================= var movePolicy = [ [0, 0, 0, 0, 0, 0], //* move_map is used to find *// [0, 1, 1, 0, 1, 1], //* wheather to move a enm *// [1, 1, 1, 1, 1, 1], //* by indexing into it with *// [1, 2, 1, 1, 2, 1], //* enm_byte + num_enm + *// [1, 2, 2, 1, 2, 2], //* set_num to get a byte. *// [2, 2, 2, 2, 2, 2], //* then that byte is checked*// [2, 2, 3, 2, 2, 3], //* for !=0 and then decrmnt *// [2, 3, 3, 2, 3, 3], //* for next test until = 0 *// [3, 3, 3, 3, 3, 3], [3, 3, 4, 3, 3, 4], [3, 4, 4, 3, 4, 4], [4, 4, 4, 4, 4, 4] ]; var moveOffset = 0; var moveId = 0; //current guard id var numOfMoveItems = movePolicy[0].length; //******************************** //initial guard start move value //******************************** function initGuardVariable() { moveOffset = moveId = 0; } function moveGuard() { var moves; var curGuard; var x, y, yOffset; if(!guardCount) return; //no guard if( ++moveOffset >= numOfMoveItems ) moveOffset = 0; moves = movePolicy[guardCount][moveOffset]; // get next moves while ( moves-- > 0) { // slows guard relative to runner if(++moveId >= guardCount) moveId = 0; curGuard = guard[moveId]; if(curGuard.action == ACT_IN_HOLE || curGuard.action == ACT_REBORN) { continue; } guardMoveStep(moveId, bestMove(moveId)); } } function guardMoveStep( id, action) { var curGuard = guard[id]; var x = curGuard.pos.x; var xOffset = curGuard.pos.xOffset; var y = curGuard.pos.y; var yOffset = curGuard.pos.yOffset; var curToken, nextToken; var centerX, centerY; var curShape, newShape; var stayCurrPos; centerX = centerY = ACT_STOP; curShape = newShape = curGuard.shape; if(curGuard.action == ACT_CLIMB_OUT && action == ACT_STOP) curGuard.action = ACT_STOP; //for level 16, 30, guard will stock in hole switch(action) { case ACT_UP: case ACT_DOWN: case ACT_FALL: if ( action == ACT_UP ) { stayCurrPos = ( y <= 0 || (nextToken = map[x][y-1].act) == BLOCK_T || nextToken == SOLID_T || nextToken == TRAP_T || nextToken == GUARD_T); if( yOffset <= 0 && stayCurrPos) action = ACT_STOP; } else { //ACT_DOWN || ACT_FALL stayCurrPos = ( y >= maxTileY || (nextToken = map[x][y+1].act) == BLOCK_T || nextToken == SOLID_T || nextToken == GUARD_T); if( action == ACT_FALL && yOffset < 0 && map[x][y].base == BLOCK_T) { action = ACT_IN_HOLE; stayCurrPos = 1; } else { if ( yOffset >= 0 && stayCurrPos) action = ACT_STOP; } } if ( action != ACT_STOP ) { if ( xOffset > 0) centerX = ACT_LEFT; else if ( xOffset < 0) centerX = ACT_RIGHT; } break; case ACT_LEFT: case ACT_RIGHT: if ( action == ACT_LEFT ) { /* original source code from book stayCurrPos = ( x <= 0 || (nextToken = map[x-1][y].act) == BLOCK_T || nextToken == SOLID_T || nextToken == TRAP_T || nextToken == GUARD_T); */ // change check TRAP_T from base, // for support level 41==> runner in trap will cause guard move stayCurrPos = ( x <= 0 || (nextToken = map[x-1][y].act) == BLOCK_T || nextToken == SOLID_T || nextToken == GUARD_T || map[x-1][y].base == TRAP_T); if (xOffset <= 0 && stayCurrPos) action = ACT_STOP; } else { //ACT_RIGHT /* original source code from book stayCurrPos = ( x >= maxTileX || (nextToken = map[x+1][y].act) == BLOCK_T || nextToken == SOLID_T || nextToken == TRAP_T || nextToken == GUARD_T); */ // change check TRAP_T from base, // for support level 41==> runner in trap will cause guard move stayCurrPos = ( x >= maxTileX || (nextToken = map[x+1][y].act) == BLOCK_T || nextToken == SOLID_T || nextToken == GUARD_T || map[x+1][y].base == TRAP_T); if (xOffset >= 0 && stayCurrPos) action = ACT_STOP; } if ( action != ACT_STOP ) { if ( yOffset > 0 ) centerY = ACT_UP; else if ( yOffset < 0) centerY = ACT_DOWN; } break; } curToken = map[x][y].base; if ( action == ACT_UP ) { yOffset -= yMove; if(stayCurrPos && yOffset < 0) yOffset = 0; //stay on current position else if(yOffset < -H2) { //move to y-1 position if ( curToken == BLOCK_T || curToken == HLADR_T ) curToken = EMPTY_T; //in hole or hide laddr map[x][y].act = curToken; //runner move to [x][y-1], so set [x][y].act to previous state y--; yOffset = tileH + yOffset; if(map[x][y].act == RUNNER_T) setRunnerDead(); //collision //map[x][y].act = GUARD_T; } if( yOffset <= 0 && yOffset > -yMove) { dropGold(id); //decrease count } newShape = "runUpDn"; } if ( centerY == ACT_UP ) { yOffset -= yMove; if( yOffset < 0) yOffset = 0; //move to center Y } if ( action == ACT_DOWN || action == ACT_FALL || action == ACT_IN_HOLE) { var holdOnBar = 0; if(curToken == BAR_T) { if( yOffset < 0) holdOnBar = 1; else if(action == ACT_DOWN && y < maxTileY && map[x][y+1].act != LADDR_T) { action = ACT_FALL; //shape fixed: 2014/03/27 } } yOffset += yMove; if(holdOnBar == 1 && yOffset >= 0) { yOffset = 0; //fall and hold on bar action = ACT_FALL_BAR; } if(stayCurrPos && yOffset > 0 ) yOffset = 0; //stay on current position else if(yOffset > H2) { //move to y+1 position if(curToken == BLOCK_T || curToken == HLADR_T) curToken = EMPTY_T; //in hole or hide laddr map[x][y].act = curToken; //runner move to [x][y+1], so set [x][y].act to previous state y++; yOffset = yOffset - tileH; if(map[x][y].act == RUNNER_T) setRunnerDead(); //collision //map[x][y].act = GUARD_T; } //add condition: AI version >= 3 will decrease drop count while guard fall if( ((curAiVersion >= 3 && action == ACT_FALL) || action == ACT_DOWN) && yOffset >= 0 && yOffset < yMove) { //try drop gold dropGold(id); //decrease count } if(action == ACT_IN_HOLE) { //check in hole or still falling if (yOffset < 0) { action = ACT_FALL; //still falling //---------------------------------------------------------------------- //For AI version >= 4, drop gold before guard failing into hole totally if(curAiVersion >= 4 && curGuard.hasGold > 0) { if(map[x][y-1].base == EMPTY_T) { //drop gold above addGold(x, y-1); } else decGold(); //gold disappear curGuard.hasGold = 0; } //---------------------------------------------------------------------- } else { //fall into hole (yOffset MUST = 0) //---------------------------------------------------------------------- //For AI version < 4, drop gold after guard failing into hole totally if( curGuard.hasGold > 0 ) { if(map[x][y-1].base == EMPTY_T) { //drop gold above addGold(x, y-1); } else decGold(); //gold disappear } curGuard.hasGold = 0; //---------------------------------------------------------------------- if( curShape == "fallRight") newShape = "shakeRight"; else newShape = "shakeLeft"; themeSoundPlay("trap"); shakeTimeStart = recordCount; //for debug if(curAiVersion < 3) { curGuard.sprite.on("animationend", function() { climbOut(id); }); } else { add2GuardShakeQueue(id, newShape); } if(playMode == PLAY_CLASSIC || playMode == PLAY_AUTO || playMode == PLAY_DEMO) { drawScore(SCORE_IN_HOLE); } else { //for modem mode & edit mode //drawGuard(1); //only guard dead need add count } } } if(action == ACT_DOWN) { newShape = "runUpDn"; } else { //ACT_FALL or ACT_FALL_BAR if (action == ACT_FALL_BAR) { if(curGuard.lastLeftRight == ACT_LEFT) newShape = "barLeft"; else newShape = "barRight"; } else { if(action == ACT_FALL && curShape != "fallLeft" && curShape != "fallRight") { if (curGuard.lastLeftRight == ACT_LEFT) newShape = "fallLeft"; else newShape = "fallRight"; } } } } if ( centerY == ACT_DOWN ) { yOffset += yMove; if ( yOffset > 0 ) yOffset = 0; //move to center Y } if ( action == ACT_LEFT) { xOffset -= xMove; if(stayCurrPos && xOffset < 0) xOffset = 0; //stay on current position else if ( xOffset < -W2) { //move to x-1 position if(curToken == BLOCK_T || curToken == HLADR_T) curToken = EMPTY_T; //in hole or hide laddr map[x][y].act = curToken; //runner move to [x-1][y], so set [x][y].act to previous state x--; xOffset = tileW + xOffset; if(map[x][y].act == RUNNER_T) setRunnerDead(); //collision //map[x][y].act = GUARD_T; } if( xOffset <= 0 && xOffset > -xMove) { dropGold(id); //try to drop gold } if(curToken == BAR_T) newShape = "barLeft"; else newShape = "runLeft"; } if ( centerX == ACT_LEFT ) { xOffset -= xMove; if ( xOffset < 0) xOffset = 0; //move to center X } if ( action == ACT_RIGHT ) { xOffset += xMove; if(stayCurrPos && xOffset > 0) xOffset = 0; //stay on current position else if ( xOffset > W2) { //move to x+1 position if(curToken == BLOCK_T || curToken == HLADR_T) curToken = EMPTY_T; //in hole or hide laddr map[x][y].act = curToken; //runner move to [x+1][y], so set [x][y].act to previous state x++; xOffset = xOffset - tileW; if(map[x][y].act == RUNNER_T) setRunnerDead(); //collision //map[x][y].act = GUARD_T; } if( xOffset >= 0 && xOffset < xMove) { dropGold(id); } if(curToken == BAR_T) newShape = "barRight"; else newShape = "runRight"; } if ( centerX == ACT_RIGHT ) { xOffset += xMove; if ( xOffset > 0) xOffset = 0; //move to center X } //if(curGuard == ACT_CLIMB_OUT) action == ACT_CLIMB_OUT; if(action == ACT_STOP) { if(curGuard.action != ACT_STOP){ curGuard.sprite.stop(); if(curGuard.action != ACT_CLIMB_OUT) curGuard.action = ACT_STOP; } } else { if(curGuard.action == ACT_CLIMB_OUT) action = ACT_CLIMB_OUT; curGuard.sprite.x = (x * tileW + xOffset) * tileScale | 0; curGuard.sprite.y = (y * tileH + yOffset) * tileScale | 0; curGuard.pos = { x:x, y:y, xOffset:xOffset, yOffset:yOffset}; if(curShape != newShape) { curGuard.sprite.gotoAndPlay(newShape); curGuard.shape = newShape; } if(action != curGuard.action){ curGuard.sprite.play(); } curGuard.action = action; if(action == ACT_LEFT || action == ACT_RIGHT) curGuard.lastLeftRight = action; } map[x][y].act = GUARD_T; // Check to get gold and carry if(map[x][y].base == GOLD_T && curGuard.hasGold == 0 && ((!xOffset && yOffset >= 0 && yOffset < H4) || (!yOffset && xOffset >= 0 && xOffset < W4) || (y < maxTileY && map[x][y+1].base == LADDR_T && yOffset < H4) // gold above laddr ) ) { //curGuard.hasGold = ((Math.random()*26)+14)|0; //14 - 39 curGuard.hasGold = ((Math.random()*26)+12)|0; //12 - 37 change gold drop steps if(playMode == PLAY_AUTO || playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) getDemoGold(curGuard); if(recordMode) processRecordGold(curGuard); removeGold(x, y); //debug ("get, (x,y) = " + x + "," + y + ", offset = " + xOffset); } //check collision again //checkCollision(runner.pos.x, runner.pos.y); } function dropGold(id) { var curGuard = guard[id]; var nextToken; var drop = 0; switch (true) { case (curGuard.hasGold > 1): curGuard.hasGold--; // count > 1, don't drop it only decrease count //loadingTxt.text = "(" + id + ") = " + curGuard.hasGold; break; case (curGuard.hasGold == 1): var x = curGuard.pos.x, y = curGuard.pos.y; if(map[x][y].base == EMPTY_T && ( y >= maxTileY || ((nextToken = map[x][y+1].base) == BLOCK_T || nextToken == SOLID_T || nextToken == LADDR_T) ) ) { addGold(x,y); curGuard.hasGold = -1; //for record play action always use value = -1 //curGuard.hasGold = -(((Math.random()*10)+1)|0); //-1 ~ -10; //waiting time for get gold drop = 1; } break; case (curGuard.hasGold < 0): curGuard.hasGold++; //wait, don't get gold till count = 0 //loadingTxt.text = "(" + id + ") = " + curGuard.hasGold; break; } } //============================================= // BEGIN NEW SHAKE METHOD for AI version >= 3 //============================================= var DEBUG_TIME = 0; var shakeRight = [ 8, 9, 10, 9, 10, 8 ]; var shakeLeft = [ 19, 20, 21, 20, 21, 19 ]; var shakeTime = [ 36, 3, 3, 3, 3, 3 ]; var shakingGuardList = []; function initStillFrameVariable() { initGuardShakeVariable(); initFillHoleVariable(); initRebornVariable(); } function initGuardShakeVariable() { shakingGuardList = []; //------------------------------------------------------------------------- // Shake time extension when guard in hole, // so the runner can dig three hold for three guards and pass through them. // The behavior almost same as original lode runner (APPLE-II version). // 2016/06/04 //------------------------------------------------------------------------- if(curAiVersion <= 3) shakeTime = [ 36, 3, 3, 3, 3, 3 ]; //for AI VERSION = 3 else shakeTime = [ 51, 3, 3, 3, 3, 3 ]; //for AI VERSION > 3 } function add2GuardShakeQueue(id, shape) { var curGuard = guard[id]; if(shape == "shakeRight") { curGuard.shapeFrame = shakeRight; } else { curGuard.shapeFrame = shakeLeft; } curGuard.curFrameIdx = 0; curGuard.curFrameTime = -1; //for init shakingGuardList.push(id); //error(arguments.callee.name, "push id =" + id + "(" + shakingGuardList + ")" ); } function processGuardShake() { var curGuard, curIdx; for(var i = 0; i < shakingGuardList.length;) { curGuard = guard[shakingGuardList[i]]; curIdx = curGuard.curFrameIdx; if( curGuard.curFrameTime < 0) { //start shake => set still frame curGuard.curFrameTime = 0; curGuard.sprite.gotoAndStop(curGuard.shapeFrame[curIdx]); } else { if(++curGuard.curFrameTime >= shakeTime[curIdx]) { if(++curGuard.curFrameIdx < curGuard.shapeFrame.length) { //change frame curGuard.curFrameTime = 0; curGuard.sprite.gotoAndStop(curGuard.shapeFrame[curGuard.curFrameIdx]); } else { //shake time out var id = shakingGuardList[i]; shakingGuardList.splice(i, 1); //remove from list //error(arguments.callee.name, "remove id =" + id + "(" + shakingGuardList + ")" ); climbOut(id); //climb out continue; } } } i++; } } function removeFromShake(id) { for(var i = 0; i < shakingGuardList.length;i++) { if(shakingGuardList[i] == id) { shakingGuardList.splice(i, 1); //remove from list //error(arguments.callee.name, "remove id =" + id + "(" + shakingGuardList + ")" ); return; } } error(arguments.callee.name, "design error id =" + id + "(" + shakingGuardList + ")" ); } //====================== // END NEW SHAKE METHOD //====================== function climbOut(id) { var curGuard = guard[id] curGuard.action = ACT_CLIMB_OUT; curGuard.sprite.removeAllEventListeners ("animationend"); curGuard.sprite.gotoAndPlay("runUpDn"); curGuard.shape = "runUpDn"; curGuard.holePos = {x: curGuard.pos.x, y: curGuard.pos.y }; if(DEBUG_TIME) loadingTxt.text = "ShakeTime = " + (recordCount - shakeTimeStart); //for debug } function bestMove(id) { var guarder = guard[id]; var x = guarder.pos.x; var xOffset = guarder.pos.xOffset; var y = guarder.pos.y; var yOffset = guarder.pos.yOffset; var curToken, nextBelow, nextMove; var checkSameLevelOnly = 0; curToken = map[x][y].base; if(guarder.action == ACT_CLIMB_OUT) { //clib from hole if(guarder.pos.y == guarder.holePos.y) { return (ACT_UP); }else { checkSameLevelOnly = 1; if(guarder.pos.x != guarder.holePos.x) { //out of hole guarder.action = ACT_LEFT; } } } if( !checkSameLevelOnly) { /****** next check to see if enm must fall. if so ***********/ /****** return e_fall and skip the rest. ***********/ if ( curToken == LADDR_T || (curToken == BAR_T && yOffset === 0) ) { //ladder & bar /* no guard fall */ } else if ( yOffset < 0) //no laddr & yOffset < 0 ==> falling return (ACT_FALL); else if ( y < maxTileY ) { nextBelow = map[x][y+1].act; if ( (nextBelow == EMPTY_T || nextBelow == RUNNER_T )) { return (ACT_FALL); } else if ( nextBelow == BLOCK_T || nextBelow == SOLID_T || nextBelow == GUARD_T || nextBelow == LADDR_T ) { /* no guard fall */ } else { return ( ACT_FALL ); } } } /******* next check to see if palyer on same floor *********/ /******* and whether enm can get him. Ignore walls *********/ var runnerX = runner.pos.x; var runnerY = runner.pos.y; // if ( y == runnerY ) { // same floor with runner if ( y == runnerY && runner.action != ACT_FALL) { //case : guard on laddr and falling => don't catch it while ( x != runnerX ) { if ( y < maxTileY ) nextBelow = map[x][y+1].base; else nextBelow = SOLID_T; curToken = map[x][y].base; if ( curToken == LADDR_T || curToken == BAR_T || // go through nextBelow == SOLID_T || nextBelow == LADDR_T || nextBelow == BLOCK_T || map[x][y+1].act == GUARD_T || //fixed: must check map[].act with guard_t (for support champLevel:43) nextBelow == BAR_T || nextBelow == GOLD_T) //add BAR_T & GOLD_T for support level 92 { if ( x < runnerX) // guard left to runner ++x; else if ( x > runnerX ) --x; // guard right to runner } else break; // exit loop with closest x if no path to runner } if ( x == runnerX ) // scan for a path ignoring walls is a success { if (guarder.pos.x < runnerX ) { //if left of man go right else left nextMove = ACT_RIGHT; } else if ( guarder.pos.x > runnerX ) { nextMove = ACT_LEFT; } else { // guard X = runner X if ( guarder.pos.xOffset < runner.pos.xOffset ) nextMove = ACT_RIGHT; else nextMove = ACT_LEFT; } return (nextMove); } } // if ( y == runnerY ) { ... /********** If can't reach man on current level, then scan floor *********/ /********** (ignoring walls) and look up and down for best move *********/ return scanFloor(id); } var bestPath, bestRating, curRating; var leftEnd, rightEnd; var startX, startY; function scanFloor(id) { var x, y; var curToken, nextBelow; var curPath; x = startX = guard[id].pos.x; y = startY = guard[id].pos.y; bestRating = 255; // start with worst rating curRating = 255; bestPath = ACT_STOP; /****** get ends for search along floor ******/ while ( x > 0 ) { //get left end first curToken = map[x-1][y].act; if ( curToken == BLOCK_T || curToken == SOLID_T ) break; if ( curToken == LADDR_T || curToken == BAR_T || y >= maxTileY || y < maxTileY && ( ( nextBelow = map[x-1][y+1].base) == BLOCK_T || nextBelow == SOLID_T || nextBelow == LADDR_T ) ) --x; else { --x; // go on left anyway break; } } leftEnd = x; x = startX; while ( x < maxTileX ) { // get right end next curToken = map[x+1][y].act; if ( curToken == BLOCK_T || curToken == SOLID_T ) break; if ( curToken == LADDR_T || curToken == BAR_T || y >= maxTileY || y < maxTileY && ( ( nextBelow = map[x+1][y+1].base) == BLOCK_T || nextBelow == SOLID_T || nextBelow == LADDR_T ) ) ++x; else { // go on right anyway ++x; break; } } rightEnd = x; /******* Do middle scan first for best rating and direction *******/ x = startX; if ( y < maxTileY && (nextBelow = map[x][y+1].base) != BLOCK_T && nextBelow != SOLID_T ) scanDown( x, ACT_DOWN ); if( map[x][y].base == LADDR_T ) scanUp( x, ACT_UP ); /******* next scan both sides of floor for best rating *******/ curPath = ACT_LEFT; x = leftEnd; while ( true ) { if ( x == startX ) { if ( curPath == ACT_LEFT && rightEnd != startX ) { curPath = ACT_RIGHT; x = rightEnd; } else break; } if( y < maxTileY && (nextBelow = map [x][y+1].base) != BLOCK_T && nextBelow != SOLID_T ) scanDown (x, curPath ); if( map[x][y].base == LADDR_T ) scanUp ( x, curPath ); if ( curPath == ACT_LEFT ) x++; else x--; } return ( bestPath ); } // end scan floor for best direction to go function scanDown(x, curPath ) { var y; var nextBelow; //curRating; var runnerX = runner.pos.x; var runnerY = runner.pos.y; y = startY; while( y < maxTileY && ( nextBelow = map [x][y+1].base) != BLOCK_T && nextBelow != SOLID_T ) // while no floor below ==> can move down { if ( map[x][y].base != EMPTY_T && map[x][y].base != HLADR_T) { // if not falling ==> try move left or right //************************************************************************************ // 2014/04/14 Add check "map[x][y].base != HLADR_T" for support // champLevel 19: a guard in hole with h-ladder can run left after dig the left hole //************************************************************************************ if ( x > 0 ) { // if not at left edge check left side if ( (nextBelow = map[x-1][y+1].base) == BLOCK_T || nextBelow == LADDR_T || nextBelow == SOLID_T || map[x-1][y].base == BAR_T ) // can move left { if ( y >= runnerY ) // no need to go on break; // already below runner } } if ( x < maxTileX ) // if not at right edge check right side { if ( (nextBelow = map[x+1][y+1].base) == BLOCK_T || nextBelow == LADDR_T || nextBelow == SOLID_T || map[x+1][y].base == BAR_T ) // can move right { if ( y >= runnerY ) break; } } } // end if not falling ++y; // go to next level down } // end while ( y < maxTileY ... ) scan down if( y == runnerY ) { // update best rating and direct. curRating = Math.abs(startX - x); // if ( (curRating = runnerX - x) < 0) //BUG from original book ? (changed by Simon) // curRating = -curRating; //ABS } else if ( y > runnerY ) curRating = y - runnerY + 200; // position below runner else curRating = runnerY - y + 100; // position above runner if( curRating < bestRating ) { bestRating = curRating; bestPath = curPath; } } // end Scan Down function scanUp( x, curPath ) { var y; var nextBelow; //curRating; var runnerX = runner.pos.x; var runnerY = runner.pos.y; y = startY; while ( y > 0 && map[x][y].base == LADDR_T ) { // while can go up --y; if ( x > 0 ) { // if not at left edge check left side if ( (nextBelow = map[x-1][y+1].base) == BLOCK_T || nextBelow == SOLID_T || nextBelow == LADDR_T || map[x-1][y].base == BAR_T ) // can move left { if ( y <= runnerY ) // no need to go on break; // already above runner } } if ( x < maxTileX ) { // if not at right edge check right side if ( (nextBelow = map[x+1][y+1].base) == BLOCK_T || nextBelow == SOLID_T || nextBelow == LADDR_T || map[x+1][y].base == BAR_T ) // can move right { if ( y <= runnerY ) break; } } //--y; } // end while ( y > 0 && laddr up) scan up if ( y == runnerY ) { // update best rating and direct. curRating = Math.abs(startX - x); //if ( (curRating = runnerX - x) < 0) // BUG from original book ? (changed by Simon) // curRating = -curRating; //ABS } else if ( y > runnerY ) curRating = y - runnerY + 200; // position below runner else curRating = runnerY - y + 100; // position above runner if ( curRating < bestRating ) { bestRating = curRating; bestPath = curPath; } } // end scan Up var bornRndX; //range random 0..maxTileX function initRnd() { //bornRndX = new rangeRandom(0, maxTileX, curLevel); //set fixed seed for demo mode bornRndX = new rangeRandom(0, maxTileX, 0); //random range 0 .. maxTileX } function getGuardId(x, y) { var id; for(id = 0; id < guardCount; id++) { if ( guard[id].pos.x == x && guard[id].pos.y == y) break; } assert(id < guardCount, "Error: can not get guard position!"); return id; } function guardReborn(x, y) { var id; //get guard id by current in hole position id = getGuardId(x, y); var bornY = 1; //start on line 2 var bornX = bornRndX.get(); var rndStart = bornX; while(map[bornX][bornY].act != EMPTY_T || map[bornX][bornY].base == GOLD_T || map[bornX][bornY].base == BLOCK_T ) { //BUG FIXED for level 115 (can not reborn at bornX=27) //don't born at gold position & diged position, 2/24/2015 if( (bornX = bornRndX.get()) == rndStart) { bornY++; } assert(bornY <= maxTileY, "Error: Born Y too large !"); } //debug("bornX = " + bornX); if(playMode == PLAY_AUTO || playMode == PLAY_DEMO || playMode == PLAY_DEMO_ONCE) { var bornPos = getDemoBornPos(); bornX = bornPos.x; bornY = bornPos.y; } if(recordMode == RECORD_KEY) saveRecordBornPos(bornX, bornY); else if(recordMode == RECORD_PLAY) { var bornPos = getRecordBornPos(); bornX = bornPos.x; bornY = bornPos.y; } map[bornX][bornY].act = GUARD_T; //debug("born (x,y) = (" + bornX + "," + bornY + ")"); var curGuard = guard[id]; curGuard.pos = { x:bornX, y:bornY, xOffset:0, yOffset: 0 }; curGuard.sprite.x = bornX * tileWScale | 0; curGuard.sprite.y = bornY * tileHScale | 0; rebornTimeStart = recordCount; if(curAiVersion < 3) { curGuard.sprite.on("animationend", function() { rebornComplete(id); }); curGuard.sprite.gotoAndPlay("reborn"); } else { add2RebornQueue(id); } curGuard.shape = "reborn"; curGuard.action = ACT_REBORN; } function rebornComplete(id) { var x = guard[id].pos.x; var y = guard[id].pos.y; if( map[x][y].act == RUNNER_T) setRunnerDead(); //collision map[x][y].act = GUARD_T; guard[id].sprite.removeAllEventListeners ("animationend"); guard[id].action = ACT_FALL; guard[id].shape = "fallRight"; //guard[id].hasGold = 0; guard[id].sprite.gotoAndPlay("fallRight"); themeSoundPlay("reborn"); if(DEBUG_TIME) loadingTxt.text = "rebornTime = " + (recordCount - rebornTimeStart); //for debug } function setRunnerDead() { if(!godMode) gameState = GAME_RUNNER_DEAD; } //=============================================== // BEGIN NEW FOR REBORN (ai version >= 3) //=============================================== var rebornFrame = [ 17, 18 ]; var rebornTime = [ 6, 2 ]; var rebornGuardList = []; function initRebornVariable() { rebornGuardList = []; } function add2RebornQueue(id) { var curGuard = guard[id]; curGuard.sprite.gotoAndStop("reborn"); curGuard.curFrameIdx = 0; curGuard.curFrameTime = -1; rebornGuardList.push(id); } function processReborn() { var curGuard, curIdx; for(var i = 0; i < rebornGuardList.length;) { curGuard = guard[rebornGuardList[i]]; curIdx = curGuard.curFrameIdx; if(++curGuard.curFrameTime >= rebornTime[curIdx]) { if(++curGuard.curFrameIdx < rebornFrame.length) { //change frame curGuard.curFrameTime = 0; curGuard.sprite.gotoAndStop(rebornFrame[curGuard.curFrameIdx]); } else { //reborn var id = rebornGuardList[i]; rebornGuardList.splice(i, 1); //remove from list rebornComplete(id); continue; } } i++; } } //==================== // END NEW FOR REBORN //====================