BangleApps/apps/waternet/app.js

2680 lines
75 KiB
JavaScript

// --------------------------------------------------------------------------------------------------
// images
// --------------------------------------------------------------------------------------------------
const blockTiles = {
width : 8, height : 8, bpp : 1,
buffer : atob("JCTnAADnJCQAAP8AAOckJCQk5AQE5CQkAAD8BATkJCQkJOcAAP8AAAAA/wAA/wAAJCTkBAT8AAAAAPwEBPwAACQkJyAgJyQkAAA/ICAnJCQkJCQkJCQkJAAAPCQkJCQkJCQnICA/AAAAAD8gID8AACQkJCQkPAAAAAA8JCQ8AAA8PP////88PAAA/////zw8PDz8/Pz8PDwAAPz8/Pw8PDw8/////wAAAAD/////AAA8PPz8/PwAAAAA/Pz8/AAAPDw/Pz8/PDwAAD8/Pz88PDw8PDw8PDw8AAA8PDw8PDw8PD8/Pz8AAAAAPz8/PwAAPDw8PDw8AAAAADw8PDwAADx+/////348AH7/////fjw8fv7+/v5+PAB+/v7+/n48PH7/////fgAAfv////9+ADx+/v7+/n4AAH7+/v7+fgA8fn9/f39+PAB+f39/f348PH5+fn5+fjwAfn5+fn5+PDx+f39/f34AAH5/f39/fgA8fn5+fn5+AAB+fn5+fn4AAAAAAAAAAADMzDMzzMwzMwD/MzPMzDMzzs4yMs7OMjLMzDMzzMz/AExMc3NMTHNzAH9zc0xMc3MA/jIyzs4yMs7OMjLOzv4ATExzc0xMfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAQEBAQEBAQH/AQEBAQEBAQAAAAAAAAD//wAAAAAAAP8BAQEBAQEB//8BAQEBAQH/gICAgICAgID/gICAgICAgIGBgYGBgYGB/4GBgYGBgYGAgICAgICA//+AgICAgID/gYGBgYGBgf8AAAAAAAAAAMAiROgWIUIHQEJESBYhQgcAAAAAAAAAADx+ZmZmfjwAGBgYGBgYGAB8fAx8YHx8AHx8DHwMfHwADBw8bHwMDAB8fGB8DHx8AGBgfHxsfHwAfHwMGDAwMAB8fGx8bHx8AHx8bHwMfHwAfn5mfn5mZgB8fmZsZn58AHx8YGBgfHwAeHxmZmZ8eAB8fGB8YHx8AHx8YHh4YGAAPn5gbmZ+PABsbHx8bGxsABgYGBgYGBgAPj4MDGx8OABubnx8fG5uAGBgYGBgfHwAQWN3f2tjYwBmdn5uZmZmADh8bGxsfDgAeHxsfHhgYAA8fmZmZn4+AHh8bGx4bGwAPHxwOAx8eAB+fhgYGBgYAGxsbGxsfHwAbGxsbGx8OABjY2Nja382AGZmfhh+ZmYAZmZ+PBgYGAB8fAwYMHx8AAAwMAAwMAAAPEZaRlpGPAAIBPIBAfIECDxmWkJaWjwAfufDgefn535+9/OBgfP3fn7n5+eBw+d+fu/PgYHP7348bk5ubkY8ADxOdm5eRjwA")
};
const congratsTiles = {
width : 8, height : 8, bpp : 1,
buffer : atob("PCQkJDwkJAA4JCQoJCQ4ADwgICAgIDwAOCQkJCQkOAA8ICA8ICA8ADwgIDggICAAHCAgLCQkHAAkJCQ8JCQkABAQEBAQEBAAHAgICAgoEAAkJCgwKCQkACAgICAgIDwAIjYqIiIiIgAkNCwkJCQkABgkJCQkJBgAOCQkJDggIAAYJCQkJCQcADgkJCQ4JCQAHCAgGAQEOAA+CAgICAgIACQkJCQkJDwAJCQkJCQkGAAiIiIiKjYiACQkJBgkJCQAIiIUHAgICAA8BAwYMCA8AAAAAAAAAAAA")
};
const congratsScreen= {
width : 128, height : 64, bpp : 1,
buffer : atob("AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAADAAAwAAAAAA/gAAAAAAHAAwAOMAAAAAAMYcBgYDDBwAMGDgBgEAAADAPj8Pjz4+ZjHx4w8Px8AAwGY7H443HGYxuOMZjsfAAMBmMxmMHxxmMPjjGYzGAADGZjMZjD8cZjH44xmMx8AA5mYzGYx3HGYzuOMZjMDAAH5+Mx+MPx5+MfjjH4zHwAA8PDMPjD8MOjHYYw8Mx8AAAAAAA4AAAAAAAAAAAAAAAAAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiGCQAPCA8PDg8OAA+JDwAIiQkACAgICQkICQACCQgABQkJAAgICAkJCAkAAgkIAAcJCQAICA8JCQ8JAAIPDwACCQkACAgIDw4ICQACCQgAAgkJAAgICAkJCAkAAgkIAAIGDwAPDw8JCQ8OAAIJDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4HAAAAAAAAAAAAAAAAAAAOBwAAAAAAAAAAAAMAAAAADgcAAAAAAAAAAAAHgAAAAA4HAAAAAAAABgAADMAAAAAPDwAAAAAAAA8GABhAAAAADw8AAAYAAAAZjwARYAAAAAeeAAAPAAAAEJmAESAAAAAHngAAGYAAADLSwBCgBgAAA/wAABLAAAAhckAQIA8AAAP8AAAyQAAAIWFAECAZgAAB+AAAIUABgCBgQBAgEIAAAfgAACBAA8AgYEAQIDLAAACQAAAgQAZgIGBAGGAhQAAB+AAAIEAMICBgQAhAIUAABw4AACBACLAwYEAMwCBAAAwDAAAgQAiQEPBAB4AgQAAYAYAAIMAIUBmQwAMAIEAAEGCAADCACBAPGYADACBAADDgwAAZgAgQBg8AAgAgwAAgYEAADwAIEAYGAAIAMIAAIGBAAAYACBAEBgABABmAACBgQAAGAAwwBAQAAQAPAAAg8EAABAAEIAIEAAEABgAAMPDAAAQABmACAgABgAYAABAAgAACAAPAAgIAAIAEAAAYAYAAAgABgAMCAAAABAAADAMAAAIAAYABAwAAAAIAAAcOAAADAAEAAAEAAAACAAAB+AAAAQABAAAAAAAAAgAAAAAAAAAAAIAAA==")
};
const selectorTiles = {
width : 8, height : 8, bpp : 1,
transparent : 0,
buffer : atob("AAAAAAAAgYHAAAAAAAAAwIGBAAAAAAAAAwAAAAAAAAMAAAAAAACAwMCAAAAAAAAAAAAAAAAAAQMDAQAAAAAAAA==")
};
const title = {
width : 128, height : 40, bpp : 1,
buffer : atob("AAAAAAAAAAAAAAAAAAAAAAAHh8HAAAAAAAAAAAAAAAAAD4fDwAAAAAAAAAAAPAAAAA+Hw8AA+AAAAAAAAHwAAAAPj8PAAPwAAAAAAAD8AAAAD4/Dw/n8Hwc7n4H4/gAAAA+Pw8f//3+He7/H/f+AAAAHj8OP//5/x/v/z/3/YAAAB8/Hj/38/+fz/8///iAAAAPO54w8+PHn4+PPHvwwAAADzOeAPPDx58PDzx54MAAAA/x/h/zw/+eDw8/+eCAAAAP8fw/88P/nh8PP/nhgAAAD/H4PHPDwB4/HzwB4wAAAAfx+Hhzw8AePx88AeMAAAAH4fh/8/v/Hj8fP/nzAAAAB+H4f/P7/x4/Hz/7+wAAAAfD+H/x+/8ePx8f+/sAAAADA+BwAYGAGDwcHAGBgAAAAQNg2AHBwDg2FhYB5IAAAAGCIMwDY/A8JxczAz+AAAAAhBOPjnIY5kMzY447gAAAAHgOAfgMB4OB4cB4PAAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAfwAAAAAAAAAAAAAAAAAAAH+AAAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAAAAAAAAAAH/gAAAAAAAAAAAAAAAAAAA7wAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAA==")
};
// --------------------------------------------------------------------------------------------------
// global variables and consts
// --------------------------------------------------------------------------------------------------
//need to call this first otherwise
//Bangle.apprect is not updated and i can't calculate screenoffsety
Bangle.loadWidgets();
const debugMode = 0;
const debugModeRamUse = 0;
const scaleScreen = 1;
const screenWidth = 176;
const screenHeight = 176;
const screenOffsetX = ((screenWidth - 16 * 8) >> 1);
const screenOffsetY = ((screenHeight + Bangle.appRect.y - 8 * 8) >> 1);
const maxBoardWidth = 10;
const maxBoardHeight = 8;
const maxBoardBgWidth = 10;
const maxBoardBgHeight = 8;
const maxBoardSize = maxBoardWidth * maxBoardHeight;
const tileSize = 8;
const gsGame = 0;
const gsTitle = 1;
const gsLevelSelect = 2;
const gsLevelsCleared = 3;
const gsHelpRotate = 4;
const gsHelpRotate2 = 5;
const gsHelpRotate3 = 6;
const gsHelpRotateSlide = 7;
const gsHelpRotateSlide2 = 8;
const gsHelpRotateSlide3 = 9;
const gsHelpRotateSlide4 = 10;
const gsHelpSlide = 11;
const gsHelpSlide2 = 12;
const gsHelpSlide3 = 13;
const gsIntro = 14;
const gsInitDiff = 50;
const gsInitGame = gsInitDiff + gsGame;
const gsInitTitle = gsInitDiff + gsTitle;
const gsInitLevelSelect = gsInitDiff + gsLevelSelect;
const gsInitLevelsCleared = gsInitDiff + gsLevelsCleared;
const gsInitHelpRotate = gsInitDiff + gsHelpRotate;
const gsInitHelpRotate2 = gsInitDiff + gsHelpRotate2;
const gsInitHelpRotate3 = gsInitDiff + gsHelpRotate3;
const gsInitHelpRotateSlide = gsInitDiff + gsHelpRotateSlide;
const gsInitHelpRotateSlide2 = gsInitDiff + gsHelpRotateSlide2;
const gsInitHelpRotateSlide3 = gsInitDiff + gsHelpRotateSlide3;
const gsInitHelpRotateSlide4 = gsInitDiff + gsHelpRotateSlide4;
const gsInitHelpSlide = gsInitDiff + gsHelpSlide;
const gsInitHelpSlide2 = gsInitDiff + gsHelpSlide2;
const gsInitHelpSlide3 = gsInitDiff + gsHelpSlide3;
const gsInitIntro = gsInitDiff + gsIntro;
const diffVeryEasy = 0;
const diffEasy = 1;
const diffNormal = 2;
const diffHard = 3;
const diffVeryHard = 4;
const diffRandom = 5;
const diffCount = 6;
const gmRotate = 0;
const gmSlide = 1;
const gmRotateSlide = 2;
const gmCount = 3;
const mmStartGame = 0;
const mmHelp = 1;
const mmOptions = 2;
const mmCredits = 3;
const mmCount = 4;
const opMusic = 0;
const opSound = 1;
const opCount = 2;
const tsMainMenu = 0;
const tsGameMode = 1;
const tsDifficulty = 2;
const tsOptions = 3;
const tsCredits = 4;
const levelCount = 25;
const arrowDown = 122;
const arrowUp = 120;
const arrowLeft = 123;
const arrowRight = 121;
const leftMenu = 118;
const frameRate = 15;
var startPos;
var menuPos;
var maxLevel;
var selectedLevel;
var boardX;
var boardY;
var difficulty;
var gameState;
var boardWidth;
var boardHeight;
var boardSize;
var levelDone;
var titleStep;
var gameMode;
var posAdd;
var mainMenu;
var option;
var needRedraw;
var requiresFlip;
var selectionX, selectionY;
var moves;
var randomSeedGame;
var level = new Uint8Array(maxBoardSize);
// Cursor
const maxCursorFrameCount = (10 * frameRate / 60);
const cursorAnimCount = 2; //blink on & off
const cursorNumTiles = 16; //for the max 2 cursors shown at once (on help screens)
var cursorFrameCount, cursorFrame, showCursor;
var spritePos = [];
for (var i = 0; i <cursorNumTiles; i++)
spritePos.push(new Uint8Array(2));
//intro
var frames;
var titlePosY;
const frameDelay = 16 * frameRate / 15;
//savestate
const soundOptionBit = 0;
const musicOptionBit = 1;
var levelLocks = new Uint8Array(gmCount * diffCount);
var options = new Uint8Array(2);
//game
var paused;
var wasMusicOn;
var wasSoundOn;
var redrawLevelDoneBit;
var currentTiles = {};
//general input
var dragleft = false;
var dragright = false;
var dragup = false;
var dragdown = false;
var btna = false;
var btnb = false;
// --------------------------------------------------------------------------------------------------
// random stuff
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript
// --------------------------------------------------------------------------------------------------
var randfunc;
Math.imul = Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
// the shift by 0 fixes the sign on the high part
// the final |0 converts the unsigned value into a signed value
return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
};
function cyrb128(str) {
let h1 = 1779033703, h2 = 3144134277,
h3 = 1013904242, h4 = 2773480762;
for (let i = 0, k; i < str.length; i++) {
k = str.charCodeAt(i);
h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
}
h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
h1 ^= (h2 ^ h3 ^ h4);
h2 ^= h1;
h3 ^= h1;
h4 ^= h1;
return [h1>>>0, h2>>>0, h3>>>0, h4>>>0];
}
//based on code from pracrand https://pracrand.sourceforge.net/ (public domain)
function sfc32(a, b, c, d) {
return function() {
a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0;
var t = (a + b) | 0;
a = b ^ b >>> 9;
b = c + (c << 3) | 0;
c = (c << 21 | c >>> 11);
d = d + 1 | 0;
t = t + d | 0;
c = c + t | 0;
return (t >>> 0) / 4294967296;
};
}
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(randfunc() * (max - min + 1) + min);
}
function srand(seed)
{
// Create cyrb128 state:
var aseed = cyrb128("applespairs" + seed.toString());
// Four 32-bit component hashes provide the seed for sfc32.
randfunc = sfc32(aseed[0], aseed[1], aseed[2], aseed[3]);
}
function random(value)
{
return randomIntFromInterval(0,value-1);
}
// --------------------------------------------------------------------------------------------------
// Cursor stuff
// --------------------------------------------------------------------------------------------------
function move_sprite(sprite, x, y)
{
spritePos[sprite][0] = x;
spritePos[sprite][1] = y;
}
function drawCursors()
{
if((showCursor == 0) || (cursorFrame & 1)) // 2nd or to add blink effect, it will skip drawing if bit 1 is set
return;
g.setColor(1,0,0);
for (var i=0; i<cursorNumTiles; i++)
if (spritePos[i][1] < screenHeight)
g.drawImage(selectorTiles,screenOffsetX + spritePos[i][0], screenOffsetY + spritePos[i][1], {frame: ((i % 8) )});
g.setColor(1,1,1);
}
//returns 1 if cursor has changed / needs redraw
function updateCursorFrame()
{
cursorFrameCount++;
if (cursorFrameCount >= maxCursorFrameCount)
{
cursorFrame++;
cursorFrameCount = 0;
if (cursorFrame >= cursorAnimCount)
cursorFrame = 0;
return 1;
}
return 0;
}
function hideCursors()
{
//HIDE CURSOR SPRITES
//cursor 0
setCursorPos(0, 0, (screenHeight / 8) + 1);
//cursor 1
setCursorPos(1, 0, (screenHeight / 8) + 1);
showCursor = 0;
}
function showCursors()
{
showCursor = 1;
}
function setCursorPos(cursorNr, xPos, yPos)
{
if (cursorNr > 1)
return;
move_sprite((cursorNr<<3) + 0, ((xPos) << 3), ((yPos - 1) << 3));
move_sprite((cursorNr<<3) + 1, ((xPos + 1) << 3), ((yPos) << 3));
move_sprite((cursorNr<<3) + 2, ((xPos) << 3), ((yPos + 1) << 3));
move_sprite((cursorNr<<3) + 3, ((xPos - 1) << 3), ((yPos) << 3));
//corners
move_sprite((cursorNr<<3) + 4, ((xPos + 1) << 3), ((yPos - 1) << 3));
move_sprite((cursorNr<<3) + 5, ((xPos + 1) << 3), ((yPos + 1) << 3));
move_sprite((cursorNr<<3) + 6, ((xPos - 1) << 3), ((yPos - 1) << 3));
move_sprite((cursorNr<<3) + 7, ((xPos - 1) << 3), ((yPos + 1) << 3));
}
function initCursors()
{
hideCursors();
cursorFrameCount = 0;
cursorFrame = 0;
}
// --------------------------------------------------------------------------------------------------
// helper funcs
// --------------------------------------------------------------------------------------------------
function set_bkg_tile_xy(x, y, tile)
{
g.drawImage(currentTiles, screenOffsetX + x *8, screenOffsetY + y*8, {frame:tile}); //arduboy.drawBitmap(x * 8, y * 8, &currentTiles[2 + (tile * 8)] , 8, 8);
}
function set_bkg_data(tiles)
{
currentTiles = tiles;
}
function get_bkg_data()
{
return currentTiles;
}
function set_bkg_tiles(x, y, map)
{
g.drawImage(map, screenOffsetX + x, screenOffsetY + y); //arduboy.drawBitmap(x, y, &map[2], pgm_read_byte(&map[0]), pgm_read_byte(&map[1]));
}
function setBlockTilesAsBackground()
{
set_bkg_data(blockTiles);
}
// --------------------------------------------------------------------------------------------------
// help screens
// --------------------------------------------------------------------------------------------------
//LEGEND STATE
function inithelpLegend()
{
setBlockTilesAsBackground();
//SelectMusic(musTitle);
needRedraw = 1;
}
//LEGEND STATE
function helpLegend(nextState)
{
if ((gameState == gsInitHelpSlide) ||
(gameState == gsInitHelpRotate) ||
(gameState == gsInitHelpRotateSlide))
{
inithelpLegend();
gameState -= gsInitDiff;
}
if (needRedraw)
{
g.clearRect(Bangle.appRect);
switch(gameState)
{
case gsHelpSlide:
printMessage(2, 0, "HELP: SLIDE");
break;
case gsHelpRotate:
printMessage(2, 0, "HELP: ROTATE");
break;
case gsHelpRotateSlide:
printMessage(2, 0, "HELP: ROSLID");
break;
}
set_bkg_tile_xy(0, 1, 33);
printMessage(1, 1, ":WATER SOURCE");
set_bkg_tile_xy(0, 2, 11);
set_bkg_tile_xy(1, 2, 6);
set_bkg_tile_xy(2, 2, 12);
printMessage(3, 2, ":NOT FILLED");
set_bkg_tile_xy(0, 3, 27);
set_bkg_tile_xy(1, 3, 22);
set_bkg_tile_xy(2, 3, 28);
printMessage(3, 3, ":FILLED");
if((gameState == gsHelpRotateSlide) ||
(gameState == gsHelpSlide))
{
set_bkg_tile_xy(0, 4, 121);
printMessage(1, 4, ":SLID ROW RIGHT");
set_bkg_tile_xy(0, 5, 123);
printMessage(1, 5, ":SLID ROW LEFT");
set_bkg_tile_xy(0, 6, 122);
printMessage(1, 6, ":SLID COL DOWN");
set_bkg_tile_xy(0, 7, 120);
printMessage(1, 7, ":SLID COL UP");
}
needRedraw = 0;
requiresFlip = 1;
}
if (btna)
{
//playMenuAcknowlege();
gameState = nextState;
}
}
//FINISH LEVEL STATE
function initHelpFinishLevel()
{
setBlockTilesAsBackground();
//SelectMusic(musTitle);
needRedraw = 1;
}
//FINISH LEVEL STATE
function helpFinishLevel(nextState)
{
if ((gameState == gsInitHelpSlide2) ||
(gameState == gsInitHelpRotate2) ||
(gameState == gsInitHelpRotateSlide2))
{
initHelpFinishLevel();
gameState -= gsInitDiff;
}
if(needRedraw)
{
g.clearRect(Bangle.appRect);
switch(gameState)
{
case gsHelpSlide2:
printMessage(2, 0, "HELP: SLIDE");
break;
case gsHelpRotate2:
printMessage(2, 0, "HELP: ROTATE");
break;
case gsHelpRotateSlide2:
printMessage(2, 0, "HELP: ROSLID");
break;
}
printMessage(0, 2, "LEVEL FINISH:");
if((gameState == gsHelpSlide2) ||
(gameState == gsHelpRotateSlide2))
{
//arrows top
set_bkg_tile_xy(2, 3, 122);
set_bkg_tile_xy(3, 3, 122);
set_bkg_tile_xy(4, 3, 122);
//arrows left / right row 1
set_bkg_tile_xy(1, 4, 121);
set_bkg_tile_xy(5, 4, 123);
//arrows left / right row 2
set_bkg_tile_xy(1, 5, 121);
set_bkg_tile_xy(5, 5, 123);
//arrows left / right row 3
set_bkg_tile_xy(1, 6, 121);
set_bkg_tile_xy(5, 6, 123);
//arrows bottom
set_bkg_tile_xy(2, 7, 120);
set_bkg_tile_xy(3, 7, 120);
set_bkg_tile_xy(4, 7, 120);
}
set_bkg_tile_xy(2, 4, 25);
set_bkg_tile_xy(3, 4, 23);
set_bkg_tile_xy(4, 4, 27);
printMessage(7, 4, "ALL WATER");
set_bkg_tile_xy(2, 5, 28);
set_bkg_tile_xy(3, 5, 33);
set_bkg_tile_xy(4, 5, 22);
printMessage(7, 5, "PIPES ARE");
set_bkg_tile_xy(2, 6, 29);
set_bkg_tile_xy(3, 6, 20);
set_bkg_tile_xy(4, 6, 23);
printMessage(7, 6, "FILLED");
needRedraw = 0;
requiresFlip = 1;
}
if (btna)
{
//playMenuAcknowlege();
gameState = nextState;
}
}
function initHelpDoSlideRotate()
{
setBlockTilesAsBackground();
//SelectMusic(musTitle);
//DRAW CURSOR SPRITES
initCursors();
if((gameState == gsInitHelpRotateSlide4) ||
(gameState == gsInitHelpSlide3))
{
setCursorPos(0, 0, 5);
setCursorPos(1, 11, 5);
}
else
{
setCursorPos(0, 1, 4);
setCursorPos(1, 12, 4);
}
showCursors();
needRedraw = 1;
}
function helpDoSlideRotate(nextState)
{
if ((gameState == gsInitHelpSlide3) ||
(gameState == gsInitHelpRotate3) ||
(gameState == gsInitHelpRotateSlide3) ||
(gameState == gsInitHelpRotateSlide4))
{
initHelpDoSlideRotate();
gameState -= gsInitDiff;
}
if(needRedraw)
{
g.clearRect(Bangle.appRect);
switch(gameState)
{
case gsHelpSlide3:
printMessage(2, 0, "HELP: SLIDE");
break;
case gsHelpRotate3:
printMessage(2, 0, "HELP: ROTATE");
break;
case gsHelpRotateSlide3:
case gsHelpRotateSlide4:
printMessage(2, 0, "HELP: ROSLID");
break;
}
if((gameState == gsHelpRotateSlide3) ||
(gameState == gsHelpRotate3))
printMessage(5, 2, "ROTATE");
else
printMessage(6, 2, "SLIDE");
// 'A' + '=>'
set_bkg_tile_xy(6, 5, 119);
printMessage(5, 5, "TOUCH");
set_bkg_tile_xy(10, 5, 118);
if((gameState == gsHelpSlide3) ||
(gameState == gsHelpRotateSlide3) ||
(gameState == gsHelpRotateSlide4))
{
//Top Arrows
set_bkg_tile_xy(1, 3, 122);
set_bkg_tile_xy(2, 3, 122);
set_bkg_tile_xy(3, 3, 122);
//arrows 1st row
set_bkg_tile_xy(0, 4, 121);
set_bkg_tile_xy(4, 4, 123);
//arrows 2nd row
set_bkg_tile_xy(0, 5, 121);
set_bkg_tile_xy(4, 5, 123);
//arrows 3rd row
set_bkg_tile_xy(0, 6, 121);
set_bkg_tile_xy(4, 6, 123);
//arrows bottom
set_bkg_tile_xy(1, 7, 120);
set_bkg_tile_xy(2, 7, 120);
set_bkg_tile_xy(3, 7, 120);
//2nd grid
//Top Arrows
set_bkg_tile_xy(12, 3, 122);
set_bkg_tile_xy(13, 3, 122);
set_bkg_tile_xy(14, 3, 122);
//arrows 1st row
set_bkg_tile_xy(11, 4, 121);
set_bkg_tile_xy(15, 4, 123);
//arrows 2nd row
set_bkg_tile_xy(11, 5, 121);
set_bkg_tile_xy(15, 5, 123);
//arrows 3rd row
set_bkg_tile_xy(11, 6, 121);
set_bkg_tile_xy(15, 6, 123);
//bottoms arrows
set_bkg_tile_xy(12, 7, 120);
set_bkg_tile_xy(13, 7, 120);
set_bkg_tile_xy(14, 7, 120);
}
//1st grid
if ((gameState == gsHelpRotate3) ||
(gameState == gsHelpRotateSlide3))
{
set_bkg_tile_xy(1, 4, 12);
set_bkg_tile_xy(2, 4, 7);
set_bkg_tile_xy(3, 4, 27);
set_bkg_tile_xy(1, 5, 28);
set_bkg_tile_xy(2, 5, 33);
set_bkg_tile_xy(3, 5, 22);
set_bkg_tile_xy(1, 6, 29);
set_bkg_tile_xy(2, 6, 20);
set_bkg_tile_xy(3, 6, 23);
}
else
{
set_bkg_tile_xy(1, 4, 9);
set_bkg_tile_xy(2, 4, 7);
set_bkg_tile_xy(3, 4, 11);
set_bkg_tile_xy(1, 5, 17);
set_bkg_tile_xy(2, 5, 38);
set_bkg_tile_xy(3, 5, 12);
set_bkg_tile_xy(1, 6, 13);
set_bkg_tile_xy(2, 6, 4);
set_bkg_tile_xy(3, 6, 7);
}
//2nd grid
set_bkg_tile_xy(12, 4, 25);
set_bkg_tile_xy(13, 4, 23);
set_bkg_tile_xy(14, 4, 27);
set_bkg_tile_xy(12, 5, 28);
set_bkg_tile_xy(13, 5, 33);
set_bkg_tile_xy(14, 5, 22);
set_bkg_tile_xy(12, 6, 29);
set_bkg_tile_xy(13, 6, 20);
set_bkg_tile_xy(14, 6, 23);
drawCursors();
needRedraw = 0;
requiresFlip = 1;
}
//needRedraw = updateCursorFrame();
if (btna)
{
//playMenuAcknowlege();
gameState = nextState;
hideCursors();
}
}
//LEGEND STATE
function helpRotateSlide()
{
helpLegend(gsInitHelpRotateSlide2);
}
//FINISH LEVEL STATE
function helpRotateSlide2()
{
helpFinishLevel(gsInitHelpRotateSlide3);
}
//SLIDE STATE
function helpRotateSlide3()
{
helpDoSlideRotate(gsInitHelpRotateSlide4);
}
//ROTATE STATE
function helpRotateSlide4()
{
helpDoSlideRotate(gsInitTitle);
}
function helpRotate()
{
helpLegend(gsInitHelpRotate2);
}
//FINISH LEVEL STATE
function helpRotate2()
{
helpFinishLevel(gsInitHelpRotate3);
}
//ROTATE STATE
function helpRotate3()
{
helpDoSlideRotate(gsInitTitle);
}
//LEGEND STATE
function helpSlide()
{
helpLegend(gsInitHelpSlide2);
}
//FINISH LEVEL STATE
function helpSlide2()
{
helpFinishLevel(gsInitHelpSlide3);
}
//SLIDE STATE
function helpSlide3()
{
helpDoSlideRotate(gsInitTitle);
}
// --------------------------------------------------------------------------------------------------
// Intro
// --------------------------------------------------------------------------------------------------
function initIntro()
{
setBlockTilesAsBackground();
titlePosY = g.getHeight();
frames = 0;
}
function intro()
{
if (gameState == gsInitIntro)
{
initIntro();
gameState -= gsInitDiff;
}
frames++;
g.clearRect(Bangle.appRect);
if (frames < frameDelay)
{
//16-12
printMessage(4 >> 1, 4, "WILLEMS DAVY");
requiresFlip = 1;
}
else
{
if (frames < frameDelay *2)
{
//16-8
printMessage(8 >> 1, 4, "PRESENTS");
requiresFlip = 1;
}
else
{
requiresFlip = 1;
g.drawImage(title, screenOffsetX, titlePosY);//arduboy.drawCompressed(0, (uint16_t)titlePosY, titlescreenMap);
if(titlePosY > screenOffsetY)
{
titlePosY -= 60/frameRate;
}
else
{
gameState = gsInitTitle;
}
}
}
if (btna || btnb)
{
gameState = gsInitTitle;
}
}
// --------------------------------------------------------------------------------------------------
// Level Stuff
// --------------------------------------------------------------------------------------------------
function moveBlockDown(aTile)
{
var tmp = level[aTile + boardSize - boardWidth];
for (var i= boardSize - boardWidth; i != 0 ; i -= boardWidth)
level[aTile + i] = level[aTile + i -boardWidth];
level[aTile] = tmp;
}
function moveBlockUp(aTile)
{
var tmp = level[aTile - boardSize + boardWidth];
for (var i= boardSize - boardWidth; i != 0; i -= boardWidth)
level[aTile - i] = level[aTile - i + boardWidth];
level[aTile] = tmp;
}
function moveBlockRight(aTile)
{
var tmp = level[aTile + boardWidth - 1];
for (var i= 0; i < boardWidth -1; i++)
level[aTile + boardWidth - 1 - i] = level[aTile + boardWidth - 2 - i];
level[aTile] = tmp;
}
function moveBlockLeft(aTile)
{
var tmp = level[aTile - boardWidth + 1];
for (var i= 0; i < boardWidth-1; i++)
level[aTile - boardWidth + 1 + i] = level[aTile - boardWidth + 2 + i];
level[aTile] = tmp;
}
//rotates a tile by change the tilenr in the level
//there are 16 tiles per set and there are 3 sets no water, water filled, and special start tiles
function rotateBlock(aTile)
{
switch (level[aTile])
{
case 1:
case 17:
case 33:
level[aTile] = 2;
break;
case 2:
case 18:
case 34:
level[aTile] = 4;
break;
case 3:
case 19:
case 35:
level[aTile] = 6;
break;
case 4:
case 20:
case 36:
level[aTile] = 8;
break;
case 5:
case 21:
case 37:
level[aTile] = 10;
break;
case 6:
case 22:
case 38:
level[aTile] = 12;
break;
case 7:
case 23:
case 39:
level[aTile] = 14;
break;
case 8:
case 24:
case 40:
level[aTile] = 1;
break;
case 9:
case 25:
case 41:
level[aTile] = 3;
break;
case 10:
case 26:
case 42:
level[aTile] = 5;
break;
case 11:
case 27:
case 43:
level[aTile] = 7;
break;
case 12:
case 28:
case 44:
level[aTile] = 9;
break;
case 13:
case 29:
case 45:
level[aTile] = 11;
break;
case 14:
case 30:
case 46:
level[aTile] = 13;
break;
default:
break;
}
}
function shuffleSlide(aTile)
{
var rnd = random(3);
switch (rnd)
{
case 0:
moveBlockUp((aTile % boardWidth) + boardSize - boardWidth);
break;
case 1:
moveBlockDown((aTile % boardWidth));
break;
case 2:
moveBlockLeft(boardWidth - 1 + aTile -(aTile % boardWidth));
break;
case 3:
moveBlockRight(aTile - (aTile % boardWidth));
break;
}
}
function shuffleRotate(aTile)
{
var rnd = random(3);
for (var i = 0; i < rnd; i++)
rotateBlock(aTile);
}
function shuffleLevel()
{
var rnd;
var j = 0;
while(j < boardSize)
{
switch(gameMode)
{
case gmRotate:
shuffleRotate(j);
j++;
break;
case gmSlide:
shuffleSlide(j);
//for speed up it should be fine as all slide levels are uneven in width / height (except random)
j+=2;
break;
case gmRotateSlide:
rnd = random(2);
if(rnd == 0)
{
shuffleSlide(j);
//for speed up
j+=2;
}
else
{
shuffleRotate(j);
j++;
}
break;
}
}
}
function handleConnectPoint(currentPoint, cellStack, cc)
{
var lookUpX = currentPoint % boardWidth;
var lookUpY = Math.floor(currentPoint / boardWidth);
var tmp;
var tmp2;
if ((lookUpY> 0) && (!(level[currentPoint] & 1)))
{
tmp = currentPoint - boardWidth;
tmp2 = level[tmp];
if (((tmp2 < 16) && (!(tmp2 & 4)) ) ||
((tmp2 > 15) && (!((tmp2 - 16) & 4))))
{
//adapt tile to filled tile
if(level[currentPoint] < 16)
{
level[currentPoint] += 16;
}
//add neighbour to cellstack of to handle tiles
if (tmp2 < 16)
{
cellStack[cc++] = tmp;
}
}
}
//if tile has passage to the east and east neigbour passage to the west
if ((lookUpX + 1 < boardWidth) && (!(level[currentPoint] & 2)))
{
tmp = currentPoint + 1;
tmp2 = level[tmp];
if (((tmp2 < 16) && (!(tmp2 & 8))) ||
((tmp2 > 15) && (!((tmp2 - 16) & 8))))
{
//adapt tile to filled tile
if(level[currentPoint] < 16)
{
level[currentPoint] += 16;
}
//add neighbour to cellstack of to handle tiles
if (tmp2 < 16)
{
cellStack[cc++] = tmp;
}
}
}
//if tile has passage to the south and south neigbour passage to the north
if ((lookUpY + 1 < boardHeight) && (!(level[currentPoint] & 4 )))
{
tmp = currentPoint + boardWidth;
tmp2 = level[tmp];
if (((tmp2 < 16) && (!(tmp2 & 1))) ||
((tmp2 > 15) && (!((tmp2 - 16) & 1))))
{
//adapt tile to filled tile
if(level[currentPoint] < 16)
{
level[currentPoint] += 16;
}
//add neighbour to cellstack of to handle tiles
if (tmp2 < 16)
{
cellStack[cc++] = tmp;
}
}
}
//if tile has passage to the west and west neigbour passage to the east
if ((lookUpX > 0) && (!(level[currentPoint] & 8)))
{
tmp = currentPoint - 1;
tmp2 = level[tmp];
if (((tmp2 < 16) && (!(tmp2 & 2))) ||
((tmp2 > 15) && (!((tmp2 - 16) & 2))))
{
//adapt tile to filled tile
if(level[currentPoint] < 16)
{
level[currentPoint] += 16;
}
//add neighbour to cellstack of to handle tiles
if(tmp2 < 16)
{
cellStack[cc++] = tmp;
}
}
}
return cc;
}
function updateConnected()
{
var cellStack = [];
//reset all tiles to default not filled one
for (var i= 0; i != boardSize; i++)
{
if (level[i] > 31)
{
level[i] -= 32;
}
else
{
if (level[i] > 15)
{
level[i] -= 16;
}
}
}
//start with start tile
var cc = 1;
cc = handleConnectPoint(startPos, cellStack, cc);
while(--cc > 0)
{
//if tile is bigger then 15 we already handled this one, continue with next one
if ((level[cellStack[cc]] < 16))
{
cc = handleConnectPoint(cellStack[cc], cellStack, cc);
}
}
//add start pos special tile
if (level[startPos] > 15)
level[startPos] += 16;
else
if (level[startPos] < 16)
level[startPos] += 32;
}
function generateLevel()
{
var neighbours = new Uint8Array(4);
var cellStack = new Uint8Array(maxBoardSize+1);
var cc = 0;
var currentPoint = 0;
var visitedRooms = 1;
var tmp, tmp2;
var selectedNeighbour;
var neighboursFound;
var lookUpX, lookUpY;
var rnd;
//generate a lookup table so we don't have to use modulus or divide constantly
//generateLookupTable(boardWidth, boardHeight);
//intial all walls value in every room we will remove bits of this value to remove walls
for(tmp = 0; tmp < boardSize; tmp++)
level[tmp] = 0xf;
while (visitedRooms != boardSize)
{
neighboursFound = 0;
lookUpX = currentPoint % boardWidth;
lookUpY = Math.floor(currentPoint / boardWidth);
tmp = currentPoint+1;
//tile has neighbour to the right which we did not handle yet
if (( lookUpX + 1 < boardWidth) && (level[tmp] == 0xf))
neighbours[neighboursFound++] = tmp;
tmp = currentPoint-1;
//tile has neighbour to the left which we did not handle yet
if ((lookUpX > 0) && (level[tmp] == 0xf))
neighbours[neighboursFound++] = tmp;
tmp = currentPoint - boardWidth;
//tile has neighbour the north which we did not handle yet
if ((lookUpY > 0) && (level[tmp] == 0xf))
neighbours[neighboursFound++] = tmp;
tmp = currentPoint + boardWidth;
//tile has neighbour the south which we did not handle yet
if ((lookUpY + 1 < boardHeight) && (level[tmp] == 0xf))
neighbours[neighboursFound++] = tmp;
switch (neighboursFound)
{
case 0:
currentPoint = cellStack[--cc];
continue;
default:
rnd = random(neighboursFound);
break;
}
selectedNeighbour = neighbours[rnd];
tmp = (selectedNeighbour % boardWidth);
//tile has neighbour to the east
if(tmp > lookUpX)
{
//remove west wall neighbour
level[selectedNeighbour] &= ~(8);
//remove east wall tile
level[currentPoint] &= ~(2);
}
else // tile has neighbour to the west
{
if(tmp < lookUpX)
{
//remove east wall neighbour
level[selectedNeighbour] &= ~(2);
//remove west wall tile
level[currentPoint] &= ~(8);
}
else // tile has neighbour to the north
{
tmp2 = selectedNeighbour / boardWidth;
if(tmp2 < lookUpY)
{
//remove south wall neighbour
level[selectedNeighbour] &= ~(4);
//remove north wall tile
level[currentPoint] &= ~(1);
}
else // tile has neighbour to the south
{
if(tmp2 > lookUpY)
{
//remove north wall neighbour
level[selectedNeighbour] &= ~(1);
//remove south wall tile
level[currentPoint] &= ~(4);
}
}
}
}
//add tile to the cellstack
if(neighboursFound > 1)
{
cellStack[cc++] = currentPoint;
}
//set tile to the neighbour
currentPoint = selectedNeighbour;
visitedRooms++;
}
}
//when all board tiles are not below 16, the level is cleared
//as there are 16 tiles per tilegroup (no water, water, special start with water)
function isLevelDone()
{
for (var i=0; i != boardSize; i++)
if(level[i] < 16)
return 0;
return 1;
}
function initLevel(aRandomSeed)
{
levelDone = 0;
moves = 0;
if(difficulty != diffRandom)
//use level number + fixed value based on difficulty as seed for the random function
//this makes sure every level from a difficulty will remain the same
srand(selectedLevel + (difficulty * 500) + (gameMode * 50));
else
srand(aRandomSeed);
maxLevel = levelCount;
//set boardsize and max level based on difficulty
switch (difficulty)
{
case diffVeryEasy:
boardWidth = 5;
boardHeight = 5;
break;
case diffEasy:
boardWidth = 6;
boardHeight = 6;
break;
case diffNormal:
boardWidth = 7;
boardHeight = 7;
break;
case diffHard:
boardWidth = 8;
boardHeight = 8;
break;
case diffVeryHard:
boardWidth = 10;
boardHeight = 8;
break;
case diffRandom:
var rnd = random(255);
boardWidth = 5 + (rnd % (maxBoardWidth - 5 + 1)); //5 is smallest level width from very easy
rnd = random(255);
boardHeight = 5 + (rnd % (maxBoardHeight - 5 + 1)); //5 is smallest level height from very easy
maxLevel = 0; //special value with random
break;
}
//add space for arrows based on same posadd value (1 or 0 depending if sliding is allowed)
boardWidth -= posAdd + posAdd;
boardHeight -= posAdd + posAdd;
boardSize = boardWidth * boardHeight;
//generate the level
generateLevel();
//startpoint of of level in center of screen
boardX = (maxBoardBgWidth - boardWidth) >> 1;
boardY = (maxBoardBgHeight - boardHeight) >> 1;
startPos = (boardWidth >> 1) + (boardHeight >> 1) * (boardWidth);
//startpoint of tile with water and our cursor
selectionX = boardWidth >> 1;
selectionY = boardHeight >> 1;
//level is currently the solution so we still need to shuffle it
shuffleLevel();
//update possibly connected tiles already starting from startpoint
updateConnected();
}
// --------------------------------------------------------------------------------------------------
// levels cleared
// --------------------------------------------------------------------------------------------------
function initLevelsCleared()
{
set_bkg_data(congratsTiles);
g.clearRect(Bangle.appRect);
g.drawImage(congratsScreen, screenOffsetX, screenOffsetY); //arduboy.drawCompressed(0, 0, congratsMap);
switch (difficulty)
{
case diffVeryEasy:
printCongratsScreen(0, 3, "VERY EASY LEVELS");
break;
case diffEasy:
printCongratsScreen(3, 3, "EASY LEVELS");
break;
case diffNormal:
printCongratsScreen(2, 3, "NORMAL LEVELS");
break;
case diffHard:
printCongratsScreen(3, 3, "HARD LEVELS");
break;
case diffVeryHard:
printCongratsScreen(0, 3, "VERY HARD LEVELS");
break;
}
// SelectMusic(musAllLevelsClear);
requiresFlip = 1;
}
function levelsCleared()
{
if(gameState == gsInitLevelsCleared)
{
initLevelsCleared();
gameState -= gsInitDiff;
}
if (btna || btnb)
{
//playMenuAcknowlege();
titleStep = tsMainMenu;
gameState = gsInitTitle;
}
needRedraw = 0;
}
// --------------------------------------------------------------------------------------------------
// level select
// --------------------------------------------------------------------------------------------------
function drawLevelSelect()
{
g.clearRect(Bangle.appRect);
//LEVEL:
printMessage(maxBoardBgWidth , 0 , "LEVEL:");
//[LEVEL NR] 2 chars
printNumber(maxBoardBgWidth + 4 , 1 , selectedLevel, 2);
//B:BACK
printMessage(maxBoardBgWidth , 6 , "BTN:");
printMessage(maxBoardBgWidth , 7 , "BACK");
//A:PLAY
printMessage(maxBoardBgWidth , 4 , "TOUCH:");
printMessage(maxBoardBgWidth , 5 , "PLAY");
//Locked & Unlocked keywoard
var tmpUnlocked = levelUnlocked(gameMode, difficulty, selectedLevel -1);
if(!tmpUnlocked)
printMessage(maxBoardBgWidth , 2 , "LOCKED");
else
printMessage(maxBoardBgWidth , 2 , "OPEN");
//Draw arrows for vertical / horizontal movement
if(gameMode != gmRotate)
{
for (var x = 0; x != boardWidth; x++)
{
set_bkg_tile_xy(boardX + x , boardY -1 , arrowDown);
set_bkg_tile_xy(boardX + x , boardY + boardHeight , arrowUp);
}
for (var y = 0; y != boardHeight; y++)
{
set_bkg_tile_xy(boardX - 1 , boardY + y , arrowRight);
set_bkg_tile_xy(boardX + boardWidth , boardY + y , arrowLeft);
}
}
var i16 = 0;
for (var yy = 0; yy < boardHeight; yy++)
{
for(var xx = 0; xx <boardWidth; xx++)
{
set_bkg_tile_xy(boardX + xx , boardY + yy, level[i16 + xx]);
}
i16 += boardWidth;
}
}
function initLevelSelect()
{
setBlockTilesAsBackground();
//SelectMusic(musTitle);
needRedraw = 1;
}
function levelSelect()
{
if(gameState == gsInitLevelSelect)
{
initLevelSelect();
gameState -= gsInitDiff;
}
if(needRedraw)
{
drawLevelSelect();
needRedraw = 0;
requiresFlip = 1;
}
var tmpUnlocked = levelUnlocked(gameMode, difficulty, selectedLevel -1);
if (btnb)
{
//playMenuBackSound();
gameState = gsInitTitle;
}
if (btna)
{
if(tmpUnlocked)
{
gameState = gsInitGame;
//playMenuAcknowlege();
}
else
{
//playErrorSound();
}
}
if (dragleft)
{
if (difficulty == diffRandom)
{
//playMenuSelectSound();
randomSeedGame = Date.now();//arduboy.generateRandomSeed();
initLevel(randomSeedGame);
needRedraw = 1;
}
else
{
if (selectedLevel > 1)
{
//playMenuSelectSound();
selectedLevel--;
initLevel(randomSeedGame);
needRedraw = 1;
}
}
}
if (dragright)
{
if (difficulty == diffRandom)
{
//playMenuSelectSound();
//need new seed based on time
randomSeedGame = Date.now();
initLevel(randomSeedGame);
needRedraw = 1;
}
else
{
if (selectedLevel < maxLevel)
{
//playMenuSelectSound();
selectedLevel++;
initLevel(randomSeedGame);
needRedraw = 1;
}
}
}
}
// --------------------------------------------------------------------------------------------------
// printing functions
// --------------------------------------------------------------------------------------------------
function setCharAt(str,index,chr) {
if(index > str.length-1) return str;
return str.substring(0,index) + chr + str.substring(index+1);
}
function formatInteger(valinteger)
{
const maxDigits = 10;
var array = " ";
const maxCharacters = (maxDigits);
const lastIndex = (maxCharacters - 1);
if(valinteger == 0)
{
array = setCharAt(array,lastIndex, '0');
return {digits:1,string:array};
}
var digits = 0;
var integer = valinteger;
do
{
var digit = integer % 10;
integer = Math.floor(integer / 10);
array = setCharAt(array,lastIndex - digits, digit.toString());
++digits;
}
while(integer > 0);
return {digits:digits,string:array};
}
//print a number on levelselect or game screen
function printNumber(ax, ay, aNumber, maxDigits)
{
const buffSize = 10;
var ret = formatInteger(aNumber);
var maxFor = ret.digits;
if (ret.digits > maxDigits)
maxFor = maxDigits;
for (var c=0; c < maxFor; c++)
{
if (ret.string.charAt(buffSize - ret.digits + c) == '')
return;
set_bkg_tile_xy(ax + (maxDigits-ret.digits) + c, ay, ret.string.charCodeAt(buffSize - ret.digits + c) + 32);
}
}
function printDebug(ax,ay, amsg)
{
if(debugMode)
{
//rememvber current tiles
var tiles = get_bkg_data();
setBlockTilesAsBackground();
g.clearRect(Bangle.appRect);
printMessage(ax, ay, amsg);
setTimeout(() => { g.flip(); }, 2500);
//restore the previous tiles
set_bkg_data(tiles);
}
}
//print a message on the title screen on ax,ay, the tileset from titlescreen contains an alphabet
function printMessage(ax, ay, amsg)
{
var index = 0;
var p = 0;
while (1)
{
var fChar = amsg.charAt(p++);
var tile = 61;
switch (fChar)
{
case '':
return;
case '[':
tile = 70;
break;
case ']':
tile = 64;
break;
case '<':
tile = 73;
break;
case '>':
tile = 67;
break;
case '+':
tile = 63;
break;
case '*':
tile = 62;
break;
case '|':
tile = 69;
break;
case '#':
tile = 65;
break;
case ':':
tile = 116;
break;
case 'a':
tile = 119;
break;
case 'b':
tile = 117;
break;
default:
if ((fChar.charCodeAt(0) >= 'A'.charCodeAt(0)) && (fChar.charCodeAt(0) <= 'Z'.charCodeAt(0)))
tile = fChar.charCodeAt(0) + 25;
if ((fChar.charCodeAt(0) >= '0'.charCodeAt(0)) && (fChar.charCodeAt(0) <= '9'.charCodeAt(0)))
tile = fChar.charCodeAt(0) + 32;
break;
}
set_bkg_tile_xy(ax + index, ay, tile);
++index;
}
}
//print a message on the CongratsScreen on ax,ay, the tileset from Congrats Screen contains an alphabet in another font
function printCongratsScreen(ax, ay, amsg)
{
// based on input form @Pharap
var index = 0;
var p = 0;
while (1)
{
var fChar = amsg.charAt(p++);
var tile = 26;
switch (fChar)
{
case '':
return;
default:
if ((fChar.charCodeAt(0) >= 'A'.charCodeAt(0)) && (fChar.charCodeAt(0) <= 'Z'.charCodeAt(0)))
tile = fChar.charCodeAt(0) - 'A'.charCodeAt(0);
break;
}
set_bkg_tile_xy(ax + index, ay, tile);
++index;
}
}
// --------------------------------------------------------------------------------------------------
// save state
// --------------------------------------------------------------------------------------------------
function validateSaveState()
{
for (var j=0; j<gmCount; j++)
{
for (var i=0; i<diffCount; i++)
{
if ((levelLocks[(j * diffCount) + i] == 0) || (levelLocks[(j * diffCount) + i] > levelCount))
return 0;
}
}
if (options[musicOptionBit] > 1)
return 0;
if (options[soundOptionBit] > 1)
return 0;
return 1;
}
function initSaveState()
{
//read from file
var file = require("Storage").open("waternet.data.dat","r");
{
var index = 0;
for (index = 0; index < gmCount * diffCount; index++)
{
tmp = file.readLine();
if(tmp !== undefined)
levelLocks[index] = Number(tmp);
}
for (index = 0; index < 2; index++)
{
tmp = file.readLine();
if(tmp !== undefined)
options[index] = Number(tmp);
}
}
//then
if(!validateSaveState())
{
for (var j=0; j<gmCount; j++)
for (var i=0; i<diffCount; i++)
levelLocks[(j * diffCount) + i] = 1; //1st level unlocked
options[musicOptionBit] = 1; //bit 0 & 1 set = music & sound on
options[soundOptionBit] = 1;
}
}
function saveSaveState()
{
//save to file
var file = require("Storage").open("waternet.data.dat", "w");
for (var index = 0; index < gmCount * diffCount; index++)
file.write(levelLocks[index].toString() + "\n");
file.write(options[musicOptionBit].toString() + "\n");
file.write(options[soundOptionBit].toString() + "\n");
}
function setMusicOnSaveState(value)
{
options[musicOptionBit] = value;
saveSaveState();
}
function isMusicOnSaveState()
{
return options[musicOptionBit] == 1;
}
function setSoundOnSaveState(value)
{
options[soundOptionBit] = value;
saveSaveState();
}
function isSoundOnSaveState()
{
return options[soundOptionBit] == 1;
}
function levelUnlocked(mode, diff, level)
{
return levelLocks[(mode * diffCount) + diff] > level;
}
function lastUnlockedLevel(mode, diff)
{
return levelLocks[(mode * diffCount) + diff];
}
function unlockLevel(mode, diff, level)
{
if (level + 1> lastUnlockedLevel(mode, diff))
{
levelLocks[(mode * diffCount) + diff] = level + 1;
saveSaveState();
}
}
// --------------------------------------------------------------------------------------------------
// titlescreen
// --------------------------------------------------------------------------------------------------
function drawTitleScreen()
{
g.clearRect(Bangle.appRect);
g.drawImage(title, screenOffsetX, screenOffsetY); //arduboy.drawCompressed(0, 0, titlescreenMap);
switch (titleStep)
{
case tsMainMenu:
printMessage(5, 4, "START");
printMessage(5, 5, "HELP");
printMessage(5, 6, "OPTIONS");
printMessage(5, 7, "CREDITS");
break;
case tsDifficulty:
printMessage(3, 3, "VERY EASY");
printMessage(3, 4, "EASY");
printMessage(3, 5, "NORMAL");
printMessage(3, 6, "HARD");
if(difficulty <= diffVeryHard)
printMessage(3, 7, "VERY HARD");
else
printMessage(3, 7, "RANDOM");
break;
case tsGameMode:
printMessage(5, 4, "ROTATE");
printMessage(5, 5, "SLIDE");
printMessage(5, 6, "ROSLID");
break;
case tsCredits:
printMessage(3, 5, "CREATED BY");
printMessage(2, 6, "WILLEMS DAVY");
printMessage(2, 7, "JOYRIDER3774");
break;
case tsOptions:
//if(isMusicOn())
printMessage(4, 4, "MUSIC ON");
//else
// printMessage(4, 4, "MUSIC OFF");
//if(isSoundOn())
printMessage(4, 5, "SOUND ON");
//else
// printMessage(4, 5, "SOUND OFF");
//break;
}
//set menu tile
switch (titleStep)
{
case tsMainMenu:
set_bkg_tile_xy(4, 4 + mainMenu, leftMenu);
break;
case tsGameMode:
set_bkg_tile_xy(4, 4 + gameMode, leftMenu);
break;
case tsDifficulty:
if(difficulty >= diffVeryHard)
set_bkg_tile_xy(2, 7, leftMenu);
else
set_bkg_tile_xy(2, 3 + difficulty, leftMenu);
break;
case tsOptions:
set_bkg_tile_xy(2, 4 + option, leftMenu);
break;
}
}
function initTitleScreen()
{
setBlockTilesAsBackground();
//SelectMusic(musTitle);
needRedraw = 1;
}
function titleScreen()
{
if(gameState == gsInitTitle)
{
initTitleScreen();
gameState -= gsInitDiff;
}
if(needRedraw)
{
drawTitleScreen();
needRedraw = 0;
requiresFlip = 1;
}
if (dragup)
{
switch (titleStep)
{
case tsMainMenu:
if(mainMenu > mmStartGame)
{
//playMenuSelectSound();
mainMenu--;
needRedraw = 1;
}
break;
case tsGameMode:
if(gameMode > gmRotate)
{
//playMenuSelectSound();
gameMode--;
needRedraw = 1;
}
break;
case tsDifficulty:
if(difficulty > diffVeryEasy)
{
//playMenuSelectSound();
difficulty--;
needRedraw = 1;
}
break;
case tsOptions:
if(option > opMusic)
{
//playMenuSelectSound();
option--;
needRedraw = 1;
}
break;
}
}
if (dragdown)
{
switch (titleStep)
{
case tsMainMenu:
if(mainMenu < mmCount-1)
{
//playMenuSelectSound();
mainMenu++;
needRedraw = 1;
}
break;
case tsGameMode:
if(gameMode < gmCount-1)
{
//playMenuSelectSound();
gameMode++;
needRedraw = 1;
}
break;
case tsDifficulty:
if(difficulty < diffCount-1)
{
//playMenuSelectSound();
difficulty++;
needRedraw = 1;
}
break;
case tsOptions:
if(option < opCount-1)
{
//playMenuSelectSound();
option++;
needRedraw = 1;
}
break;
}
}
if (btnb)
{
switch (titleStep)
{
case tsOptions:
case tsCredits:
titleStep = tsMainMenu;
//playMenuBackSound();
needRedraw = 1;
break;
case tsGameMode:
case tsDifficulty:
titleStep--;
//playMenuBackSound();
needRedraw = 1;
break;
}
}
if (btna)
{
//playMenuAcknowlege();
switch(mainMenu)
{
case mmOptions:
if(titleStep != tsOptions)
{
titleStep = tsOptions;
needRedraw = 1;
}
else
{
switch(option)
{
case opMusic:
//setMusicOn(!isMusicOn());
//setMusicOnSaveState(isMusicOn());
needRedraw = 1;
break;
case opSound:
//setSoundOn(!isSoundOn());
//setSoundOnSaveState(isSoundOn());
needRedraw = 1;
break;
}
}
break;
case mmCredits:
if(titleStep != tsCredits)
{
titleStep = tsCredits;
needRedraw = 1;
}
else
{
titleStep = tsMainMenu;
needRedraw = 1;
}
break;
case mmHelp:
if (titleStep < tsGameMode)
{
titleStep++;
needRedraw = 1;
}
else
{
switch (gameMode)
{
case gmRotate:
gameState = gsInitHelpRotate;
break;
case gmSlide:
gameState = gsInitHelpSlide;
break;
case gmRotateSlide:
gameState = gsInitHelpRotateSlide;
break;
}
}
break;
case mmStartGame:
if (titleStep < tsDifficulty)
{
titleStep++;
needRedraw = 1;
}
else
{
if (difficulty == diffRandom)
selectedLevel = 1;
else
selectedLevel = lastUnlockedLevel(gameMode, difficulty);
if (gameMode == gmRotate)
posAdd = 0;
else
posAdd = 1;
//set randomseet to systime here
//it will be reused all the time
//with the level generating
//but not when going back from
//level playing to level selector
//when calling init level there
randomSeedGame = Date.now();
initLevel(randomSeedGame);
gameState = gsInitLevelSelect;
}
break;
}
}
}
// --------------------------------------------------------------------------------------------------
// game
// --------------------------------------------------------------------------------------------------
function drawGame()
{
//background
if(!paused && !redrawLevelDoneBit)
{
g.clearRect(Bangle.appRect);
//LEVEL:
printMessage(maxBoardBgWidth, 0, "LEVEL:");
//[LEVEL NR] 2 chars
printNumber(maxBoardBgWidth + 4, 1, selectedLevel, 2);
//MOVES:
printMessage(maxBoardBgWidth, 2, "MOVES:");
printNumber(maxBoardBgWidth + 1, 3, moves, 5);
//A:XXXXXX (XXXXXX="ROTATE" or XXXXXX="SLIDE " or XXXXXX="ROSLID")
switch (gameMode)
{
case gmRotate:
printMessage(maxBoardBgWidth, 4, "TOUCH:");
printMessage(maxBoardBgWidth, 5, "ROTATE");
break;
case gmSlide:
printMessage(maxBoardBgWidth, 4, "TOUCH:");
printMessage(maxBoardBgWidth, 5, "SLIDE");
break;
case gmRotateSlide:
printMessage(maxBoardBgWidth, 4, "TOUCH:");
printMessage(maxBoardBgWidth, 5, "ROSLID");
break;
}
//B:BACK
printMessage(maxBoardBgWidth, 6, "BTN:");
printMessage(maxBoardBgWidth, 7, "BACK");
//Draw arrows for vertical / horizontal movement
if(gameMode != gmRotate)
{
for (var x = 0; x != boardWidth; x++)
{
set_bkg_tile_xy(boardX + x, boardY -1, arrowDown);
set_bkg_tile_xy(boardX + x, boardY + boardHeight, arrowUp);
}
for (var y = 0; y != boardHeight; y++)
{
set_bkg_tile_xy(boardX - 1, boardY + y, arrowRight);
set_bkg_tile_xy(boardX + boardWidth, boardY + y, arrowLeft);
}
}
//level
var i16 = 0;
for (var yy = 0; yy < boardHeight; yy++)
{
for(var xx = 0; xx <boardWidth; xx++)
{
set_bkg_tile_xy(boardX +xx , boardY + yy, level[i16 + xx]);
}
i16+=boardWidth;
}
}
}
function initGame()
{
paused = 0;
//SelectMusic(musGame);
//set background tiles
setBlockTilesAsBackground();
//set sprite for selector / cursor
initCursors();
setCursorPos(0, boardX + selectionX, boardY + selectionY);
showCursors();
redrawLevelDoneBit = 0;
}
function doPause()
{
drawGame();
drawCursors();
paused = 1;
//wasSoundOn = isSoundOn();
//wasMusicOn = isMusicOn();
//setMusicOn(0);
//setSoundOn(0);
hideCursors();
g.setColor(0,0,0);
g.fillRect(screenOffsetX, screenOffsetY + ((maxBoardBgHeight >> 1) - 3) * 8, screenOffsetX + 16*8, screenOffsetY
+ ((maxBoardBgHeight >> 1) - 3) * 8 + (6*8));
g.setColor(1,1,1);
printMessage(0, (maxBoardBgHeight >> 1) - 3, "[**************]");
printMessage(0, (maxBoardBgHeight >> 1) - 2, "|PLEASE CONFIRM+");
printMessage(0, (maxBoardBgHeight >> 1) - 1, "| +");
printMessage(0, (maxBoardBgHeight >> 1) + 0, "| TOUCH PLAY +");
printMessage(0, (maxBoardBgHeight >> 1) + 1, "| BTN TO QUIT +");
printMessage(0, (maxBoardBgHeight >> 1) + 2, "<##############>");
}
function doUnPause()
{
paused = 0;
//setMusicOn(wasMusicOn);
//setSoundOn(wasSoundOn);
setCursorPos(0, boardX + selectionX, boardY + selectionY);
showCursors();
needRedraw = 1;
}
function game()
{
if(gameState == gsInitGame)
{
initGame();
gameState -= gsInitDiff;
}
if(needRedraw)
{
drawGame();
drawCursors();
needRedraw = 0;
requiresFlip = 1;
}
//needRedraw = updateCursorFrame();
if (dragdown)
{
if(!levelDone && !paused)
{
//playGameMoveSound();
//if not touching border on bottom
if (selectionY + 1 < boardHeight + posAdd)
{
selectionY += 1;
needRedraw = 1;
}
else
//set to border on top
{
selectionY = -posAdd;
needRedraw = 1;
}
setCursorPos(0, boardX + selectionX, boardY + selectionY);
}
}
if (dragup)
{
if (!levelDone && !paused)
{
//if not touching border on top
//playGameMoveSound();
if (selectionY -1 >= -posAdd)
{
selectionY -= 1;
needRedraw = 1;
}
else
//set to border on bottom
{
selectionY = boardHeight -1 +posAdd;
needRedraw = 1;
}
setCursorPos(0, boardX + selectionX, boardY + selectionY);
}
}
if (dragright)
{
if (!levelDone && !paused)
{
//playGameMoveSound();
//if not touching border on right
if(selectionX + 1 < boardWidth + posAdd)
{
selectionX += 1;
needRedraw = 1;
}
else
//set to border on left
{
selectionX = -posAdd;
needRedraw = 1;
}
setCursorPos(0, boardX + selectionX, boardY + selectionY);
}
}
if (dragleft)
{
if(!levelDone && !paused)
{
//playGameMoveSound();
//if not touching border on left
if( selectionX -1 >= -posAdd)
{
selectionX -= 1;
needRedraw = 1;
}
//set to border on right
else
{
selectionX = boardWidth -1 + posAdd;
needRedraw = 1;
}
setCursorPos(0, boardX + selectionX, boardY + selectionY);
}
}
if (btna)
{
if(paused)
{
doUnPause();
//playMenuAcknowlege();
needRedraw = 1;
}
else
{
if(!levelDone)
{
if ((selectionX > -1) && (selectionX < boardWidth) &&
(selectionY > -1) && (selectionY < boardHeight))
{
if (gameMode != gmSlide)
{
rotateBlock(selectionX + (selectionY * boardWidth));
moves++;
//playGameAction();
needRedraw = 1;
}
else
{
//playErrorSound();
}
}
else
{
if ((selectionX > -1) && (selectionX < boardWidth))
{
if (selectionY == -1)
{
moveBlockDown(selectionX + ((selectionY+1) * boardWidth));
moves++;
//playGameAction();
needRedraw = 1;
}
else
{
if (selectionY == boardHeight)
{
moveBlockUp(selectionX + ((selectionY-1) * boardWidth));
moves++;
//playGameAction();
needRedraw = 1;
}
}
}
else
{
if ((selectionY > -1) && (selectionY < boardHeight))
{
if (selectionX == -1)
{
moveBlockRight((selectionX + 1) + (selectionY * boardWidth));
moves++;
//playGameAction();
needRedraw = 1;
}
else
{
if (selectionX == boardWidth)
{
moveBlockLeft((selectionX - 1) + (selectionY * boardWidth));
moves++;
//playGameAction();
needRedraw = 1;
}
}
}
else
{
//playErrorSound();
}
}
}
updateConnected();
levelDone = isLevelDone();
if(levelDone)
{
//update level one last time so we are at final state
//as it won't be updated anymore as long as level done is displayed
//1 forces level to be drawn (only) one last time the other call uses levelDone
drawGame();
//SelectMusic(musLevelClear);
//hide cursor it's only sprite we use
hideCursors();
g.setColor(0,0,0);
g.fillRect(screenOffsetX + ((16 - 13) >> 1) * 8, screenOffsetY + ((maxBoardBgHeight >> 1) - 2) * 8, screenOffsetX + (((16 - 13) >> 1) * 8) + (14*8), screenOffsetY + (((maxBoardBgHeight >> 1) - 2) * 8) +(5*8));
g.setColor(1,1,1);
printMessage(((16 - 13) >> 1), (maxBoardBgHeight >> 1) - 2, "[************]");
printMessage(((16 - 13) >> 1), (maxBoardBgHeight >> 1) - 1, "| LEVEL DONE +");
printMessage(((16 - 13) >> 1), (maxBoardBgHeight >> 1) , "| TOUCH TO +");
printMessage(((16 - 13) >> 1), (maxBoardBgHeight >> 1) + 1, "| CONTINUE +");
printMessage(((16 - 13) >> 1), (maxBoardBgHeight >> 1) + 2, "<############>");
redrawLevelDoneBit = 1;
}
}
else
{
redrawLevelDoneBit = 0;
//goto next level
if (difficulty == diffRandom)
{
//ned new seed based on time
randomSeedGame = Date.now();
initLevel(randomSeedGame);
//SelectMusic(musGame);
//show cursor again (it's actually to early but i'm not fixing that)
setCursorPos(0, boardX + selectionX, boardY + selectionY);
showCursors();
needRedraw = 1;
}
else
{
//goto next level if any
if (selectedLevel < maxLevel)
{
selectedLevel++;
unlockLevel(gameMode, difficulty, selectedLevel-1);
initLevel(randomSeedGame);
//SelectMusic(musGame);
//show cursor again (it's actually to early but i'm not fixing that)
setCursorPos(0, boardX + selectionX, boardY + selectionY);
showCursors();
needRedraw = 1;
}
else //Goto some congrats screen
{
gameState = gsInitLevelsCleared;
}
}
}
}
}
if(btnb)
{
if(!levelDone)
{
if(!paused)
{
//playMenuBackSound();
doPause();
needRedraw = 1;
}
else
{
//need to enable early again to play backsound
//normally unpause does it but we only unpause
//after fade
//setSoundOn(wasSoundOn);
hideCursors();
//playMenuBackSound();
gameState = gsInitLevelSelect;
doUnPause();
//unpause sets cursor visible !
hideCursors();
//need to reset the level to initial state when going back to level selector
//could not find a better way unfortunatly
//also we do not want to reset the randomseed used for random level generating
//or a new level would have been created when going back we only want the level
//with random to change when pressing left and right in the level selector
//this way it stays consistent with the normal levels
//and the player can replay the level if he wants to
initLevel(randomSeedGame);
}
}
}
}
// --------------------------------------------------------------------------------------------------
// main game start
// --------------------------------------------------------------------------------------------------
function setup()
{
setBlockTilesAsBackground();
option = 0;
difficulty = diffNormal;
selectedLevel = 1;
mainMenu = mmStartGame;
gameState = gsInitIntro;
titleStep = tsMainMenu;
gameMode = gmRotate;
//has to be called first because initsound and initmusic read savestate sound to set intial flags
initSaveState();
//initSound();
//initMusic();
//setMusicOn(isMusicOnSaveState());
//setSoundOn(isSoundOnSaveState());
}
function loop()
{
//soundTimer();
g.reset();
g.setColor(1,1,1);
g.setBgColor(0,0,0);
//gamestate handling
var prevGameState = gameState;
switch (gameState)
{
case gsInitTitle:
case gsTitle:
clearInterval(intervalTimer);
titleScreen();
break;
case gsInitLevelSelect:
case gsLevelSelect:
levelSelect();
break;
case gsInitGame:
case gsGame:
game();
break;
case gsInitLevelsCleared:
case gsLevelsCleared:
levelsCleared();
break;
case gsInitHelpSlide:
case gsHelpSlide:
helpSlide();
break;
case gsInitHelpSlide2:
case gsHelpSlide2:
helpSlide2();
break;
case gsInitHelpSlide3:
case gsHelpSlide3:
helpSlide3();
break;
case gsHelpRotateSlide:
case gsInitHelpRotateSlide:
helpRotateSlide();
break;
case gsInitHelpRotateSlide2:
case gsHelpRotateSlide2:
helpRotateSlide2();
break;
case gsInitHelpRotateSlide3:
case gsHelpRotateSlide3:
helpRotateSlide3();
break;
case gsInitHelpRotateSlide4:
case gsHelpRotateSlide4:
helpRotateSlide4();
break;
case gsInitHelpRotate:
case gsHelpRotate:
helpRotate();
break;
case gsInitHelpRotate2:
case gsHelpRotate2:
helpRotate2();
break;
case gsInitHelpRotate3:
case gsHelpRotate3:
helpRotate3();
break;
case gsInitIntro:
case gsIntro:
intro();
break;
}
if(requiresFlip)
{
if(scaleScreen)
{
//scale whats currently on screen to full size of the screen
//128 was original games width (128x64)
//var scale = (screenWidth - 8) / 128;
//don't make this smaller than 1 or it won't work
var scale = 1.25;
g.drawImage(g.asImage(),((g.getWidth() / 2)-((g.getWidth() * scale) / 2)), Bangle.appRect.y/2 - Bangle.appRect.y/2*scale + ((g.getHeight()/2) - ((g.getHeight() * scale) / 2)),{scale:scale});
}
Bangle.drawWidgets();
if(debugMode)
{
const offsetvalue = 0.20;
var x1 = screenWidth * offsetvalue;
var x2 = screenWidth - screenWidth * offsetvalue;
var y1 = Bangle.appRect.y + screenHeight *offsetvalue;
var y2 = screenHeight - screenHeight * offsetvalue;
g.setColor(1,0,1);
//up
g.drawRect(0,Bangle.appRect.y,screenWidth-1,y1);
//down
g.drawRect(0,y2,screenWidth-1,screenHeight-1);
//left
g.drawRect(0,Bangle.appRect.y,x1,screenHeight-1);
//right
g.drawRect(x2,Bangle.appRect.y,screenWidth-1, screenHeight-1);
}
g.flip();
requiresFlip = 0;
}
//when switching gamestate we need a redraw
if(gameState != prevGameState)
needRedraw = 1;
debugLog("loop");
if(debugModeRamUse)
{
var memTmp = process.memory(false);
var used = memTmp.usage - memStart.usage;
debugLog("Udiff:"+ used.toString() + " used:" + memTmp.usage.toString() + " free:" + memTmp.free.toString() + " total:" + memTmp.total.toString() );
}
}
function debugLog(val)
{
if(debugMode)
print(val);
}
function handleTouch(button, data)
{
const offsetvalue = 0.20;
var x1 = screenWidth * offsetvalue;
var x2 = screenWidth - screenWidth * offsetvalue;
var y1 = Bangle.appRect.y + screenHeight *offsetvalue;
var y2 = screenHeight - screenHeight * offsetvalue;
dragleft = data.x <x1;
dragright = data.x > x2;
dragup = data.y < y1;
dragdown = data.y > y2;
btna = ((data.x <= x2) && (data.x >= x1) && (data.y >= y1) && (data.y <= y2) && (data.type == 0));
btnb = ((data.x <= x2) && (data.x >= x1) && (data.y >= y1) && (data.y <= y2) && (data.type == 2));
debugLog("tap button:" + button.toString() + " x:" + data.x.toString() + " y:" + data.y.toString() + " x1:" + x1.toString() +" x2:" + x2.toString() +" y1:" + y1.toString() +" y2:" + y2.toString() +" type:" + data.type.toString());
debugLog("l:" + dragleft.toString() + " u:" + dragup.toString() + " r:" + dragright.toString() + " d:" + dragdown.toString() + " a:" + btna.toString() + " b:" + btnb.toString());
loop();
dragleft = false;
dragright = false;
dragdown = false;
dragup = false;
btna = false;
btnb = false;
while(needRedraw)
loop();
debugLog("handleTouch done");
}
function btnPressed()
{
dragleft = false;
dragright = false;
dragdown = false;
dragup = false;
btna = false;
btnb = true;
loop();
btnb = false;
while(needRedraw)
loop();
debugLog("btnPressed done");
}
var memStart;
if(debugModeRamUse)
memStart = process.memory(true);
//clear one time entire screen
g.clear();
//setup game and run loop it will repeat during intro
//otherwise only as long as redraw is needed after input was detected
setup();
//for intro only
var intervalTimer = setInterval(loop, 66); // 15 fps
//for handling input
Bangle.on('touch', handleTouch);
setWatch(btnPressed, BTN, {edge:"rising", debounce:50, repeat:true});