Merge branch 'master' of github.com:espruino/BangleApps into pushups
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1,49 @@
|
||||||
|
g.clear().setRotation(1);
|
||||||
|
// g.setRotation ALSO changes accelerometer axes
|
||||||
|
var avrAngle = undefined;
|
||||||
|
var history = [];
|
||||||
|
|
||||||
|
var R = Bangle.appRect;
|
||||||
|
var W = g.getWidth();
|
||||||
|
var H = g.getHeight();
|
||||||
|
var relativeTo = undefined;
|
||||||
|
|
||||||
|
function draw(v) {
|
||||||
|
if (v===undefined) v = Bangle.getAccel();
|
||||||
|
// current angle
|
||||||
|
var d = Math.sqrt(v.y*v.y + v.z*v.z);
|
||||||
|
var ang = Math.atan2(-v.x, d)*180/Math.PI;
|
||||||
|
// Median filter
|
||||||
|
if (history.length > 10) history.shift(); // pull old reading off the start
|
||||||
|
history.push(ang);
|
||||||
|
avrAngle = history.slice().sort()[(history.length-1)>>1]; // median filter
|
||||||
|
// Render
|
||||||
|
var x = R.x + R.w/2;
|
||||||
|
var y = R.y + R.h/2;
|
||||||
|
g.reset().clearRect(R).setFontAlign(0,0);
|
||||||
|
var displayAngle = avrAngle;
|
||||||
|
g.setFont("6x15").drawString("ANGLE (DEGREES)", x, R.y2-8);
|
||||||
|
if (relativeTo!==undefined) {
|
||||||
|
g.drawString("RELATIVE TO", x,y-50);
|
||||||
|
g.setFont("Vector:30").drawString(relativeTo.toFixed(1),x,y-30);
|
||||||
|
y += 20;
|
||||||
|
displayAngle = displayAngle-relativeTo;
|
||||||
|
}
|
||||||
|
g.setFont("Vector:60").drawString(displayAngle.toFixed(1),x,y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
draw();
|
||||||
|
Bangle.on('accel',draw);
|
||||||
|
|
||||||
|
// Pressing the button turns relative angle on/off
|
||||||
|
Bangle.setUI({
|
||||||
|
mode : "custom",
|
||||||
|
btn : function(n) {
|
||||||
|
if (relativeTo===undefined)
|
||||||
|
relativeTo = avrAngle;
|
||||||
|
else
|
||||||
|
relativeTo = undefined;
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEw4cA///ov+5lChWMyGuxdzpdj4/lKf4AUkgQPgm0wAiPy2QCBsBkmS6QRNhIRBrVACJlPu2+pdICBcCrVJlvJtIRLifStMl3MtkARKydUyMkzMl0CMKyWWyUk1MkSJXkyR7BogRLgVcydSrVGzLHKgdLyfSpdE3JYKklqTwNJknJYJVkxcSp+pnygKhMs1OSEQOSYhVJl1bCIbBK5Mq7gRCyARJiVbqyPBCIKMKuVM24yBCIIiJnVOqu5CISMKp9JlvJCIRXKpP3nxoCRhUSBwSMNBwaMMgn6yp6DRhUl0mypiMMgM9ksipaMMhMtCINKRhlJmoRBpJuBCBIRGRhUE5I1CpKMLgmZn5ZDGhUAycnRoNMRhTDCsn3tfkRhLnDTwYQLNgSMMUQkyRhbGEkyMKAApFOAH4AGA"))
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"id": "angles",
|
||||||
|
"name": "Angles (Spirit Level)",
|
||||||
|
"shortName": "Angles",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "Shows Angle or Relative angle in degrees (Digital Protractor/Inclinometer). Place Bangle sideways against a surface with the button facing away for best readings.",
|
||||||
|
"icon": "icon.png",
|
||||||
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
"tags": "tool",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"storage": [
|
||||||
|
{"name":"angles.app.js","url":"app.js"},
|
||||||
|
{"name":"angles.img","url":"icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -2,3 +2,4 @@
|
||||||
0.02: Allow boot exceptions, e.g. to load DST
|
0.02: Allow boot exceptions, e.g. to load DST
|
||||||
0.03: Permit exceptions to load in low-power mode, e.g. daylight saving time.
|
0.03: Permit exceptions to load in low-power mode, e.g. daylight saving time.
|
||||||
Also avoid polluting global scope.
|
Also avoid polluting global scope.
|
||||||
|
0.04: Enhance menu: enable bluetooth, visit settings & visit recovery
|
||||||
|
|
|
@ -61,14 +61,13 @@ var reload = function () {
|
||||||
nextDraw = undefined;
|
nextDraw = undefined;
|
||||||
},
|
},
|
||||||
btn: function () {
|
btn: function () {
|
||||||
E.showPrompt("Restore watch to full power?").then(function (v) {
|
var menu = {
|
||||||
if (v) {
|
"Restore to full power": drainedRestore,
|
||||||
drainedRestore();
|
"Enable BLE": function () { return NRF.wake(); },
|
||||||
}
|
"Settings": function () { return load("setting.app.js"); },
|
||||||
else {
|
"Recovery": function () { return Bangle.showRecoveryMenu(); },
|
||||||
reload();
|
};
|
||||||
}
|
E.showMenu(menu);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Bangle.CLOCK = 1;
|
Bangle.CLOCK = 1;
|
||||||
|
|
|
@ -79,13 +79,13 @@ const reload = () => {
|
||||||
nextDraw = undefined;
|
nextDraw = undefined;
|
||||||
},
|
},
|
||||||
btn: () => {
|
btn: () => {
|
||||||
E.showPrompt("Restore watch to full power?").then(v => {
|
const menu = {
|
||||||
if(v){
|
"Restore to full power": drainedRestore,
|
||||||
drainedRestore();
|
"Enable BLE": () => NRF.wake(),
|
||||||
}else{
|
"Settings": () => load("setting.app.js"),
|
||||||
reload();
|
"Recovery": () => Bangle.showRecoveryMenu(),
|
||||||
}
|
};
|
||||||
})
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Bangle.CLOCK=1;
|
Bangle.CLOCK=1;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
{
|
{
|
||||||
"id": "drained",
|
"id": "drained",
|
||||||
"name": "Drained",
|
"name": "Drained",
|
||||||
"version": "0.03",
|
"version": "0.04",
|
||||||
"description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals",
|
"description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"type": "clock",
|
|
||||||
"tags": "clock",
|
|
||||||
"supports": ["BANGLEJS2"],
|
"supports": ["BANGLEJS2"],
|
||||||
"allow_emulator": true,
|
"allow_emulator": true,
|
||||||
"storage": [
|
"storage": [
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: First Release
|
||||||
|
0.02: Changing resolution to seconds instead of 5 seconds
|
|
@ -149,9 +149,9 @@ function showMenu()
|
||||||
"START" : function() { startSession(); },
|
"START" : function() { startSession(); },
|
||||||
"Sets" : { value : settings.sets,min:0,max:20,step:1,onchange : v => { settings.sets=v; } },
|
"Sets" : { value : settings.sets,min:0,max:20,step:1,onchange : v => { settings.sets=v; } },
|
||||||
"Work minutes" : { value : settings.workmin,min:0,max:59,step:1,onchange : v => { settings.workmin=v; } },
|
"Work minutes" : { value : settings.workmin,min:0,max:59,step:1,onchange : v => { settings.workmin=v; } },
|
||||||
"Work seconds" : { value : settings.workseg,min:0,max:59,step:5,onchange : v => { settings.workseg=v; } },
|
"Work seconds" : { value : settings.workseg,min:0,max:59,step:1,onchange : v => { settings.workseg=v; } },
|
||||||
"Rest minutes" : { value : settings.restmin,min:0,max:59,step:1,onchange : v => { settings.restmin=v; } },
|
"Rest minutes" : { value : settings.restmin,min:0,max:59,step:1,onchange : v => { settings.restmin=v; } },
|
||||||
"Rest seconds" : { value : settings.restseg,min:0,max:59,step:5,onchange : v => { settings.restseg=v; } },
|
"Rest seconds" : { value : settings.restseg,min:0,max:59,step:1,onchange : v => { settings.restseg=v; } },
|
||||||
"Signal type" : { value : settings.buzz,format : v => v?"Buzz":"Beep",onchange : v => { settings.buzz=v; }}
|
"Signal type" : { value : settings.buzz,format : v => v?"Buzz":"Beep",onchange : v => { settings.buzz=v; }}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "intervals",
|
"id": "intervals",
|
||||||
"name": "Intervals App",
|
"name": "Intervals App",
|
||||||
"shortName": "Intervals",
|
"shortName": "Intervals",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "Intervals for training. It is possible to configure work time and rest time and number of sets.",
|
"description": "Intervals for training. It is possible to configure work time and rest time and number of sets.",
|
||||||
"icon": "intervals.png",
|
"icon": "intervals.png",
|
||||||
"tags": "",
|
"tags": "",
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
Support for fast loading
|
Support for fast loading
|
||||||
0.04: Localisation request: added Miles and AM/PM
|
0.04: Localisation request: added Miles and AM/PM
|
||||||
0.05: Prevent exceptions from halting the draw cycle
|
0.05: Prevent exceptions from halting the draw cycle
|
||||||
|
0.06: Fix Settings page to ensure that the currently set distance is displayed (not 0.75)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "pebbled",
|
"id": "pebbled",
|
||||||
"name": "Pebble Clock with distance",
|
"name": "Pebble Clock with distance",
|
||||||
"shortName": "Pebble + distance",
|
"shortName": "Pebble + distance",
|
||||||
"version": "0.05",
|
"version": "0.06",
|
||||||
"description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).",
|
"description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "pebbled.png",
|
"icon": "pebbled.png",
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Step length': {
|
'Step length': {
|
||||||
value: 0.75 || s.avStep,
|
value: s.avStep || 0.75,
|
||||||
min: 0.2,
|
min: 0.2,
|
||||||
max: 1.5,
|
max: 1.5,
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
0.02: Major speed improvement. Added more stars. Up to 500!
|
0.02: Major speed improvement. Added more stars. Up to 500!
|
||||||
0.03: Added more stars and constellations. Now it shows 20 constellations.
|
0.03: Added more stars and constellations. Now it shows 20 constellations.
|
||||||
0.04: Use default Bangle formatter for booleans
|
0.04: Use default Bangle formatter for booleans
|
||||||
|
0.05: Added more constellations (scorpio and aguila)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "planetarium",
|
"id": "planetarium",
|
||||||
"name": "Planetarium",
|
"name": "Planetarium",
|
||||||
"shortName": "Planetarium",
|
"shortName": "Planetarium",
|
||||||
"version": "0.04",
|
"version": "0.05",
|
||||||
"description": "Planetarium showing up to 500 stars using the watch location and time",
|
"description": "Planetarium showing up to 500 stars using the watch location and time",
|
||||||
"icon": "planetarium.png",
|
"icon": "planetarium.png",
|
||||||
"tags": "",
|
"tags": "",
|
||||||
|
|
|
@ -38,3 +38,7 @@ Draco
|
||||||
e_15 131,131 70,70 382,382 e_15,382 187,187 423,423 e_16,e_16 207,207 122,122 e_17,e_17 232,232 342,342 452,452 428
|
e_15 131,131 70,70 382,382 e_15,382 187,187 423,423 e_16,e_16 207,207 122,122 e_17,e_17 232,232 342,342 452,452 428
|
||||||
Pegasus
|
Pegasus
|
||||||
92 85,138 54,54 85,138 92,283 85,283 389,160 85,92 258,258 297,297 83
|
92 85,138 54,54 85,138 92,283 85,283 389,160 85,92 258,258 297,297 83
|
||||||
|
Aguila
|
||||||
|
12 249,249 271,249 170,249 217,12 365,120 12
|
||||||
|
Scorpius
|
||||||
|
14 105,14 80,14 152,14 137,137 76,332 239,239 41,76 188,188 332,41 181,181 27
|
||||||
|
|
|
|
@ -0,0 +1 @@
|
||||||
|
E.toArrayBuffer(atob("MDAEEREREREREURERERERERERBERERERERERERERERERREREREREREREREEREREREREREREREREURERERERERERERERBERERERERERERERFEREREREREREREREREERERERERERERERREREREREREREREREREQREREREREREREURBEhEURERERERERERERBEREREREREREURBESERIkRERERERERERBERERERERERFEQhERIhEiREREREREREREERERERERERFERCERIiIiJEREREREREREQRERERERERREREERASIiEkREREREREREQRERERERERREREQQERIiEkRERERERERERBEREREREUREREQRERAiIiEkRERERERERBEREREREURERERAERERISEkRERERERERBEREREREUREREREEQAREiJEREREREREREERERERFEREREREIiIRESIUREREREREREERERERFEREREREERABERIRREREREREREERERERFEREREREQREREREhREREREREREERERERFEREREREIiJBERESFEREREREREQRERERFEREREREIiQRERERIUREREREREQRERERRERERERCIiIhEQEREhREREREREQRERERRERERERCIiIiIRERESFEREREREQRERERREREREQiIiIiIiQRESJEREREREQRERERREREREQiIiIiIiIkFBJEREREREQRERERREREREQiIiIiIiJBESEkREREREQRERERREREREQiIiIiIiIiRCIiREREREQRERERREREREQiIiIiIiIiIkQiREREREQRERERREREREQiIiIiIiIiIiIiJEREREQRERERREREREQiIiIiIyIiIiIiIkREREQRERERREREREQiIiIkQjMiIiIkIkREREQRERERREREREREREREQiIiIiJEQiIiMkQRERERREQiIkREQRESIiIiIiJCQiMzIkQRERERREIiIgAAABEBERRCMzMzIiIhARERERERFEIiIiIiIiIzMzMzMzMhAAJAEQVRERERQjMzMzMzMzMzMiIhEAAAAAEiBURBERFCIzMzIiIhERAAAAARERERERESFERBEREUERAAAAAAAAARERERERERFREUJEQhERERERFEREREREREREREREREREREJEQkEREREUREREREREREREREREREREREEkREERERFEREREREREREREREQiJEREREQkRBERERFEJERCIiRCIiIiJEIiIkREREQSERARERESREIiIiIiRERERERERERCREVSIAEREREUREREREREREREREREREREREVREBEREREURERERBFERERERERERERERVEAAREREREQAAABEREREREREUREREREEAAAAAABEREREREREREREREREAAAAAAAAAAAABERERERERERERRERERERBEREREREREREREREREREREREUREREREREREQRERERERERERERERERERERRERERERERBERERERERERER"))
|
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"id": "quoteclock",
|
||||||
|
"name": "Quote Clock",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "A clock showing quotes every hour",
|
||||||
|
"icon": "app.png",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock,shakespeare",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"quoteclock.app.js","url":"app.js"},
|
||||||
|
{"name":"quoteclock.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
|
@ -14,3 +14,4 @@
|
||||||
0.14: cleanup code and fix fastload issue
|
0.14: cleanup code and fix fastload issue
|
||||||
0.15: fix draw before widget hide
|
0.15: fix draw before widget hide
|
||||||
0.16: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps
|
0.16: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps
|
||||||
|
0.17: Add fullscreen option (on by default) to show widgets, adjust sidebar 1 and 2 when fullscreen is off
|
||||||
|
|
|
@ -10,14 +10,22 @@
|
||||||
* Tap top or bottom right to instantly cycle to the next sidebar
|
* Tap top or bottom right to instantly cycle to the next sidebar
|
||||||
* Uses pedometer widget to get latest step count
|
* Uses pedometer widget to get latest step count
|
||||||
* Dependant apps are installed when Rebble installs
|
* Dependant apps are installed when Rebble installs
|
||||||
* Uses the whole screen, widgets are made invisible but still run in the background
|
* When in fullscreen widgets are made invisible but still run in the background
|
||||||
* The icon is James Dean - 'Rebel Without a Cause'
|
* The icon is James Dean - 'Rebel Without a Cause'
|
||||||
|
|
||||||
|
## Fullscreen
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
## With widgets
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## Future Enhancements
|
## Future Enhancements
|
||||||
|
|
||||||
* Support for Weather Icons in the Steps Sidebar
|
* Support for Weather Icons in the Steps Sidebar
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
"id": "rebble",
|
"id": "rebble",
|
||||||
"name": "Rebble Clock",
|
"name": "Rebble Clock",
|
||||||
"shortName": "Rebble",
|
"shortName": "Rebble",
|
||||||
"version": "0.16",
|
"version": "0.17",
|
||||||
"description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion",
|
"description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "rebble.png",
|
"icon": "rebble.png",
|
||||||
"dependencies": {"mylocation":"app"},
|
"dependencies": {"mylocation":"app"},
|
||||||
"screenshots": [{"url":"screenshot_rebble.png"}],
|
"screenshots": [{"url":"screenshot_rebble.png"}, {"url":"screenshot_rebble2.png"}, {"url":"screenshot_rebble3.png"}, {"url":"screenshot_rebble4.png"}, {"url":"screenshot_rebble_w1.png"}, {"url":"screenshot_rebble_w2.png"}, {"url":"screenshot_rebble_w3.png"}],
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"supports": ["BANGLEJS2"],
|
"supports": ["BANGLEJS2"],
|
||||||
|
|
|
@ -40,7 +40,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadSettings=function() {
|
let loadSettings=function() {
|
||||||
settings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true,'sideTap':0};
|
settings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true, 'fullScreen': true, 'sideTap':0};
|
||||||
//sideTap 0 = on | 1 = sidebar1...
|
//sideTap 0 = on | 1 = sidebar1...
|
||||||
|
|
||||||
let tmp = require('Storage').readJSON(SETTINGS_FILE, 1) || settings;
|
let tmp = require('Storage').readJSON(SETTINGS_FILE, 1) || settings;
|
||||||
|
@ -118,32 +118,60 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
|
|
||||||
if (drawCount % 60 == 0)
|
if (drawCount % 60 == 0)
|
||||||
updateSunRiseSunSet(location.lat, location.lon);
|
updateSunRiseSunSet(location.lat, location.lon);
|
||||||
|
|
||||||
g.reset();
|
g.reset();
|
||||||
g.setColor(g.theme.bg);
|
|
||||||
g.fillRect(0, 0, w2, h);
|
if (settings.fullScreen) {
|
||||||
g.setColor(settings.bg);
|
g.setColor(g.theme.bg);
|
||||||
g.fillRect(w2, 0, w, h);
|
g.fillRect(0, 0, w2, h);
|
||||||
|
g.setColor(settings.bg);
|
||||||
|
g.fillRect(w2, 0, w, h);
|
||||||
|
|
||||||
// time
|
// time
|
||||||
g.setColor(g.theme.fg);
|
g.setColor(g.theme.fg);
|
||||||
g.setFontKdamThmor();
|
g.setFontKdamThmor();
|
||||||
g.setFontAlign(0, -1);
|
g.setFontAlign(0, -1);
|
||||||
g.drawString(hh, w2/2, 10 + 0);
|
g.drawString(hh, w2/2, 10 + 0);
|
||||||
g.drawString(mm, w2/2, 10 + h/2);
|
g.drawString(mm, w2/2, 10 + h/2);
|
||||||
|
|
||||||
switch(sideBar) {
|
switch(sideBar) {
|
||||||
case 0:
|
case 0:
|
||||||
drawSideBar1();
|
drawSideBar1();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
drawSideBar2();
|
drawSideBar2();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
drawSideBar3();
|
drawSideBar3();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(0, 24, 113, 176);
|
||||||
|
g.setColor(settings.bg);
|
||||||
|
g.fillRect(113, 24, 176, 176);
|
||||||
|
|
||||||
|
// time
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setFontKdamThmor();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.drawString(hh, 57, 24);
|
||||||
|
g.drawString(mm, 57, 100);
|
||||||
|
|
||||||
|
switch(sideBar) {
|
||||||
|
case 0:
|
||||||
|
drawSideBar1Alt();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
drawSideBar2Alt();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
drawSideBar3();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
drawCount++;
|
drawCount++;
|
||||||
queueDraw();
|
queueDraw();
|
||||||
}
|
}
|
||||||
|
@ -164,6 +192,16 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
|
|
||||||
drawDateAndCalendar(w3, h/2, dy, dd, mm);
|
drawDateAndCalendar(w3, h/2, dy, dd, mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let drawSideBar1Alt=function() {
|
||||||
|
let date = new Date();
|
||||||
|
let dy= require("date_utils").dow(date.getDay(),1).toUpperCase();
|
||||||
|
let dd= date.getDate();
|
||||||
|
let mm= require("date_utils").month(date.getMonth()+1,1).toUpperCase();
|
||||||
|
let yy = date.getFullYear();
|
||||||
|
|
||||||
|
drawDateAndCalendarAlt(145, 46, dy, dd, mm, yy);
|
||||||
|
}
|
||||||
|
|
||||||
let drawSideBar2=function() {
|
let drawSideBar2=function() {
|
||||||
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
||||||
|
@ -178,6 +216,14 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
setSmallFont();
|
setSmallFont();
|
||||||
g.setFontAlign(0, -1);
|
g.setFontAlign(0, -1);
|
||||||
g.drawString(formatSteps(), w3, 7*h/8);
|
g.drawString(formatSteps(), w3, 7*h/8);
|
||||||
|
}
|
||||||
|
|
||||||
|
let drawSideBar2Alt=function() {
|
||||||
|
// steps
|
||||||
|
g.drawImage(boot_img, 113, 59, { scale: 1 });
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.drawString(formatSteps(), 145, 122);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sunrise, sunset times
|
// sunrise, sunset times
|
||||||
|
@ -212,6 +258,28 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
g.setFontAlign(0, -1);
|
g.setFontAlign(0, -1);
|
||||||
g.drawString(mm.toUpperCase(), x, y + 70);
|
g.drawString(mm.toUpperCase(), x, y + 70);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let drawDateAndCalendarAlt=function(x, y, dy, dd, mm, yy) {
|
||||||
|
// day
|
||||||
|
setTextColor();
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.drawString(dy.toUpperCase(), x, y);
|
||||||
|
|
||||||
|
drawCalendar(x - 18, y + 28, 35, 3, dd);
|
||||||
|
|
||||||
|
// month
|
||||||
|
setTextColor();
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.drawString(mm.toUpperCase(), x, y + 70);
|
||||||
|
|
||||||
|
// year
|
||||||
|
setTextColor();
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.drawString(yy, x, y + 94);
|
||||||
|
}
|
||||||
|
|
||||||
// at x,y width:wi thicknes:th
|
// at x,y width:wi thicknes:th
|
||||||
let drawCalendar=function(x,y,wi,th,str) {
|
let drawCalendar=function(x,y,wi,th,str) {
|
||||||
|
@ -311,7 +379,10 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
drawTimeout = undefined;
|
drawTimeout = undefined;
|
||||||
delete Graphics.prototype.setFontKdamThmor;
|
delete Graphics.prototype.setFontKdamThmor;
|
||||||
Bangle.removeListener('charging',chargingListener);
|
|
||||||
|
if (settings.fullScreen) {
|
||||||
|
Bangle.removeListener('charging',chargingListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let main=function(){
|
let main=function(){
|
||||||
|
@ -341,17 +412,17 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Bangle.on('charging',chargingListener);
|
|
||||||
|
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
require("widget_utils").hide();
|
|
||||||
|
if (settings.fullScreen) {
|
||||||
|
Bangle.on('charging',chargingListener);
|
||||||
|
require("widget_utils").hide();
|
||||||
|
} else {
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
const SETTINGS_FILE = "rebble.json";
|
const SETTINGS_FILE = "rebble.json";
|
||||||
|
|
||||||
// initialize with default settings...
|
// initialize with default settings...
|
||||||
let localSettings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true, 'sideTap':0};
|
let localSettings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true, 'fullScreen': true, 'sideTap':0};
|
||||||
//sideTap 0 = on| 1= sideBar1 | 2 = ...
|
//sideTap 0 = on| 1= sideBar1 | 2 = ...
|
||||||
|
|
||||||
// ...and overwrite them with any saved values
|
// ...and overwrite them with any saved values
|
||||||
|
@ -37,6 +37,14 @@
|
||||||
localSettings.bg = bg_code[v];
|
localSettings.bg = bg_code[v];
|
||||||
save();
|
save();
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
'Fullscreen': {
|
||||||
|
value: localSettings.fullScreen,
|
||||||
|
onchange: (v) => {
|
||||||
|
localSettings.fullScreen = v;
|
||||||
|
save();
|
||||||
|
showMenu();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'Auto Cycle': {
|
'Auto Cycle': {
|
||||||
value: localSettings.autoCycle,
|
value: localSettings.autoCycle,
|
||||||
|
@ -74,4 +82,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
showMenu();
|
showMenu();
|
||||||
})
|
})
|
||||||
|
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.0 KiB |
|
@ -1,2 +1 @@
|
||||||
require("heatshrink").decompress(atob("mEwghC/AF8OoMRC6nu8kRiAuT93uGCgWBGCguCGCgsBoMUGCQuBFYMRDAIwQFQUhDAIFCFx/hiUyC4NOGAKMP8MRmYwBjwwBCxkEFAIXBiYwBC4PuC5hxCC4IwCDwPgC5gpBpxxBiMSL4QWMgQpBIIKnEFxsikcxOISODCxkDmUiLIQADFxsjUIQWELp0iLwYuQgMzkUiFydBkcyFycOoMSXoIuST4YuTB4NBZwIuSABAuPAA5dQdSQuBoIXBLwouPiUxGAguOC4imDRh3hC4wuMgBABC44WMgBxBI4wuNgBxCC4MhAoQWNC4IwBU4guOgEBFQVBiguQGAi7PGBCMPGBAuRGAoWSGAYuTAH4AcA="))
|
require("heatshrink").decompress(atob("mEw4cA///ov+5lChWMyGuxdzpdj4/lKf4AUkgQPgm0wAiPy2QCBsBkmS6QRNhIRBrVACJlPu2+pdICBcCrVJlvJtIRLifStMl3MtkARKydUyMkzMl0CMKyWWyUk1MkSJXkyR7BogRLgVcydSrVGzLHKgdLyfSpdE3JYKklqTwNJknJYJVkxcSp+pnygKhMs1OSEQOSYhVJl1bCIbBK5Mq7gRCyARJiVbqyPBCIKMKuVM24yBCIIiJnVOqu5CISMKp9JlvJCIRXKpP3nxoCRhUSBwSMNBwaMMgn6yp6DRhUl0mypiMMgM9ksipaMMhMtCINKRhlJmoRBpJuBCBIRGRhUE5I1CpKMLgmZn5ZDGhUAycnRoNMRhTDCsn3tfkRhLnDTwYQLNgSMMUQkyRhbGEkyMKAApFOAH4AGA"))
|
||||||
|
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEw4cA///w8h7fOm2V/8fjkf/Gt58jKf4AtiVJkmSARFICK3PlnyCJ1t03aEcBZjCBVJCP4R/CK9N8gRPpmUEaGSuRHP+1KCJ8m5AjgI4PyNZ+cAQIQCwgjKCgQRNdP4R/CL4PJAQIRWAH4ApA=="))
|
|
@ -0,0 +1,263 @@
|
||||||
|
/* Espruino VT100 JS REPL
|
||||||
|
|
||||||
|
|
||||||
|
TODO: Add option to connect to a remote BLE device
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var settings = Object.assign({
|
||||||
|
// default values
|
||||||
|
textSize: 1,
|
||||||
|
loopAround: 1,
|
||||||
|
oneToOne: 0,
|
||||||
|
speedScaling: 24
|
||||||
|
}, /*require('Storage').readJSON("repl.settings.json", true) || */{});
|
||||||
|
|
||||||
|
// Key Maps for Keyboard
|
||||||
|
var KEYMAPLOWER = [
|
||||||
|
"`1234567890-=\b\b",
|
||||||
|
"\tqwertyuiop[]\n\n",
|
||||||
|
"\2asdfghjkl;'#\x82\n",
|
||||||
|
"\2\\zxcvbnm,./\x80\x83\x81",
|
||||||
|
];
|
||||||
|
var KEYMAPUPPER = [
|
||||||
|
"¬!\"£$%^&*()_+\b\b",
|
||||||
|
"\tQWERTYUIOP{}\n\n",
|
||||||
|
"\2ASDFGHJKL:@~\x82\n",
|
||||||
|
"\2|ZXCVBNM<>?\x80\x83\x81",
|
||||||
|
];
|
||||||
|
var KEYIMGL = Graphics.createImage(`
|
||||||
|
|
||||||
|
# #
|
||||||
|
## #
|
||||||
|
######
|
||||||
|
## #
|
||||||
|
# #
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
###
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
`);
|
||||||
|
KEYIMGL.transparent = 0;
|
||||||
|
var KEYIMGR = Graphics.createImage(`
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
##
|
||||||
|
#########
|
||||||
|
##
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#######
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
###
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
###
|
||||||
|
#####
|
||||||
|
|
||||||
|
|
||||||
|
# #
|
||||||
|
## ##
|
||||||
|
### ##### ###
|
||||||
|
## ### ##
|
||||||
|
# # #
|
||||||
|
|
||||||
|
`);
|
||||||
|
KEYIMGR.transparent = 0;
|
||||||
|
/* If a char in the keymap is >=128,
|
||||||
|
subtract 128 and look in this array for
|
||||||
|
multi-character key codes*/
|
||||||
|
var KEYEXTRA = [
|
||||||
|
String.fromCharCode(27, 91, 68), // 0x80 left
|
||||||
|
String.fromCharCode(27, 91, 67), // 0x81 right
|
||||||
|
String.fromCharCode(27, 91, 65), // 0x82 up
|
||||||
|
String.fromCharCode(27, 91, 66), // 0x83 down
|
||||||
|
String.fromCharCode(27, 91, 53, 126), // 0x84 page up
|
||||||
|
String.fromCharCode(27, 91, 54, 126), // 0x85 page down
|
||||||
|
];
|
||||||
|
|
||||||
|
// state
|
||||||
|
const R = Bangle.appRect;
|
||||||
|
var kbx = 0,
|
||||||
|
kby = 0,
|
||||||
|
kbdx = 0,
|
||||||
|
kbdy = 0,
|
||||||
|
kbShift = false,
|
||||||
|
flashToggle = false;
|
||||||
|
const PX = 12,
|
||||||
|
PY = 16,
|
||||||
|
DRAGSCALE = settings.speedScaling;
|
||||||
|
var xoff = 0,
|
||||||
|
yoff = g.getHeight() - PY * 4;
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
"ram";
|
||||||
|
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
||||||
|
//g.drawImage(KEYIMG,0,yoff);
|
||||||
|
g.reset().setFont("6x8:2");
|
||||||
|
g.clearRect(R.x, yoff, R.x2, R.y2);
|
||||||
|
if (kbx >= 0)
|
||||||
|
g.setColor(g.theme.bgH).fillRect(xoff + kbx * PX, yoff + kby * PY, xoff + (kbx + 1) * PX - 1, yoff + (kby + 1) * PY - 1).setColor(g.theme.fg);
|
||||||
|
g.drawImage(KEYIMGL, xoff - 1, yoff + PY, { scale: 2 });
|
||||||
|
g.drawImage(KEYIMGR, xoff + PX * 12, yoff, { scale: 2 });
|
||||||
|
var replace = /[\x80\x81\x82\x83\x84\x85]/g;
|
||||||
|
g.drawString(map[0].replace(replace," "), xoff, yoff);
|
||||||
|
g.drawString(map[1].replace(replace," "), xoff, yoff + PY);
|
||||||
|
g.drawString(map[2].replace(replace," "), xoff, yoff + PY * 2);
|
||||||
|
g.drawString(map[3].replace(replace," "), xoff, yoff + PY * 3);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTerminal(dataOutCallback) {
|
||||||
|
g.reset().clearRect(R);
|
||||||
|
// Set up the terminal
|
||||||
|
term = require("VT100").connect(g, {
|
||||||
|
charWidth: 6,
|
||||||
|
charHeight: 8
|
||||||
|
});
|
||||||
|
term.oy = R.y;
|
||||||
|
term.h = yoff; // we added this - it's not usually part of it
|
||||||
|
term.consoleHeight = 0 | ((term.h - term.oy) / term.charH);
|
||||||
|
term.scrollDown = function() {
|
||||||
|
g.setClipRect(R.x, term.y, R.x2, term.oy + term.h);
|
||||||
|
g.scroll(0, -this.charH);
|
||||||
|
g.setClipRect(R.x, R.y, R.x2, R.y2);
|
||||||
|
this.y--;
|
||||||
|
};
|
||||||
|
term.fgCol = g.theme.fg;
|
||||||
|
term.bgCol = g.theme.bg;
|
||||||
|
draw();
|
||||||
|
var flashInterval = setInterval(() => {
|
||||||
|
flashToggle = !flashToggle;
|
||||||
|
draw();
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
function keyPress(kbx, kby) {
|
||||||
|
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
||||||
|
var ch = map[kby][kbx];
|
||||||
|
if (ch == "\2")
|
||||||
|
kbShift = !kbShift;
|
||||||
|
else {
|
||||||
|
if (ch.charCodeAt(0) > 127)
|
||||||
|
ch = KEYEXTRA[ch.charCodeAt(0) - 128];
|
||||||
|
dataOutCallback(ch);
|
||||||
|
}
|
||||||
|
Bangle.buzz(20);
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.setUI({
|
||||||
|
mode: "custom",
|
||||||
|
drag: e => {
|
||||||
|
if (settings.oneToOne) {
|
||||||
|
kbx = Math.max(Math.min(Math.floor((e.x - 16) / (6 * 2)), 13), 0);
|
||||||
|
kby = Math.max(Math.min(Math.floor((e.y - 120) / (8 * 2)), 3), 0);
|
||||||
|
//print(e.y, kby, e.x, kbx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.oneToOne) {
|
||||||
|
kbdx += e.dx;
|
||||||
|
kbdy += e.dy;
|
||||||
|
var dx = Math.round(kbdx / DRAGSCALE),
|
||||||
|
dy = Math.round(kbdy / DRAGSCALE);
|
||||||
|
kbdx -= dx * DRAGSCALE;
|
||||||
|
kbdy -= dy * DRAGSCALE;
|
||||||
|
if (dx || dy) {
|
||||||
|
if (settings.loopAround) {
|
||||||
|
kbx = (kbx + dx + 15) % 15;
|
||||||
|
kby = (kby + dy + 4) % 4;
|
||||||
|
} else {
|
||||||
|
kbx = Math.max(Math.min((kbx + dx), 13), 0);
|
||||||
|
kby = Math.max(Math.min((kby + dy), 3), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw();
|
||||||
|
|
||||||
|
if (!e.b && e.y > Bangle.appRect.y && settings.oneToOne /*&& settings.releaseToSelect*/ )
|
||||||
|
keyPress(kbx, kby);
|
||||||
|
},
|
||||||
|
touch: () => {
|
||||||
|
if (!settings.oneToOne /*|| !settings.releaseToSelect*/ )
|
||||||
|
keyPress(kbx, kby);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let catchSwipe = () => {
|
||||||
|
E.stopEventPropagation && E.stopEventPropagation();
|
||||||
|
};
|
||||||
|
Bangle.prependListener && Bangle.prependListener('swipe', catchSwipe); // Intercept swipes on fw2v19 and later. Should not break on older firmwares.
|
||||||
|
return {
|
||||||
|
dataReceived : function(d) {
|
||||||
|
g.reset().setFont("6x8");
|
||||||
|
// USB.write(e); // optionally mirror back to the PC
|
||||||
|
// Send characters to the terminal
|
||||||
|
for (var i in d) term.char(d[i]);
|
||||||
|
// update the screen
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mainMenu() {
|
||||||
|
E.showMenu({
|
||||||
|
"":{title:"Terminal"},
|
||||||
|
/*LANG*/"JS REPL" : function() {
|
||||||
|
var t = startTerminal(function(d) {
|
||||||
|
LoopbackB.write(d);
|
||||||
|
});
|
||||||
|
LoopbackB.on('data', function(d) {
|
||||||
|
t.dataReceived(d);
|
||||||
|
});
|
||||||
|
// Now move the console to Loopback
|
||||||
|
LoopbackA.setConsole();
|
||||||
|
},
|
||||||
|
/*LANG*/"Bluetooth" : function() {
|
||||||
|
Bangle.setUI();
|
||||||
|
E.showMessage(/*LANG*/"Scanning...", /*LANG*/"Bluetooth");
|
||||||
|
NRF.findDevices(function(devices) {
|
||||||
|
if (!devices.length)
|
||||||
|
return E.showAlert("No devices found").then(() => mainMenu());
|
||||||
|
var menu = { "" : { title: /*LANG*/"Bluetooth", back : () => mainMenu() } };
|
||||||
|
devices.forEach(dev => {
|
||||||
|
var name = dev.name || dev.id.substr(0,17);
|
||||||
|
menu[name] = function() {
|
||||||
|
Bangle.setUI();
|
||||||
|
E.showMessage(/*LANG*/"Connecting...", /*LANG*/"Bluetooth");
|
||||||
|
require("ble_uart").connect(dev).then(function(uart) {
|
||||||
|
var t = startTerminal(function(d) {
|
||||||
|
uart.write(d);
|
||||||
|
});
|
||||||
|
t.dataReceived("Connected to:\n "+name+"\n")
|
||||||
|
uart.on('data', function(d) { t.dataReceived(d); });
|
||||||
|
}).catch(err => {
|
||||||
|
E.showAlert(err.toString()).then(() => mainMenu());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
E.showMenu(menu);
|
||||||
|
}, { filters: [{ services: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e'] }], timeout: 2000, active:true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mainMenu();
|
After Width: | Height: | Size: 393 B |
|
@ -0,0 +1,14 @@
|
||||||
|
{ "id": "terminal",
|
||||||
|
"name": "VT100 Terminal",
|
||||||
|
"shortName":"Terminal",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Terminal and Keyboard that can be used as a REPL. You can type JS commands into Bangle.js's own REPL and execute them, or you can connect to other Bluetooth LE UART devices (like other Espruinos) and issue commands.",
|
||||||
|
"icon": "app.png",
|
||||||
|
"tags": "terminal,tool,bluetooth",
|
||||||
|
"screenshots" : [ { "url":"screenshot1.png" }, { "url":"screenshot2.png" } ],
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"storage": [
|
||||||
|
{"name":"terminal.app.js","url":"app.js"},
|
||||||
|
{"name":"terminal.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
|
@ -2,3 +2,5 @@
|
||||||
0.02: Better controls, implement game over.
|
0.02: Better controls, implement game over.
|
||||||
0.03: Implement mode and level selection screens.
|
0.03: Implement mode and level selection screens.
|
||||||
0.04: Bring back old controls as "swipe" in menu, exit with button press
|
0.04: Bring back old controls as "swipe" in menu, exit with button press
|
||||||
|
0.10: Major overhaul: added score, levels, bugfixes and misc, inspired by NES tetris
|
||||||
|
0.11: Save/Restore game state
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "tetris",
|
{ "id": "tetris",
|
||||||
"name": "Tetris",
|
"name": "Tetris",
|
||||||
"shortName":"Tetris",
|
"shortName":"Tetris",
|
||||||
"version":"0.04",
|
"version":"0.11",
|
||||||
"description": "Tetris",
|
"description": "Tetris",
|
||||||
"icon": "tetris.png",
|
"icon": "tetris.png",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
@ -12,5 +12,8 @@
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"tetris.app.js","url":"tetris.app.js"},
|
{"name":"tetris.app.js","url":"tetris.app.js"},
|
||||||
{"name":"tetris.img","url":"app-icon.js","evaluate":true}
|
{"name":"tetris.img","url":"app-icon.js","evaluate":true}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"name":"tetris.json"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,26 +36,45 @@ const tiles = [
|
||||||
const ox = 176/2 - 5*8;
|
const ox = 176/2 - 5*8;
|
||||||
const oy = 8;
|
const oy = 8;
|
||||||
|
|
||||||
|
const FILE = "tetris.json";
|
||||||
|
|
||||||
|
const settings = Object.assign({
|
||||||
/* 0 .. simulated arrows
|
/* 0 .. simulated arrows
|
||||||
1 .. drag piece
|
1 .. drag piece
|
||||||
2 .. accelerometer. 12 lines record.
|
2 .. accelerometer. 12 lines record.
|
||||||
3 .. altimeter
|
3 .. altimeter
|
||||||
*/
|
*/
|
||||||
var control = 0, level = 0;
|
control: 0,
|
||||||
|
level: 0,
|
||||||
|
initialLevel: 0,
|
||||||
|
lines: 0,
|
||||||
|
score: 0,
|
||||||
|
pf: undefined,
|
||||||
|
ctn: Math.floor(Math.random()*7), // current tile number
|
||||||
|
ntn: Math.floor(Math.random()*7), // next tile number
|
||||||
|
ntr: Math.floor(Math.random()*4), // next tile rotation
|
||||||
|
dropInterval: undefined,
|
||||||
|
}, require('Storage').readJSON(FILE, true) || {});
|
||||||
|
|
||||||
var alt_start = -9999; /* For altimeter control */
|
var alt_start = -9999; /* For altimeter control */
|
||||||
/* 0 .. menu
|
/* 0 .. menu
|
||||||
1 .. game
|
1 .. game
|
||||||
2 .. game over */
|
2 .. game over */
|
||||||
var state = 0;
|
var state = 0;
|
||||||
|
|
||||||
var pf;
|
var px=4, py=0;
|
||||||
|
|
||||||
|
function writeSettings() {
|
||||||
|
require('Storage').writeJSON(FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function initGame() {
|
function initGame() {
|
||||||
pf = Array(23).fill().map(()=>Array(12).fill(0)); // field is really 10x20, but adding a border for collision checks
|
settings.pf = Array(23).fill().map(()=>Array(12).fill(0)); // field is really 10x20, but adding a border for collision checks
|
||||||
pf[20].fill(1);
|
settings.pf[20].fill(1);
|
||||||
pf[21].fill(1);
|
settings.pf[21].fill(1);
|
||||||
pf[22].fill(1);
|
settings.pf[22].fill(1);
|
||||||
pf.forEach((x,i) => { pf[i][0] = 1; pf[i][11] = 1; });
|
settings.pf.forEach((x,i) => { settings.pf[i][0] = 1; settings.pf[i][11] = 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
function rotateTile(t, r) {
|
function rotateTile(t, r) {
|
||||||
|
@ -71,13 +90,18 @@ function rotateTile(t, r) {
|
||||||
return nt;
|
return nt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var time = Date.now();
|
||||||
|
var ct = rotateTile(tiles[settings.ctn], Math.floor(Math.random()*4)); // current tile (rotated)
|
||||||
|
|
||||||
function drawBoundingBox() {
|
function drawBoundingBox() {
|
||||||
g.setBgColor(0, 0, 0).clear().setColor(1, 1, 1);
|
g.setBgColor(0, 0, 0).clear().setColor(1, 1, 1);
|
||||||
g.theme.bg = 0;
|
g.theme.bg = 0;
|
||||||
for (i=0; i<4; ++i) g.drawRect(ox-i-1, oy-i-1, ox+10*8+i, oy+20*8+i);
|
for (i=0; i<4; ++i) g.drawRect(ox-i-1, oy-i-1, ox+10*8+i, oy+20*8+i);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTile (tile, n, x, y, qClear) {
|
function drawTile(tile, n, x, y, qClear) {
|
||||||
|
if (state != 1) // stops tile from being drawn on the game over screen
|
||||||
|
return;
|
||||||
if (qClear) g.setColor(0);
|
if (qClear) g.setColor(0);
|
||||||
else g.setColor(tcols[n].r, tcols[n].g, tcols[n].b);
|
else g.setColor(tcols[n].r, tcols[n].g, tcols[n].b);
|
||||||
for (i=0; i<tile.length; ++i)
|
for (i=0; i<tile.length; ++i)
|
||||||
|
@ -90,58 +114,133 @@ function drawTile (tile, n, x, y, qClear) {
|
||||||
function showNext(n, r) {
|
function showNext(n, r) {
|
||||||
var nt = rotateTile(tiles[n], r);
|
var nt = rotateTile(tiles[n], r);
|
||||||
g.setColor(0).fillRect(176-33, 40, 176-33+33, 82);
|
g.setColor(0).fillRect(176-33, 40, 176-33+33, 82);
|
||||||
drawTile(nt, ntn, 176-33, 40);
|
drawTile(nt, settings.ntn, 176-33, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
var time = Date.now();
|
function calculateSpeed() {
|
||||||
var px=4, py=0;
|
let step = 500;
|
||||||
var ctn = Math.floor(Math.random()*7); // current tile number
|
if (settings.level <= 6) // 200-500ms
|
||||||
var ntn = Math.floor(Math.random()*7); // next tile number
|
step = step - 50*settings.level;
|
||||||
var ntr = Math.floor(Math.random()*4); // next tile rotation
|
else if (settings.level <= 13) { // 25-175ms
|
||||||
var ct = rotateTile(tiles[ctn], Math.floor(Math.random()*4)); // current tile (rotated)
|
step = 200;
|
||||||
var dropInterval = 450;
|
step = step - 25*(settings.level - 6);
|
||||||
var nlines = 0;
|
}
|
||||||
|
else {
|
||||||
|
step = 20; // usually limited by the hardware
|
||||||
|
// levels 15+ are programmed to go faster by skipping lines
|
||||||
|
}
|
||||||
|
print(`level ${settings.level}: drop interval ${step}ms`);
|
||||||
|
if (settings.control == 3)
|
||||||
|
step = step*2;
|
||||||
|
dropInterval = step;
|
||||||
|
}
|
||||||
|
|
||||||
function redrawPF(ly) {
|
function redrawPF(ly) {
|
||||||
for (y=0; y<=ly; ++y)
|
for (y=0; y<=ly; ++y)
|
||||||
for (x=1; x<11; ++x) {
|
for (x=1; x<11; ++x) {
|
||||||
c = pf[y][x];
|
c = settings.pf[y][x];
|
||||||
if (c>0) g.setColor(tcols[c-1].r, tcols[c-1].g, tcols[c-1].b).drawImage(block, ox+(x-1)*8, oy+y*8);
|
if (c>0) g.setColor(tcols[c-1].r, tcols[c-1].g, tcols[c-1].b).drawImage(block, ox+(x-1)*8, oy+y*8);
|
||||||
else g.setColor(0, 0, 0).fillRect(ox+(x-1)*8, oy+y*8, ox+x*8-1, oy+(y+1)*8-1);
|
else g.setColor(0, 0, 0).fillRect(ox+(x-1)*8, oy+y*8, ox+x*8-1, oy+(y+1)*8-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function gameOver() {
|
function gameOver() {
|
||||||
|
state = 0;
|
||||||
g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22)
|
g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22)
|
||||||
.drawString("Game Over", 176/2, 76);
|
.drawString("Game Over", 176/2, 76);
|
||||||
state = 0;
|
// this cannot allow changing game controls because it would set up duplicate events
|
||||||
E.showAlert("Game Over").then(selectGame, print);
|
E.showAlert("Game Over").then(newGame, print);
|
||||||
|
settings.lines = 0;
|
||||||
|
settings.score = 0;
|
||||||
|
settings.level = settings.initialLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redrawStats(onlyScore) {
|
||||||
|
g.setColor(0).fillRect(5, 30, 41, 60)
|
||||||
|
.setColor(1, 1, 1).drawString(settings.score.toString(), 22, 50);
|
||||||
|
if (!onlyScore) {
|
||||||
|
g.setColor(0).fillRect(5, 80, 41, 110)
|
||||||
|
.setColor(1, 1, 1).drawString(settings.level.toString(), 22, 100)
|
||||||
|
.setColor(0).fillRect(5, 130, 41, 160)
|
||||||
|
.setColor(1, 1, 1).drawString(settings.lines.toString(), 22, 150);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertAndCheck() {
|
function insertAndCheck() {
|
||||||
for (y=0; y<ct.length; ++y)
|
// stop pieces from falling into each other
|
||||||
for (x=0; x<ct[y].length; ++x)
|
for (let y=0; y<ct.length; ++y)
|
||||||
if (ct[y][x]>0) pf[py+y][px+x+1] = ctn+1;
|
for (let x=0; x<ct[y].length; ++x)
|
||||||
|
if (ct[y][x]>0) settings.pf[py+y][px+x+1] = settings.ctn+1;
|
||||||
|
let clearCount = 0;
|
||||||
|
let linesToClear = [];
|
||||||
|
let yReal = 19; // the y for display purposes
|
||||||
// check for full lines
|
// check for full lines
|
||||||
for (y=19; y>0; y--) {
|
for (let y=19; y>0; y--) {
|
||||||
var qFull = true;
|
var qFull = true;
|
||||||
for (x=1; x<11; ++x) qFull &= pf[y][x]>0;
|
for (let x=1; x<11; ++x) qFull &= settings.pf[y][x]>0;
|
||||||
if (qFull) {
|
if (qFull) {
|
||||||
nlines++;
|
clearCount++;
|
||||||
dropInterval -= 5;
|
linesToClear.push([y, yReal]);
|
||||||
Bangle.buzz(30);
|
print(`linesToClear.push(${y})`);
|
||||||
for (ny=y; ny>0; ny--) pf[ny] = JSON.parse(JSON.stringify(pf[ny-1]));
|
// clear the line, but do not display it yet
|
||||||
redrawPF(y);
|
for (ny=y; ny>0; ny--) settings.pf[ny] = JSON.parse(JSON.stringify(settings.pf[ny-1]));
|
||||||
g.setColor(0).fillRect(5, 30, 41, 80).setColor(1, 1, 1).drawString(nlines.toString(), 22, 50);
|
y++;
|
||||||
}
|
}
|
||||||
|
yReal--;
|
||||||
|
}
|
||||||
|
if (clearCount) {
|
||||||
|
settings.lines += clearCount;
|
||||||
|
let effectiveLevel = Math.max(settings.level, 1);
|
||||||
|
if (clearCount == 1) { // single
|
||||||
|
settings.score += 100 * effectiveLevel;
|
||||||
|
Bangle.buzz(80, 0.5);
|
||||||
|
}
|
||||||
|
else if (clearCount == 2) { // double
|
||||||
|
settings.score += 300 * effectiveLevel;
|
||||||
|
Bangle.buzz(80);
|
||||||
|
}
|
||||||
|
else if (clearCount == 3) { // triple
|
||||||
|
settings.score += 500 * effectiveLevel;
|
||||||
|
Bangle.buzz(200);
|
||||||
|
}
|
||||||
|
else if (clearCount >= 4) { // tetris
|
||||||
|
settings.score += 800 * effectiveLevel;
|
||||||
|
Bangle.buzz(500);
|
||||||
|
}
|
||||||
|
// the score will not be shown yet because redrawStats was not called
|
||||||
|
|
||||||
|
// clear effect
|
||||||
|
let timer = getTime();
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
while (true) {
|
||||||
|
var rectLength = (getTime()-timer)/0.05 + 1;
|
||||||
|
if (rectLength > 6)
|
||||||
|
break;
|
||||||
|
var x1 = 6 - rectLength;
|
||||||
|
var x2 = 4 + rectLength;
|
||||||
|
for (let line of linesToClear) {
|
||||||
|
let y = line[1];
|
||||||
|
g.fillRect(ox+x1*8, oy+y*8, ox+x2*8-1, oy+(y+1)*8-1);
|
||||||
|
}
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
// display the cleared lines
|
||||||
|
for (let line of linesToClear) {
|
||||||
|
redrawPF(line[0]);
|
||||||
|
}
|
||||||
|
if (settings.lines != 0 && settings.lines % 10 == 0) {
|
||||||
|
settings.level++;
|
||||||
|
calculateSpeed();
|
||||||
|
}
|
||||||
|
redrawStats();
|
||||||
}
|
}
|
||||||
// spawn new tile
|
// spawn new tile
|
||||||
px = 4; py = 0;
|
px = 4; py = 0;
|
||||||
ctn = ntn;
|
settings.ctn = settings.ntn;
|
||||||
ntn = Math.floor(Math.random()*7);
|
settings.ntn = Math.floor(Math.random()*7);
|
||||||
ct = rotateTile(tiles[ctn], ntr);
|
ct = rotateTile(tiles[settings.ctn], settings.ntr);
|
||||||
ntr = Math.floor(Math.random()*4);
|
settings.ntr = Math.floor(Math.random()*4);
|
||||||
showNext(ntn, ntr);
|
showNext(settings.ntn, settings.ntr);
|
||||||
if (!moveOk(ct, 0, 0)) {
|
if (!moveOk(ct, 0, 0)) {
|
||||||
gameOver();
|
gameOver();
|
||||||
}
|
}
|
||||||
|
@ -149,48 +248,76 @@ function insertAndCheck() {
|
||||||
|
|
||||||
function moveOk(t, dx, dy) {
|
function moveOk(t, dx, dy) {
|
||||||
var ok = true;
|
var ok = true;
|
||||||
for (y=0; y<t.length; ++y)
|
for (y=0; y<t.length; ++y)
|
||||||
for (x=0; x<t[y].length; ++x)
|
for (x=0; x<t[y].length; ++x)
|
||||||
if (t[y][x]*pf[py+dy+y][px+dx+x+1] > 0) ok = false;
|
if (t[y][x]*settings.pf[py+dy+y][px+dx+x+1] > 0) ok = false;
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pauseGame() {
|
||||||
|
//print("Paused");
|
||||||
|
state = 3;
|
||||||
|
E.showMenu({
|
||||||
|
"" : { "title" : /*LANG*/"Pause menu" },
|
||||||
|
"< Back" : () => resumeGame(),
|
||||||
|
/*LANG*/"Exit" : () => {
|
||||||
|
writeSettings();
|
||||||
|
load();
|
||||||
|
},
|
||||||
|
/*LANG*/"New game": () => newGame(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resumeGame() {
|
||||||
|
//print("Resumed");
|
||||||
|
state = 1;
|
||||||
|
drawGame();
|
||||||
|
redrawPF(19);
|
||||||
|
}
|
||||||
|
|
||||||
function gameStep() {
|
function gameStep() {
|
||||||
if (state != 1)
|
if (state != 1)
|
||||||
return;
|
return;
|
||||||
if (Date.now()-time > dropInterval) { // drop one step
|
if (Date.now()-time > dropInterval) { // drop one step
|
||||||
time = Date.now();
|
time = Date.now();
|
||||||
if (moveOk(ct, 0, 1)) {
|
if (settings.level >= 15 && moveOk(ct, 0, 2)) {
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, true);
|
// at level 15, pieces drop twile as quickly
|
||||||
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
|
py += 2;
|
||||||
|
}
|
||||||
|
else if (moveOk(ct, 0, 1)) {
|
||||||
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
py++;
|
py++;
|
||||||
}
|
}
|
||||||
else { // reached the bottom
|
else { // reached the bottom
|
||||||
insertAndCheck(ct, ctn, px, py);
|
insertAndCheck(ct, settings.ctn, px, py);
|
||||||
}
|
}
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rotate() {
|
function rotate() {
|
||||||
t = rotateTile(ct, 3);
|
t = rotateTile(ct, 3);
|
||||||
if (moveOk(t, 0, 0)) {
|
if (moveOk(t, 0, 0)) {
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, true);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
ct = t;
|
ct = t;
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(x, y) {
|
function move(x, y) {
|
||||||
if (moveOk(ct, x, y)) {
|
r = moveOk(ct, x, y);
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, true);
|
if (r) {
|
||||||
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
px += x;
|
px += x;
|
||||||
py += y;
|
py += y;
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, false);
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
function linear(x) {
|
function linear(x) {
|
||||||
print("Linear: ", x);
|
//print("Linear: ", x);
|
||||||
let now = px / 10;
|
let now = px / 10;
|
||||||
if (x < now-0.06)
|
if (x < now-0.06)
|
||||||
move(-1, 0);
|
move(-1, 0);
|
||||||
|
@ -198,126 +325,150 @@ function linear(x) {
|
||||||
move(1, 0);
|
move(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newGame() {
|
function setupControls() {
|
||||||
E.showMenu();
|
if (settings.control == 4) { // Swipe
|
||||||
Bangle.setUI({mode : "custom", btn: () => load()});
|
|
||||||
if (control == 4) { // Swipe
|
|
||||||
Bangle.on("touch", (e) => {
|
Bangle.on("touch", (e) => {
|
||||||
t = rotateTile(ct, 3);
|
t = rotateTile(ct, 3);
|
||||||
if (moveOk(t, 0, 0)) {
|
if (moveOk(t, 0, 0)) {
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, true);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
ct = t;
|
ct = t;
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.on("swipe", (x,y) => {
|
Bangle.on("swipe", (x,y) => {
|
||||||
if (y<0) y = 0;
|
if (y<0) y = 0;
|
||||||
if (moveOk(ct, x, y)) {
|
if (moveOk(ct, x, y)) {
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, true);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, true);
|
||||||
px += x;
|
px += x;
|
||||||
py += y;
|
py += y;
|
||||||
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
|
drawTile(ct, settings.ctn, ox+px*8, oy+py*8, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else { // control != 4
|
} else { // control != 4
|
||||||
if (control == 2) { // Tilt
|
if (settings.control == 2) { // Tilt
|
||||||
Bangle.on("accel", (e) => {
|
Bangle.on("accel", (e) => {
|
||||||
if (state != 1) return;
|
if (state != 1) return;
|
||||||
if (control != 2) return;
|
if (settings.control != 2) return;
|
||||||
print(e.x);
|
print(e.x);
|
||||||
linear((0.2-e.x) * 2.5);
|
linear((0.2-e.x) * 2.5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (control == 3) { // Move
|
if (settings.control == 3) { // Pressure
|
||||||
Bangle.setBarometerPower(true);
|
Bangle.setBarometerPower(true);
|
||||||
Bangle.on("pressure", (e) => {
|
Bangle.on("pressure", (e) => {
|
||||||
if (state != 1) return;
|
if (state != 1) return;
|
||||||
if (control != 3) return;
|
if (settings.control != 3) return;
|
||||||
let a = e.altitude;
|
let a = e.altitude;
|
||||||
if (alt_start == -9999)
|
if (alt_start == -9999)
|
||||||
alt_start = a;
|
alt_start = a;
|
||||||
a = a - alt_start;
|
a = a - alt_start;
|
||||||
print(e.altitude, a);
|
//print(e.altitude, a);
|
||||||
linear(a);
|
linear(a);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Bangle.on("drag", (e) => {
|
Bangle.on("drag", (e) => {
|
||||||
let h = 176/2;
|
let h = 176/2;
|
||||||
if (state == 2) {
|
if (state == 2) {
|
||||||
if (e.b)
|
if (e.b)
|
||||||
selectGame();
|
selectGame();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!e.b)
|
|
||||||
return;
|
|
||||||
if (state == 0) return;
|
|
||||||
if (e.y < h) {
|
|
||||||
if (e.x < h)
|
|
||||||
rotate();
|
|
||||||
else {
|
|
||||||
let i = 0;
|
|
||||||
for (i=0; i<10; i++) {
|
|
||||||
move(0, 1);
|
|
||||||
g.flip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (control == 1)
|
|
||||||
linear((e.x - 20) / 156);
|
|
||||||
if (control != 0)
|
|
||||||
return;
|
return;
|
||||||
if (e.x < h)
|
}
|
||||||
move(-1, 0);
|
if (!e.b)
|
||||||
else
|
return;
|
||||||
move(1, 0);
|
if (state == 0) return;
|
||||||
}
|
if (e.y < h) {
|
||||||
|
if (e.x < h)
|
||||||
|
rotate();
|
||||||
|
else {
|
||||||
|
while (move(0, 1)) {
|
||||||
|
settings.score++;
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
redrawStats(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (settings.control == 1)
|
||||||
|
linear((e.x - 20) / 156);
|
||||||
|
if (settings.control != 0)
|
||||||
|
return;
|
||||||
|
if (e.x < h)
|
||||||
|
move(-1, 0);
|
||||||
|
else
|
||||||
|
move(1, 0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function newGame() {
|
||||||
|
settings.lines = 0;
|
||||||
|
settings.score = 0;
|
||||||
|
settings.level = settings.initialLevel;
|
||||||
initGame();
|
initGame();
|
||||||
drawGame();
|
startGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startGame() {
|
||||||
|
calculateSpeed();
|
||||||
state = 1;
|
state = 1;
|
||||||
var step = 450 - 50*level;
|
drawGame();
|
||||||
if (control == 3)
|
var gi = setInterval(gameStep, 20);
|
||||||
step = step*2;
|
|
||||||
dropInterval = step;
|
|
||||||
var gi = setInterval(gameStep, 50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawGame() {
|
function drawGame() {
|
||||||
|
Bangle.setUI({mode : "custom", btn: () => {
|
||||||
|
if (state == 1) {
|
||||||
|
pauseGame();
|
||||||
|
}
|
||||||
|
}});
|
||||||
drawBoundingBox();
|
drawBoundingBox();
|
||||||
g.setColor(1, 1, 1).setFontAlign(0, 1, 0)
|
g.setColor(1, 1, 1).setFontAlign(0, 1, 0)
|
||||||
.setFont("6x15", 1).drawString("Lines", 22, 30)
|
.setFont("6x15", 1).drawString("Score", 22, 30)
|
||||||
|
.drawString("Level", 22, 80)
|
||||||
|
.drawString("Lines", 22, 130)
|
||||||
.drawString("Next", 176-22, 30);
|
.drawString("Next", 176-22, 30);
|
||||||
showNext(ntn, ntr);
|
redrawStats();
|
||||||
g.setColor(0).fillRect(5, 30, 41, 80)
|
showNext(settings.ntn, settings.ntr);
|
||||||
.setColor(1, 1, 1).drawString(nlines.toString(), 22, 50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLevel() {
|
|
||||||
print("Level selection menu");
|
|
||||||
|
|
||||||
var menu = {};
|
|
||||||
menu["< Back"] = () => {selectGame();};
|
|
||||||
menu[/*LANG*/"Level 1"] = () => { level = 0; selectGame(); };
|
|
||||||
menu[/*LANG*/"Level 2"] = () => { level = 1; selectGame(); };
|
|
||||||
menu[/*LANG*/"Level 3"] = () => { level = 2; selectGame(); };
|
|
||||||
E.showMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectGame() {
|
function selectGame() {
|
||||||
state = 0;
|
state = 0;
|
||||||
print("Game selection menu");
|
//print("Game selection menu");
|
||||||
//for (let i = 0; i < 100000; i++) ;
|
|
||||||
|
|
||||||
var menu = {};
|
var menu = {};
|
||||||
menu[/*LANG*/"Normal"] = () => { control = 0; newGame(); };
|
menu[/*LANG*/"New game"] = () => {
|
||||||
menu[/*LANG*/"Drag"] = () => { control = 1; newGame(); };
|
setupControls();
|
||||||
menu[/*LANG*/"Tilt"] = () => { control = 2; newGame(); };
|
newGame();
|
||||||
menu[/*LANG*/"Move"] = () => { control = 3; newGame(); };
|
resumeGame();
|
||||||
menu[/*LANG*/"Swipe"] = () => { control = 4; newGame(); };
|
};
|
||||||
menu[/*LANG*/"Level"] = () => { selectLevel(); };
|
if (settings.pf !== undefined) {
|
||||||
|
menu[/*LANG*/"Resume game"] = () => {
|
||||||
|
setupControls();
|
||||||
|
startGame();
|
||||||
|
resumeGame();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
menu[/*LANG*/"Controls"] = {
|
||||||
|
value: settings.control,
|
||||||
|
min: 0, max: 4,
|
||||||
|
format: v => [/*LANG*/"Normal", /*LANG*/"Drag", /*LANG*/"Tilt", /*LANG*/"Pressure", /*LANG*/"Swipe"][v],
|
||||||
|
onchange: v => {
|
||||||
|
settings.control = v;
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
menu[/*LANG*/"Level"] = {
|
||||||
|
value : 1,
|
||||||
|
min : 0,
|
||||||
|
max : 10,
|
||||||
|
wrap : true,
|
||||||
|
onchange : (l) => {
|
||||||
|
settings.initialLevel = l;
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ if (window.location.host=="banglejs.com") {
|
||||||
'This is not the official Bangle.js App Loader - you can try the <a href="https://banglejs.com/apps/">Official Version</a> here.';
|
'This is not the official Bangle.js App Loader - you can try the <a href="https://banglejs.com/apps/">Official Version</a> here.';
|
||||||
}
|
}
|
||||||
|
|
||||||
var RECOMMENDED_VERSION = "2v19";
|
var RECOMMENDED_VERSION = "2v20";
|
||||||
// could check http://www.espruino.com/json/BANGLEJS.json for this
|
// could check http://www.espruino.com/json/BANGLEJS.json for this
|
||||||
|
|
||||||
// We're only interested in Bangles
|
// We're only interested in Bangles
|
||||||
|
|