1var game = { 2 boardContentId: '', 3 testing: false, 4 showHint: false, 5 currentHint: {}, 6 dimention: 0, 7 cellSize: 0, 8 levelInfo: {}, 9 level: {}, 10 levelProgress: {}, 11 mooves: [], 12 balls: [], 13 newBalls: [], 14 gameInterval: {}, 15 frameInterval: 0, 16 frame: 0, 17 speed: 1, 18 lastRun: 0, 19 20 //cellMove: null, 21 minCellMove: 10, 22 23 distance: function () { 24 return game.frame * game.speed / game.cellSize 25 }, 26 27 play: function(showHint = false) { 28 state.refreshLastPlayed(); 29 30 if (state.firstPackagePlay() && !state.inductions['p' + state.package.current]) { 31 const inductionShown = inductionScreen.showPackageInduction(state.package.current) 32 33 if(inductionShown) { 34 state.inductions['p' + state.package.current] = true 35 return 36 } 37 } 38 39 game.fillTheBoard(showHint); 40 }, 41 42 fillTheBoard: function(showHint = false) { 43 get('boardScreen').classList.remove(INDUCTION) 44 45 let newLevelInfo = new LevelInfo(state.mode.current, state.package.current, state.level.current); 46 47 if (get(BOARD_CONTENT_ID) && newLevelInfo.equal(game.levelInfo)) { 48 newLevelInfo = null 49 game.levelInfo = {}; 50 game.animateCellsReset(); 51 setTimeout(game.fillTheBoard, 200, showHint); 52 return; 53 } else { 54 game.levelInfo = newLevelInfo 55 newLevelInfo = null 56 } 57 58 let gameLevel = levels[state.mode.current][state.package.current].levels[state.level.current]; 59 game.createBoard('board', BOARD_CONTENT_ID, gameLevel, game.cellMouseDown, showHint) 60 gameLevel = null 61 62 game.clearBalls(); 63 game.addBall(); 64 }, 65 66 createBoard: function(parentId, id, lvl, ceilClickListener, showHint=false) { 67 game.dimention = lvl.map.length; 68 game.showHint = showHint; 69 game.hintPause = false; 70 game.boardContentId = id; 71 game.ceilClickListener = ceilClickListener 72 73 rm(HINT); 74 game.clearBoard(id); 75 76 let parent = get(parentId); 77 const {boardTop, boardLeft, boardSize} = this.getBoardSize(parent); 78 79 let boardContent = document.createElement('div'); 80 boardContent.id = id; 81 boardContent.style.width = boardContent.style.height = boardSize + "px"; 82 boardContent.style.marginTop = boardTop + "px"; 83 boardContent.style.marginLeft = boardLeft + "px"; 84 boardContent.setAttribute('class', 'boardTable'); 85 86 game.level = clone(lvl); 87 game.levelProgress = new LevelProgress(state.mode.current, state.package.current, state.level.current, game.level.solution, state.currentLevelBestMoves()); 88 game.mooves = []; 89 game.frame = 0; 90 game.frameInterval = 0; 91 92 game.cellSize = Math.round(boardSize / game.dimention) 93 game.speed = round(game.cellSize / GAME_CEIL_DIVIDER_FOR_SPEED) 94 95 get('boardAdvice').style.height = (game.cellSize + boardTop) * 0.6 + "px" 96 97 for(let i = 0; i < game.dimention; i++){ 98 for(let j = 0; j < game.dimention; j++){ 99 let cellId = "cell-" + i + "-" + j; 100 rm(cellId); 101 102 let parentDiv = document.createElement("div"); 103 parentDiv.id = cellId; 104 parentDiv.style.width = (game.cellSize-1) + "px"; 105 parentDiv.style.height = (game.cellSize-1) + "px"; 106 parentDiv.topLeft(i * game.cellSize, j * game.cellSize); 107 parentDiv.setAttribute('row', i); 108 parentDiv.setAttribute('col', j); 109 parentDiv.setAttribute('class', game.level.map[i][j]); 110 parentDiv.mousedown(ceilClickListener); 111 112 let contentDiv = document.createElement("div"); 113 contentDiv.setAttribute('class', 'content'); 114 115 let subContentDiv = document.createElement("div"); 116 subContentDiv.setAttribute('class', 'subContent'); 117 118 let fixedDiv = document.createElement("div"); 119 fixedDiv.setAttribute('class', 'fixed'); 120 121 subContentDiv.appendChild(fixedDiv); 122 contentDiv.appendChild(subContentDiv); 123 parentDiv.appendChild(contentDiv); 124 boardContent.appendChild(parentDiv); 125 } 126 } 127 128 parent.appendChild(boardContent); 129 130 setTimeout(fireEvent, 0, GAME_STATE_CHANGE, {status: READY}); 131 132 game.showNextHint(); 133 }, 134 135 clearBoard: function(boardId) { 136 let boardContent = get(boardId) 137 138 if (!boardContent) return 139 140 let parentDivs = boardContent.childNodes; 141 for (let i = 0; i < parentDivs.length; i++) { 142 parentDivs[i].removeMousedown(game.ceilClickListener) 143 boardContent.removeChild(parentDivs[i]) 144 } 145 146 rm(boardId) 147 }, 148 149 getBoardSize: function(parent) { 150 let parentW = parent.clientWidth; 151 let parentH = window.innerHeight - get('boardTop').clientHeight - get('boardFooter').clientHeight; 152 let boardTop = 0; 153 let boardLeft = 0; 154 let boardSize = 0; 155 156 if (parentH === parentW) boardSize = parentW; 157 else if (parentW > parentH) { 158 boardSize = parentH; 159 boardLeft = Math.floor((parentW - parentH) / 2); 160 } else { 161 boardSize = parentW; 162 boardTop = Math.floor((parentH - parentW) / 2); 163 } 164 165 return {boardTop, boardLeft, boardSize} 166 }, 167 168 showNextHint: function () { 169 if (!game.showHint) return; 170 171 if (game.hintPause) { 172 game.hintPause = false; 173 fireEvent(SOUND, {sound: BALL_ROLL_SOUND}); 174 } 175 176 game.currentHint = game.levelProgress.nextHint(); 177 if (!game.currentHint) { 178 rm(HINT); 179 return; 180 } 181 182 // add new one 183 let hintDiv = get(HINT); 184 if (!hintDiv) { 185 hintDiv = document.createElement("div"); 186 hintDiv.id = HINT; 187 hintDiv.innerHTML = HINT_HTML; 188 hintDiv.style.width = (game.cellSize - 1) + "px"; 189 hintDiv.style.height = (game.cellSize - 1) + "px"; 190 get('boardScreen').appendChild(hintDiv); 191 } 192 193 hintDiv.topLeft(game.currentHint.top, game.currentHint.left); 194 195 get(HINT).setAttribute('class', game.currentHint.distance > 0 ? HIDDEN : ''); 196 setTimeout((cls)=>{get(HINT).classList.add(cls)}, 500, game.currentHint.type); 197 }, 198 199 refreshBoard: function() { 200 for(let i = 0; i < game.dimention; i++){ 201 for(let j = 0; j < game.dimention; j++){ 202 203 let parentDiv = getCell(i, j); 204 parentDiv.topLeft(i * game.cellSize, j * game.cellSize) 205 parentDiv.setAttribute('class', game.level.map[i][j]); 206 } 207 } 208 209 get(game.boardContentId).classList.remove(MOVE_IN_PROGRESS) 210 }, 211 212 addBall: function(ball) { 213 if (!ball) { 214 ball = new Ball(BOARD_CONTENT_ID, "ball", RED, game.cellSize, game.cellSize, game.cellSize, RIGHT, game.speed); 215 } 216 217 game.newBalls.unshift(ball); 218 }, 219 220 clearBalls: function() { 221 for (let i=0; i<game.balls.length; i++) { 222 rm(game.balls[i].id); 223 } 224 225 for (let j=0; j<game.newBalls.length; j++) { 226 rm(game.newBalls[j].id); 227 } 228 229 game.balls = new Array(); 230 game.newBalls = new Array(); 231 }, 232 233 startOrSpeedUp: function() { 234 if (game.frameInterval === 0) { 235 // start 236 game.start(NORMAL_GAME_INTERVAL); 237 238 fireEvent(SOUND, {sound: BALL_ROLL_SOUND}); 239 fireEvent(GAME_STATE_CHANGE, {status: STARTED}); 240 } else if (game.frameInterval > FAST_GAME_INTERVAL) { 241 // speed up 242 game.setGameInterval(FAST_GAME_INTERVAL); 243 244 fireEvent(SOUND, {sound: BALL_ROLL_FAST_SOUND}); 245 fireEvent(GAME_STATE_CHANGE, {status: FAST}); 246 } 247 }, 248 249 start: function(interval) { 250 game.setGameInterval(interval); 251 game.showNextHint(); 252 }, 253 254 setGameInterval: function (interval) { 255 if (game.gameInterval) cancelAnimationFrame(game.gameInterval); 256 game.frameInterval = interval; 257 game.lastRun = 0 258 game.gameInterval = requestAnimationFrame(game.gameFrame); 259 }, 260 261 pauseResume: function () { 262 if (game.gameInterval) { 263 cancelAnimationFrame(game.gameInterval) 264 game.gameInterval = 0; 265 get('boardScreen').classList.add(PAUSED); 266 fireEvent(VOLUME_CHANGE, {volume: 0}); 267 } else { 268 game.gameInterval = requestAnimationFrame(game.gameFrame); 269 get('boardScreen').classList.remove(PAUSED); 270 fireEvent(VOLUME_CHANGE, {volume: 1}); 271 } 272 }, 273 274 gameFrame: function (timestamp) { 275 game.gameInterval = requestAnimationFrame(game.gameFrame); 276 277 if (timestamp < (game.lastRun + game.frameInterval)) { 278 return 279 } else { 280 game.lastRun = timestamp 281 } 282 283 if (game.hintPause) { 284 return; 285 } 286 287 if (game.showHint && game.currentHint && game.currentHint.distance > 0 && game.currentHint.distance <= game.distance()) { 288 get(HINT).classList.remove(HIDDEN); 289 game.hintPause = true; 290 291 fireEvent(SOUND_OFF, {sound: BALL_ROLL_SOUND}); 292 293 return; 294 } 295 296 game.frame++; 297 298 for(let b=0; b<game.balls.length; b++) { 299 if (game.balls[b].mooving) { 300 let continueLoop = game.balls[b].moove(); 301 if (!continueLoop) break; 302 } 303 } 304 305 if (game.newBalls.length) { 306 for (let i=0; i<game.newBalls.length; i++) { 307 game.newBalls[i].show() 308 game.balls.unshift(game.newBalls[i]) 309 310 setTimeout((b)=>{ 311 b.moove() 312 }, 20, game.newBalls[i]) 313 } 314 game.newBalls = [] 315 } 316 }, 317 318 ballInPlace: function(row, col) { 319 fireEvent(SOUND, {sound: BALL_IN_PLACE_SOUND}); 320 321 // mark ceil as achieved 322 game.level.map[row][col] += ' ' + ACHIEVED 323 getCell(row, col).classList.add(ACHIEVED) 324 325 for (let i=0; i<game.balls.length; i++) { 326 // if there are at least one mooving - continue 327 if (game.balls[i].mooving) return; 328 } 329 330 // otherwise - game over successfully 331 game.over(true); 332 }, 333 334 getSecondTeleportPosition: function (ceil) {
335 const row = +ceil.getAttribute('row') 336 const col = +ceil.getAttribute('col') 337 338 for(let i = 0; i < game.dimention; i++){ 339 for(let j = 0; j < game.dimention; j++){ 340 if (game.level.map[i][j].indexOf(TELEPORT) >= 0 && !(i === row && j === col)) { 341 return {row: i, col: j} 342 } 343 } 344 } 345 346 return {row, col} 347 }, 348 349 screenStateChange: function(event) { 350 let oldState = get('boardScreen').getAttribute('state') 351 let newState = event.detail.status; 352 353 if (oldState) { 354 get('boardScreen').classList.remove(oldState) 355 } 356 357 if (newState) { 358 get('boardScreen').setAttribute('state', newState) 359 get('boardScreen').classList.add(newState) 360 } 361 362 app.log('state:' + oldState + ' -> ' + newState) 363 }, 364 365 over: function(success) { 366 cancelAnimationFrame(game.gameInterval) 367 368 get(game.boardContentId).classList.add(success ? FINISHED : FAILED) 369 370 fireEvent(SOUND, {sound: success ? LEVEL_COMPLETED_SOUND : LEVEL_FAILED_SOUND}); 371 372 setTimeout(fireEvent, 1000, GAME_OVER, {success: success, time: new Date()}); 373 }, 374 375 overHandler: function(e) { 376 rm(HINT); 377 378 let lvlState = game.levelProgress.getLevelState(true); 379 380 if (e.detail.success) { 381 const awardState = state.levelAwardState(lvlState) 382 const starsBefore = state.userStars(); 383 const solution = state.levelSolved(lvlState); 384 385 boardScreen.overHandler(e) 386 boardScreen.showEarnings(starsBefore, solution, awardState, lvlState); 387 } else { 388 boardScreen.overHandler(e) 389 } 390 }, 391 392 starCollectHandler: function(e) { 393 game.levelProgress.starCollected(); 394 }, 395 396 boardMoveHandler: function(e) { 397 game.mooves.push(e.detail); 398 game.levelProgress.nextMove(); 399 }, 400 401 cellMouseDown: function(e) { 402 let cell = e.currentTarget; 403 404 if (!cell.classList.contains(CELL) || cell.classList.contains(FIXED)) return; 405 406 let data = e.touches ? e.touches[0] : e; 407 408 game.cellMovement = new CellMove( 409 +cell.getAttribute("row"), 410 +cell.getAttribute("col"), 411 data.screenX, 412 data.screenY, 413 game.distance() 414 ); 415 416 get('boardScreen').mousemove(game.cellMouseMove); 417 get('boardScreen').mouseup(game.cellMouseUp); 418 419 e.preventDefault(); 420 return false; 421 }, 422 423 cellMouseMove: function(e) { 424 let data = e.touches ? e.touches[0] : e; 425 426 let deltaX = data.screenX - game.cellMovement.startX; 427 let deltaY = data.screenY - game.cellMovement.startY; 428 429 if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > game.minCellMove) { 430 game.cellMovement.direction = deltaX > 0 ? RIGHT : LEFT; 431 game.cellMove(); 432 } else if (Math.abs(deltaY) > Math.abs(deltaX) && Math.abs(deltaY) > game.minCellMove) { 433 game.cellMovement.direction = deltaY > 0 ? DOWN : UP; 434 game.cellMove(); 435 } 436 }, 437 438 cellMouseUp: function(e) { 439 get('boardScreen').removeMousemove(game.cellMouseMove); 440 get('boardScreen').removeMouseup(game.cellMouseUp); 441 }, 442 443 cellMove: function() { 444 game.cellMouseUp(); 445 446 const deniedCeils = game.ballAffected(game.cellMovement) || game.noPlaceToMove(game.cellMovement) 447 if (deniedCeils) { 448 if (Array.isArray(deniedCeils)) { 449 game.highlightDeniedMovement(deniedCeils) 450 451 if (deniedCeils.length == 1 && deniedCeils[0].classList.contains('fixed')) { 452 setTimeout(boardScreen.showAdvice, 0, translation('fixedAdvice')) 453 } else { 454 setTimeout(boardScreen.showAdvice, 0, translation('ballAdvice')) 455 } 456 } 457 return; 458 } 459 460 fireEvent(SOUND, {sound: CEIL_MOVE_SOUND}); 461 game.animateCellsMove(game.cellMovement); 462 463 let movementIsRight = true; 464 465 // in case hints are turned on, user should move the right cell 466 if (game.showHint && game.currentHint) { 467 movementIsRight = ( 468 (game.cellMovement.vertical() && game.cellMovement.col === game.currentHint.col) || 469 (game.cellMovement.horizontal() && game.cellMovement.row === game.currentHint.row) 470 ) && game.cellMovement.direction === game.currentHint.type; 471 } 472 473 if (movementIsRight) { 474 setTimeout(game.rearrangeCellsAfterAnimation, 200); 475 } else { 476 setTimeout(game.refreshBoard, 200); 477 } 478 }, 479 480 highlightDeniedMovement: function(ceils) { 481 fireEvent(SOUND, {sound: DENIED_SOUND}); 482 483 ceils.map(ceil => ceil.classList.add(MOVE_DENIED)) 484 485 setTimeout(game.unHighlightDeniedMovement, 1500, ceils) 486 }, 487 488 unHighlightDeniedMovement: function(ceils) { 489 ceils.map(ceil => ceil.classList.remove(MOVE_DENIED)) 490 }, 491 492 undo: function () { 493 if (game.showHint && game.currentHint) { 494 return false 495 } 496 497 let undoSet = game.levelProgress.undo() 498 let undoCell; 499 500 if (undoSet) { 501 for (let i=0; i<undoSet.length; i++) { 502 undoCell = undoSet[i] 503 game.level.map[undoCell.row][undoCell.col] = undoCell.classes; 504 } 505 506 game.refreshBoard(); 507 return true 508 } else { 509 return false 510 } 511 }, 512 513 getCellsToMove: function(cellMovement) { 514 // identify set of cells to move 515 let cellsToMove = [getCell(cellMovement.row, cellMovement.col)]; 516 let cell = null; 517 518 let horizontal = game.cellMovement.horizontal(); 519 let start = horizontal ? game.cellMovement.col : game.cellMovement.row; 520 let end = game.dimention; 521 522 for (let i=start+1; i<end; i++) { 523 cell = horizontal ? getCell(game.cellMovement.row, i) : getCell(i, game.cellMovement.col); 524 525 if (game.cellIsMovable(cell)) { 526 cellsToMove.push(cell); 527 } else { 528 break; 529 } 530 } 531 532 for (let i=start-1; i>=0; i--) { 533 cell = horizontal ? getCell(game.cellMovement.row, i) : getCell(i, game.cellMovement.col); 534 535 if (game.cellIsMovable(cell)) { 536 cellsToMove.push(cell); 537 } else { 538 break; 539 } 540 } 541 542 return cellsToMove; 543 }, 544 545 cellIsMovable: function(cell) { 546 return cell && cell.classList.contains(CELL) && !cell.classList.contains(FIXED); 547 }, 548 549 animateCellsMove: function(){ 550 get(game.boardContentId).classList.add(MOVE_IN_PROGRESS) 551 552 let cellsToMove = game.getCellsToMove(game.cellMovement); 553 let vertical = game.cellMovement.vertical(); 554 555 for (let i=0; i<cellsToMove.length; i++) { 556 cellsToMove[i].classList.add(ANIMATED_CELL) 557 if (vertical) { 558 let row = +cellsToMove[i].getAttribute('row'); 559 cellsToMove[i].top(row * game.cellSize + (game.cellSize * (game.cellMovement.direction == DOWN ? 1 : -1))); 560 } else { 561 let col = +cellsToMove[i].getAttribute('col'); 562 cellsToMove[i].left(col * game.cellSize + (game.cellSize * (game.cellMovement.direction == RIGHT ? 1 : -1))); 563 } 564 } 565 }, 566 567 rearrangeCellsAfterAnimation: function(){ 568 let cellsToMove = game.getCellsToMove(game.cellMovement); 569 let newClasses = ""; 570 571 for (let i=0; i<cellsToMove.length; i++) { 572 cellsToMove[i].classList.remove(ANIMATED_CELL) 573 } 574 575 let undo = []; 576 577 switch(game.cellMovement.direction) { 578 case UP: 579 for (let i=0; i<game.dimention; i++) { 580 if (!(cellsToMove.includes(getCell(i, game.cellMovement.col)) || cellsToMove.includes(getCell(i+1, game.cellMovement.col)))) continue; 581 582 newClasses = (i === (game.dimention-1)) ? "" : game.level.map[i+1][game.cellMovement.col]; 583 if (newClasses.indexOf(CELL) < 0 || newClasses.indexOf(FIXED) >= 0) newClasses = ""; 584 585 undo.push(new CellData(i, game.cellMovement.col, game.level.map[i][game.cellMovement.col])); 586 game.level.map[i][game.cellMovement.col] = newClasses; 587 } 588 break; 589 case DOWN: 590 for (let i=game.dimention-1; i>=0; i--) { 591 if (!(cellsToMove.includes(getCell(i, game.cellMovement.col)) || cellsToMove.includes(getCell(i-1, game.cellMovement.col)))) continue; 592 593 newClasses = (i === 0) ? "" : game.level.map[i-1][game.cellMovement.col]; 594 if (newClasses.indexOf(CELL) < 0 || newClasses.indexOf(FIXED) >= 0) newClasses = ""; 595 596 undo.push(new CellData(i, game.cellMovement.col, game.level.map[i][game.cellMovement.col])); 597 game.level.map[i][game.cellMovement.col] = newClasses; 598 } 599 break; 600 case LEFT: 601 for (let j=0; j<game.dimention; j++) { 602 if (!(cellsToMove.includes(getCell(game.cellMovement.row, j)) || cellsToMove.includes(getCell(game.cellMovement.row, j+1)))) continue; 603 604 newClasses = (j === (game.dimention-1)) ? "" : game.level.map[game.cellMovement.row][j+1]; 605 if (newClasses.indexOf(CELL) < 0 || newClasses.indexOf(FIXED) >= 0) newClasses = ""; 606 607 undo.push(new CellData(game.cellMovement.row, j, game.level.map[game.cellMovement.row][j])); 608 game.level.map[game.cellMovement.row][j] = newClasses; 609 } 610 break; 611 case RIGHT: 612 for (let j=game.dimention-1; j>=0; j--) { 613 if (!(cellsToMove.includes(getCell(game.cellMovement.row, j)) || cellsToMove.includes(getCell(game.cellMovement.row, j-1)))) continue; 614 615 newClasses = (j === 0) ? "" : game.level.map[game.cellMovement.row][j-1]; 616 if (newClasses.indexOf(CELL) < 0 || newClasses.indexOf(FIXED) >= 0) newClasses = ""; 617 618 undo.push(new CellData(game.cellMovement.row, j, game.level.map[game.cellMovement.row][j])); 619 game.level.map[game.cellMovement.row][j] = newClasses; 620 } 621 break; 622 } 623 624 game.levelProgress.addUndo(undo); 625 game.refreshBoard(); 626 627 fireEvent(BOARD_MOVE, game.cellMovement); 628 629 if (game.showHint) { 630 game.showNextHint(); 631 } 632 }, 633 634 animateCellsReset: function() { 635 let boardShouldBe = clone(levels[state.mode.current][state.package.current].levels[state.level.current]).map; 636 for (let i=0; i<game.level.map.length; i++) { 637 for (let j=0; j<game.level.map[i].length; j++) { 638 let parentDiv = getCell(i, j); 639 640 let result = game.findCellResetPosition(parentDiv.getAttribute('class'), boardShouldBe); 641 642 boardShouldBe = result.boardShouldBe; 643 644 parentDiv.classList.add(ANIMATED_CELL); 645 parentDiv.top(result.newi * game.cellSize); 646 parentDiv.left(result.newj * game.cellSize); 647 } 648 } 649 }, 650
651 findCellResetPosition: function(classes, targetArray) { 652 let cls1 = game.clearClasses(classes) 653 for (let i=0; i<targetArray.length; i++) { 654 for (let j=0; j<targetArray[i].length; j++) { 655 let cls2 = game.clearClasses(targetArray[i][j]) 656 657 if (cls1 === cls2) { 658 targetArray[i][j] = "-"; 659 return {newi: i, newj: j, boardShouldBe: targetArray} 660 } 661 } 662 } 663 }, 664 665 clearClasses: function(classes) { 666 return game.clearClass( 667 game.clearClass( 668 game.clearClass(classes, 'star'), 'involved'), '-') 669 }, 670 671 clearClass: function(classes, cls) { 672 return classes 673 .replace(' ' + cls,'') 674 .replace(cls + ' ','') 675 .replace(cls,'') 676 }, 677 678 ballAffected: function(cellMove) { 679 let isAffected = false 680 681 const allBalls = [...game.balls, ...game.newBalls]; 682 for (let b=0; b<allBalls.length; b++) { 683 const ball = allBalls[b] 684 if (ball.finished) continue 685 686 const hoverRowCols = ball.hoverRowCols() 687 688 const emptyInBetween = game.emptyBetweenClickAndBall(cellMove, hoverRowCols) 689 690 if (cellMove.direction == UP || cellMove.direction == DOWN) { 691 isAffected = !emptyInBetween && game.isBallCol(+cellMove.col, hoverRowCols); 692 } else { 693 isAffected = !emptyInBetween && game.isBallRow(+cellMove.row, hoverRowCols); 694 } 695 696 if (isAffected) return isAffected 697 } 698 699 return isAffected 700 }, 701 702 isBallCol: function(col, rowCols) { 703 const allBalls = [...game.balls, ...game.newBalls]; 704 for (let b=0; b<allBalls.length; b++) { 705 let ball = allBalls[b] 706 if (ball.finished) continue; 707 708 //let rowCols = ball.hoverRowCols(); 709 for (let c=0; c<rowCols.cols.length; c++) { 710 if (rowCols.cols[c] === col) return ball.hoverCells(rowCols).cells; 711 } 712 } 713 714 return false; 715 }, 716 717 isBallRow: function(row, rowCols) { 718 const allBalls = [...game.balls, ...game.newBalls]; 719 for (let b=0; b<allBalls.length; b++) { 720 let ball = allBalls[b] 721 if (ball.finished) continue; 722 723 //let rowCols = ball.hoverRowCols(); 724 for (let r=0; r<rowCols.rows.length; r++) { 725 if (rowCols.rows[r] === row) return ball.hoverCells(rowCols).cells; 726 } 727 } 728 729 return false; 730 }, 731 732 emptyBetweenClickAndBall: function (cellMove, hoverRowCols) { 733 if (cellMove.direction == UP || cellMove.direction == DOWN) { 734 let from = Math.min(hoverRowCols.rows[0], cellMove.row); 735 let to = Math.max(hoverRowCols.rows[0], cellMove.row); 736 737 if (from === to) return false; 738 739 for (let row=from+1; row<to; row++) { 740 let cellClasses = game.level.map[row][cellMove.col]; 741 if (cellClasses.indexOf(CELL) < 0 || cellClasses.indexOf(FIXED) > 0) return true; 742 } 743 744 return false; 745 } else { 746 let from = Math.min(hoverRowCols.cols[0], cellMove.col); 747 let to = Math.max(hoverRowCols.cols[0], cellMove.col); 748 749 if (from === to) return false; 750 751 for (let col=from+1; col<to; col++) { 752 let cellClasses = game.level.map[cellMove.row][col]; 753 if (cellClasses.indexOf(CELL) < 0 || cellClasses.indexOf(FIXED) > 0) return true; 754 } 755 756 return false; 757 } 758 }, 759 760 noPlaceToMove: function(cellMove) { 761 if (cellMove.direction == UP) { 762 for (let i=cellMove.row-1; i>=0; i--) { 763 if (!getCell(i, cellMove.col)) return false; 764 else if (getCell(i, cellMove.col).classList.contains('fixed')) return [getCell(i, cellMove.col)]; 765 else if (!getCell(i, cellMove.col).classList.contains('cell')) return false; 766 } 767 } else if (cellMove.direction == DOWN) { 768 for (let i=cellMove.row+1; i<game.dimention; i++) { 769 if (!getCell(i, cellMove.col)) return false; 770 else if (getCell(i, cellMove.col).classList.contains('fixed')) return [getCell(i, cellMove.col)]; 771 else if (!getCell(i, cellMove.col).classList.contains('cell')) return false; 772 } 773 } else if (game.cellMovement.direction == RIGHT) { 774 for (let j=cellMove.col+1; j<game.dimention; j++) { 775 if (!getCell(cellMove.row, j)) return false; 776 else if (getCell(cellMove.row, j).classList.contains('fixed')) return [getCell(cellMove.row, j)]; 777 else if (!getCell(cellMove.row, j).classList.contains('cell')) return false; 778 } 779 } else { 780 for (let j=cellMove.col-1; j>=0; j--) { 781 if (!getCell(cellMove.row, j)) return false; 782 else if (getCell(cellMove.row, j).classList.contains('fixed')) return [getCell(cellMove.row, j)]; 783 else if (!getCell(cellMove.row, j).classList.contains('cell')) return false; 784 } 785 } 786 787 return true 788 } 789}; 790 791window.addEventListener(GAME_OVER, game.overHandler); 792window.addEventListener(GAME_STATE_CHANGE, game.screenStateChange); 793window.addEventListener(STAR_COLLECTED, game.starCollectHandler); 794window.addEventListener(BOARD_MOVE, game.boardMoveHandler);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.