*add starpoint cutoffs for bag, curtain, toad and sunlight goals

*save level scores in json format to cope with randomised levels
*lev 6 help references both llamas and alpacas
*make goalbooster effect actualy work
*tweak random goal numbers - too low - add a minimum cutoff
*try to make height correct on android tablets
*add happy birthday message
This commit is contained in:
Rob Pearce 2016-09-05 14:22:21 +10:00
parent 807bd533f1
commit 3088b74816
2 changed files with 126 additions and 267 deletions

379
cat.html
View File

@ -1127,46 +1127,58 @@ function countthingsoftype(type) {
} }
var playerdata = { var playerdata = {
totstars: 0,
levscore: [], levscore: [],
saveall : function() { saveall : function() {
if (game.cheat) return; if (game.cheat) return;
this.savetotstars();
for (i = 0; i < this.levscore.length; i++) {
savelevscore(i);
}
},
savetotstars : function() { console.log("*** saving tot stars = " + this.totstars);
// save max level // save max level
if (game.cheat) return;
localStorage.setItem('totstars',this.totstars); localStorage.setItem('totstars',this.totstars);
},
savelevscore : function(lev) { // save level scores
if (game.cheat) return; localStorage.setItem("levscores", JSON.stringify(this.levscore));
localStorage.setItem("levscore" + lev, this.levscore[lev]);
}, },
load : function() { load : function() {
var num,i; var num,i,temp;
// local star count // local star count
num = localStorage.getItem('totstars'); num = localStorage.getItem('totstars');
if (num != undefined) { if (num != undefined) {
this.totstars = num; this.totstars = num;
console.log("playerdata.load() - totstars is " + this.totstars); console.log("playerdata.load() - totstars is " + this.totstars);
} else {
console.log("playerdata.load() - couldn't find totstars");
this.totstars = 0;
} }
// load scores
temp = localStorage.getItem("levscores");
if (temp == undefined) {
this.levscore = [];
} else {
this.levscore = JSON.parse(temp);
}
/*
// save level scores
localStorage.setItem("levscores", JSON.stringify(this.levscore));
// load level hiscores // load level hiscores
for (i = 0; i < game.levels.length; i++) { for (i = 0; i < game.levels.length; i++) {
num = localStorage.getItem("levscore" + i); num = localStorage.getItem("levscore" + i);
if (num == undefined) { if (num == undefined) {
this.levscore[i] = 0; this.levscore[i] = 0;
} else { } else {
//console.log("load() - lev " + i + " score " + num);
this.levscore[i] = num; this.levscore[i] = num;
console.log("playerdata.load() - lev " + i + " score is " + num);
} }
console.log("load() - lev " + i + " score is " + this.levscore[i]);
} }
*/
// calculate player stars based on scores // calculate player stars based on scores
this.settotstars(game.countplayerstars()); this.settotstars(game.countplayerstars());
@ -1181,23 +1193,27 @@ var playerdata = {
}, },
clearall : function() { clearall : function() {
localStorage.removeItem("maxlevel"); // old one //localStorage.removeItem("maxlevel"); // old one
/*
localStorage.removeItem("totstars"); localStorage.removeItem("totstars");
for (i = 0; i < game.levels.length; i++) { for (i = 0; i < 100; i++) {
localStorage.removeItem("levscore" + i); localStorage.removeItem("levscore" + i);
} }
*/
localStorage.clear();
console.log("cleared local storage."); console.log("cleared local storage.");
}, },
settotstars : function(num) { settotstars : function(num) {
console.log("playerdata() - setting total stars to " + num); console.log("settotstars() - setting total stars to " + num);
this.totstars = num; this.totstars = num;
this.savetotstars(); this.saveall();
}, },
setlevscore : function(lev, num) { setlevscore : function(lev, num) {
this.levscore[lev] = num; this.levscore[lev] = num;
this.savelevscore(lev); this.saveall();
}, },
}; };
@ -1309,7 +1325,7 @@ var game = {
}, (rnd(3)+1) * 1000); }, (rnd(3)+1) * 1000);
*/ */
nimages++; nimages++;
console.log(nimages + " / " + maximages + " images loaded."); //console.log(nimages + " / " + maximages + " images loaded.");
}, },
drawloader : function() { drawloader : function() {
@ -1457,7 +1473,8 @@ var game = {
// hide address bar on phones // hide address bar on phones
if (game.android || game.ios) { if (game.android || game.ios) {
document.body.style.height = (window.innerHeight + 50) + 'px'; //document.body.style.height = (window.innerHeight + 50) + 'px';
document.body.style.height = (game.curh + 50) + 'px';
} }
// scale canvas // scale canvas
@ -1654,19 +1671,24 @@ var game = {
} }
for (i = 0; i < ngoals; i++) { for (i = 0; i < ngoals; i++) {
var max,maxcount; var mm,min,max,count;
// turn goal percentages into actual numbers // turn goal percentages into actual numbers
max = game.getgoalmax(lev, game.levels[lev].goals[i].type); mm = game.getgoalminmax(lev, game.levels[lev].goals[i].type);
maxcount = Math.floor((game.levels[lev].goals[i].count / 100) * max)
if (maxcount < 1) maxcount = 1; min = mm[0];
max = mm[1];
console.log("genrandomlev() - lev " + lev + " goal " + i + " type=" + game.levels[lev].goals[i].type + " min="+min + " max=" + max);
game.levels[lev].goals[i].count = maxcount; count = min + Math.floor((game.levels[lev].goals[i].count / 100) * (max - min))
if (count < 1) count = 1;
game.levels[lev].goals[i].count = count;
// add forced things based on goals // add forced things based on goals
switch (game.levels[lev].goals[i].type) { switch (game.levels[lev].goals[i].type) {
case "brick": case "brick":
game.addlevelforcethings(game.levels[lev].goals[i].type, maxcount); game.addlevelforcethings(game.levels[lev].goals[i].type, count);
break; break;
} }
} }
@ -1793,6 +1815,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
calcstars : function (lev, points) { calcstars : function (lev, points) {
var i; var i;
for (i = 2; i >= 0; i--) { for (i = 2; i >= 0; i--) {
if (this.levels[lev] == undefined) {
console.log("** error - lev " + lev + " is undefined");
}
if (points >= this.levels[lev].starpoints[i]) { if (points >= this.levels[lev].starpoints[i]) {
return (i+1); return (i+1);
} }
@ -1821,40 +1846,57 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.levels[lev].starpoints[2] = p3; this.levels[lev].starpoints[2] = p3;
}, },
getgoalmax : function (lev, gtype) { getgoalminmax : function (lev, gtype) {
var max = -1; var min = 1,max = -1;
switch (gtype) { switch (gtype) {
case "food": case "food":
min = lev * 0.5;
max = lev * 1.2; max = lev * 1.2;
break; break;
case "llama": case "llama":
min = lev * 0.16;
max = lev * 0.5; max = lev * 0.5;
break; break;
case "cat": case "cat":
min = lev * 0.8;
max = lev * 1.5; max = lev * 1.5;
break; break;
case "goat": case "goat":
min = lev * 0.17;
max = lev * 0.25; max = lev * 0.25;
break; break;
case "brick": case "brick":
min = lev * 0.03;
max = lev * 0.1; max = lev * 0.1;
break; break;
case "door": case "door":
min = lev * 0.03;
max = lev * 0.1; max = lev * 0.1;
break; break;
case "sun": case "sunlight":
max = lev * 0.6; min = lev * 0.06;
max = lev * 0.16;
break; break;
case "bag": case "bag":
nbags = game.getmaxbags(lev); min = 1;
max = game.getmaxbags(lev);
break;
case "toad":
min = lev * 0.06;
max = lev * 0.15;
break; break;
default: // should never happen default: // should never happen
min = 1;
max = lev * 0.2; max = lev * 0.2;
break; break;
} }
min = Math.floor(min);
max = Math.floor(max); max = Math.floor(max);
if (max < 1) max = 1;
return max; if (min < 1) min = 1;
if (max < min) max = min;
return [ min, max];
}, },
calclevparams : function( lev ) { calclevparams : function( lev ) {
@ -1900,10 +1942,22 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * 3 * 2 * this.levels[lev].goals[i].count; min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * 3 * 2 * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * 1; turnsreq += this.levels[lev].goals[i].count * 1;
break; break;
case "sun": case "sunlight":
min += SLEEPYCATPOINTS*5 * this.levels[lev].goals[i].count; min += Math.min(CATPOINTS, SLEEPYCATPOINTS)*this.levels[lev].gridh * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].gridh; turnsreq += this.levels[lev].gridh;
break; break;
case "curtain":
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * 1.2;
break;
case "bag":
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * BAGCAPACITY * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * 1.2;
break;
case "toad":
min += Math.min(CATPOINTS, SLEEPYCATPOINTS)*this.levels[lev].gridh * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * 2;
break;
} }
} }
@ -2370,7 +2424,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
col = "#00cc00"; col = "#00cc00";
texttodraw = "OVERLOAD!"; texttodraw = "OVERLOAD!";
break; break;
case "sun": case "sunlight":
// do nothing // do nothing
break; break;
case "shears": case "shears":
@ -2766,6 +2820,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var titlexoff = 0; var titlexoff = 0;
var titley = 10; var titley = 10;
var creditsy = 64; var creditsy = 64;
var birthdayy = 96;
var textgrad; var textgrad;
// background // background
@ -2789,6 +2844,16 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
shadowtext(this.context, "Cat Parade", TITLETEXTSIZE,"red", SCREENW / 2 - titlexoff, titley, "#ff0000", "#ffff00", "white"); shadowtext(this.context, "Cat Parade", TITLETEXTSIZE,"red", SCREENW / 2 - titlexoff, titley, "#ff0000", "#ffff00", "white");
shadowtext(this.context, "rpearce, 2016", TITLECREDITTEXTSIZE, "#00aaee", SCREENW / 2 - titlexoff, creditsy); shadowtext(this.context, "rpearce, 2016", TITLECREDITTEXTSIZE, "#00aaee", SCREENW / 2 - titlexoff, creditsy);
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1;
var yy = today.getFullYear();
// 11th sep
if (dd == 11 && mm == 9) {
shadowtext(this.context, "HAPPY BIRTHDAY BETH!", TITLECREDITTEXTSIZE, "#ff0000", SCREENW / 2 - titlexoff, birthdayy);
}
this.context.textBaseline = "bottom"; this.context.textBaseline = "bottom";
shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2 + titlexoff, SCREENH - 64); shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2 + titlexoff, SCREENH - 64);
}, },
@ -2805,6 +2870,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var total = 0; var total = 0;
for (i = 1 ; i < game.levels.length; i++ ) { for (i = 1 ; i < game.levels.length; i++ ) {
console.log("countplayerstars() - lev " + i + " score " + playerdata.getlevscore(i) + " stars " + game.calcstars(i, playerdata.getlevscore(i)));
total += game.calcstars(i, playerdata.getlevscore(i)); total += game.calcstars(i, playerdata.getlevscore(i));
} }
return total; return total;
@ -2878,222 +2944,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// original help text for reference. maybe use this // original help text for reference. maybe use this
// for a 'continuous mode' later. // for a 'continuous mode' later.
if (curlevel == -1) { if (curlevel == 1) {
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Drag a cat to eat cheese.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "Cats can eat any amount of cheese.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "Cats can only eat cheese in a straight line.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "Cats get tired after eating and cannot eat again.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
// help on eating
// row 1
x = imgsize;
y = cury;
row1y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x2 = x + gridsize;
y2 = y;
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
ctx.strokeStyle = PATHLINECOLGOOD;
ctx.lineWidth = LINEWIDTH;
ctx.beginPath();
ctx.moveTo(x + imgsize/2, y + imgsize/2);
ctx.lineTo(x2 + imgsize/2, y2 + imgsize/2);
ctx.stroke();
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
cury = y2 + gridsize;
// row 2
x = imgsize;
y = cury;
row2y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x2 = x + gridsize;
y2 = y;
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
x2 = x2 + gridsize;
y2 = y;
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
x2 = x2 + gridsize;
y2 = y;
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
cury = y2 + gridsize;
// arrow to middle
x = x2 + gridsize;
y = row1y + (imgsize);
x2 = x + gridsize*1.5;
y2 = y;
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
// middle
ctx.textAlign = "center";
ctx.textBaseline = "top";
x = midpoint1;
y = row1y+10;
shadowtext(ctx, "+" + FOODPOINTS + " points", HELPTEXTSIZE,pointscol, x, y);
y = row2y-10;
shadowtext(ctx, "per cheese", HELPTEXTSIZE,pointscol, x, y);
// arrow to right
x = midpoint1 + gridsize + 10;
y = row1y + (imgsize);
x2 = SCREENW - imgsize*2;
y2 = y;
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
// right
x = SCREENW - imgsize*2;
y = row1y;
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
y = row2y;
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
// LLAMA HELP
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Cats are scared of " + llamatext + "s and can't move when near them.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
x = (SCREENW / 2) - gridsize/2 - gridsize;
y = cury;
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
x += gridsize;
y = cury;
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
x += gridsize;
y = cury;
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
// PARADE HELP
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Drag a path through multiple cats to start a parade.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, " - Parades can turn corners.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, " - Parades can include one " + llamatext + " only.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
// top line of parade
x = imgsize;
y = cury;
row1y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[0] = x + imgsize/2;
liney[0] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
linex[3] = x + imgsize/2;
liney[3] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
linex[4] = x + imgsize/2;
liney[4] = y + imgsize/2;
x += gridsize;
x = imgsize;
y += gridsize;
row2y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[1] = x + imgsize/2;
liney[1] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
linex[2] = x + imgsize/2;
liney[2] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
linex[5] = x + imgsize/2;
liney[5] = y + imgsize/2;
cury = y + HELPTEXTYSPACE;
for (i = 0; i < 4; i++) {
drawline(ctx, linex[i], liney[i], linex[i+1], liney[i+1], PATHLINECOLGOOD, LINEWIDTH);
}
drawarrow(ctx, linex[4], liney[4], linex[5], liney[5], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
// arrow to middle
x = x + gridsize;
y = row1y + (imgsize);
x2 = midpoint2 - 10;
y2 = y;
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
// explain points for parades
ctx.textAlign = "left";
ctx.textBaseline = "top";
x = midpoint2;
y = row1y;
shadowtext(ctx, "+" + CATPOINTS + " points per cat", HELPTEXTSIZE,pointscol, x, y);
y += HELPTEXTYSPACE;
shadowtext(ctx, "+" + SLEEPYCATPOINTS + " points per sleepy cat", HELPTEXTSIZE,pointscol, x, y);
y += HELPTEXTYSPACE;
shadowtext(ctx, "+" + LLAMAPOINTS + " points per " + llamatext, HELPTEXTSIZE,pointscol, x, y);
cury = y + HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
// GAME OVER HELP
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "You fail the level if there are no valid moves left.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
ctx.textAlign = "center";
this.context.textBaseline = "bottom";
shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2, SCREENH - HELPTEXTYSPACE*2);
} else if (curlevel == 1) {
cury = this.drawhelpsubtitle(ctx, "Chomping Food", cury); cury = this.drawhelpsubtitle(ctx, "Chomping Food", cury);
ctx.textAlign = "left"; ctx.textAlign = "left";
@ -3750,7 +3601,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
ctx.textBaseline = "bottom"; ctx.textBaseline = "bottom";
shadowtext(ctx, "Goats and cats can gang up on " + llamatext + "s.", HELPTEXTSIZE,helpcol, textxspace, cury); shadowtext(ctx, "Goats and cats can gang up on " + llamatext + "s.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
shadowtext(ctx, "Parades with a goat can contain any number of llamas.", HELPTEXTSIZE,helpcol, textxspace, cury); shadowtext(ctx, "Parades with a goat can contain any number of " + llamatext + "s.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
// top line of parade // top line of parade
@ -3851,7 +3702,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
y += HELPTEXTYSPACE; y += HELPTEXTYSPACE;
cury = y; cury = y;
shadowtext(ctx, "Goats can't start parades. Parades must start with a cat.", HELPTEXTSIZE,helpcol, textxspace, cury); shadowtext(ctx, "Goats can't start parades.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "Parades must start with a cat.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE * 1.5; cury += HELPTEXTYSPACE * 1.5;
// bad example // bad example
@ -5176,7 +5029,13 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// create it if required. // create it if required.
if (!game.levelexists(levnum)) { if (!game.levelexists(levnum)) {
game.genrandomlevel(levnum); var n;
// create levels up to this one
for (n = 1; n <= levnum; n++) {
if (!game.levelexists(n)) {
game.genrandomlevel(n);
}
}
} }
randomlev = game.levels[levnum].random; randomlev = game.levels[levnum].random;
@ -5804,8 +5663,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
} }
//console.log("goat coords " + this.goatx + "," + this.goaty + " dir " + this.goatdir);
console.log("goat coords " + this.goatx + "," + this.goaty + " dir " + this.goatdir);
}, },
@ -5870,6 +5728,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
GRIDW = DEF_GRIDW; GRIDW = DEF_GRIDW;
GRIDH = DEF_GRIDH; GRIDH = DEF_GRIDH;
console.log("going to levsel state, game.countplayerstars() is " + game.countplayerstars());
// count player stars // count player stars
playerdata.settotstars(game.countplayerstars()); playerdata.settotstars(game.countplayerstars());
@ -6430,8 +6289,8 @@ dodb = true;
} }
} }
if (goalthings.indexOf(type)) { if (goalthings.indexOf(type) != -1) {
console.log("resetting goalbooster"); console.log("got type '" + type + "' - goalthing is '" + goalthings + "' - resetting goalbooster");
game.goalbooster = 0; game.goalbooster = 0;
} }
@ -7842,7 +7701,7 @@ function mainloop() {
// otherwise levels with turn limits won't work. // otherwise levels with turn limits won't work.
// record score // record score
if (score > playerdata.levscore[curlevel]) { if (playerdata.levscore[curlevel] == null || score > playerdata.levscore[curlevel]) {
playerdata.setlevscore(curlevel, score); playerdata.setlevscore(curlevel, score);
} }

14
todo
View File

@ -9,14 +9,14 @@ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/
--- check here for ios --- check here for ios
------------------- -------------------
*add starpoint cutoffs for bag, curtain, toad and sunlight goals
*save level scores in json format to cope with randomised levels
*lev 6 help references both llamas and alpacas
*make goalbooster effect actualy work
*tweak random goal numbers - too low - add a minimum cutoff
*try to make height correct on android tablets
*add happy birthday message
*random levels.
*bugfix: cat-in-boat to goat should okay
*when forcing an goal object because we have none, make the chance higher based on how many things we're dropping.
*add more win images
* make win images sequential rather than random.
tweak random goal numbers
sometimes add random bricks sometimes add random bricks
randoms: randoms: