*move goal progress increments to thing.kill() function

*Make 'allowedthings' default to previous level's one.
*fix lev6 help
*bugfix: whitecats aren't ever appearing randomly?
*new object: bricks
*Don't allow extending path off the top of the grid.
*fix incorrect pluralisation "foods" in goal text
This commit is contained in:
Rob Pearce 2016-08-31 13:55:35 +10:00
parent b5dedbe0ad
commit 9176b45a50
6 changed files with 518 additions and 101 deletions

557
cat.html
View File

@ -74,6 +74,8 @@ var TURNSBARSPEEDUP = 0.02;
var TURNSBARSPEEDDOWN = 0.01; var TURNSBARSPEEDDOWN = 0.01;
var BAGCAPACITY = 6; // how many cats to pop a bag var BAGCAPACITY = 6; // how many cats to pop a bag
var BRICKHP = 9; // how many cats it takes to remove a brick
var SLASHDIST = 3; // space between slash marks on bricks
// for background // for background
var catalpha = 1.0; var catalpha = 1.0;
@ -90,14 +92,16 @@ var GOALVERB = {
'cat': 'Clear', 'cat': 'Clear',
'goat': 'Clear', 'goat': 'Clear',
'door': 'Enter', 'door': 'Enter',
'sun': 'Wait out', 'sunlight': 'Wait out',
'bag': 'Burst', 'bag': 'Burst',
'toad': 'Slap', 'toad': 'Slap',
'whitecat': 'Attack', 'whitecat': 'Attack',
'brick': 'Break',
}; };
var GOALNAME = { var GOALNAME = {
'whitecat': 'white cat', 'whitecat': 'white cat',
'sunlight': 'sun',
}; };
var prizetypes = [ var prizetypes = [
@ -300,6 +304,21 @@ function loadimage(name, filename) {
image[name].src = filename; image[name].src = filename;
} }
function gridxyhasthingtype(gridx, gridy, wanttype) {
var i;
if (things == undefined) return null;
// only include non-animating things
for (i = 0; i < things.length; i += 1) {
if ((things[i].gridx == gridx) && (things[i].gridy == gridy) && (things[i].type == wanttype)) {
if (!things[i].isanimating()) {
return things[i];
}
}
}
return null;
}
function getgridthing(gridx, gridy) { function getgridthing(gridx, gridy) {
var i; var i;
if (things == undefined) return null; if (things == undefined) return null;
@ -572,6 +591,10 @@ function canextendpath(overthing) {
if (!overthing) return false; if (!overthing) return false;
if (!isongrid(overthing.gridx, overthing.gridy)) {
return false;
}
pathtype = getpathtype(); pathtype = getpathtype();
if ( isadjacent(overthing, curpath[curpath.length-1]) && // adjacent to last thing in path? if ( isadjacent(overthing, curpath[curpath.length-1]) && // adjacent to last thing in path?
@ -829,6 +852,50 @@ function isadjacenttotype(what, wanttype, exceptionthing) {
return false; return false;
} }
function addslash(slashes, w, h) {
slashes.push(Math.floor(rnd(w))); // x1
slashes.push(Math.floor(rnd(h))); // y1
slashes.push(Math.floor(rnd(w))); // x2
slashes.push(Math.floor(rnd(h))); // y2
}
function drawslashes(ctx, x, y, slashes) {
var i,n;
if (slashes == undefined || slashes.length <= 0) {
return;
}
for (i = 0; i < slashes.length; i+= 4) {
var dx,dy,xstep,ystep,angle;
// get angle of line
dx = slashes[i+2] - slashes[i];
dy = slashes[i+1] - slashes[i+3];
//console.log("dxy is " + dx + "," + dy);
angle = Math.atan2(dy,dx);
//angle *= 180/Math.PI; // degrees
// add 90 degrees
angle += 90;
// back to radians
//angle *= Math.PI/180;
xstep = Math.cos(angle);
ystep = Math.sin(angle);
//console.log("line " + i + " - angle is " + (angle * 180/Math.PI) + " steps are " + xstep + "," + ystep);
for (n = 0; n < 3; n++) {
var modx,mody;
modx = xstep * n * SLASHDIST;
mody = ystep * n * SLASHDIST;
drawline(ctx, x + slashes[i] + modx, y + slashes[i+1] + mody,
x + slashes[i+2] + modx, y + slashes[i+3] + mody,
"black", 1);
}
}
}
function drawline(ctx,x1,y1,x2,y2,col,width) { function drawline(ctx,x1,y1,x2,y2,col,width) {
ctx.strokeStyle = col; ctx.strokeStyle = col;
ctx.lineWidth = width; ctx.lineWidth = width;
@ -1276,6 +1343,18 @@ var game = {
}, },
// x1, x2, y2, x3, y3....
addlevelbricks : function () {
var lev,newbrick,i;
lev = this.levels.length - 1;
for (i = 0 ; i < arguments.length; i += 2) {
newbrick = new Object();
newbrick.gridx = arguments[i];
newbrick.gridy = arguments[i+1];
this.levels[lev].bricks.push(newbrick);
}
},
addlevelbag : function (lev, y ) { addlevelbag : function (lev, y ) {
var mybag; var mybag;
mybag = new Object(); mybag = new Object();
@ -1294,9 +1373,9 @@ var game = {
mylevel.goals = new Array(); mylevel.goals = new Array();
mylevel.thinglist = new Array(); mylevel.thinglist = new Array();
mylevel.forcelist = new Array(); mylevel.forcelist = new Array();
mylevel.allowedthings = new Array();
mylevel.maxturns = lev + 4; // default mylevel.maxturns = lev + 4; // default
mylevel.bags = []; mylevel.bags = [];
mylevel.bricks = [];
if (lev == 1) { if (lev == 1) {
mylevel.gridsize = DEF_GRIDSIZE; mylevel.gridsize = DEF_GRIDSIZE;
@ -1313,6 +1392,14 @@ var game = {
mylevel.boardx = this.levels[lev-1].boardx; mylevel.boardx = this.levels[lev-1].boardx;
} }
mylevel.allowedthings = new Array();
if (lev > 1) {
// default to allowed things from previous level.
for (i = 0; i < this.levels[lev-1].allowedthings.length; i++) {
mylevel.allowedthings.push(this.levels[lev-1].allowedthings[i]);
}
}
this.levels[lev] = mylevel; this.levels[lev] = mylevel;
playerdata.levscore[lev] = 0; playerdata.levscore[lev] = 0;
@ -1388,6 +1475,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
progress : function(type, amt) { progress : function(type, amt) {
var i; var i;
if (game.state != "running") return false;
// past last level! // past last level!
if (curlevel >= game.levels.length) return false; if (curlevel >= game.levels.length) return false;
@ -1473,6 +1562,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
min += GOATPOINTS * this.levels[lev].goals[i].count; min += GOATPOINTS * 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 "brick":
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * (BRICKHP/3) * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * (BRICKHP/3); // avg parades to kill it, maybe a bit less
break;
case "turn": case "turn":
// assume you'll get a parade on most turns. // assume you'll get a parade on most turns.
num = (Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count); num = (Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count);
@ -1542,6 +1635,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.levels = []; this.levels = [];
this.addlevel(1, true); this.addlevel(1, true);
this.addlevelgoals("food", 5); this.addlevelgoals("food", 5);
this.addlevelallowedthings("cat", "food");
this.setstarpoints(1, 50, 60, 80); this.setstarpoints(1, 50, 60, 80);
this.addlevelthings( "cat", 50, "food", 50); this.addlevelthings( "cat", 50, "food", 50);
@ -1550,41 +1644,38 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.addlevelthings("cat", 45, "food", 55); this.addlevelthings("cat", 45, "food", 55);
this.addlevel(3, true); this.addlevel(3, true);
this.addlevelallowedthings("cat", "food", "llama"); this.addlevelallowedthings("llama");
this.addlevelgoals("llama", 4); this.addlevelgoals("llama", 4);
this.addlevel(4, true); this.addlevel(4, true);
this.addlevelgoals("llama", 5); this.addlevelgoals("llama", 5);
this.addlevelgoals("food", 5); this.addlevelgoals("food", 5);
this.addlevelallowedthings("cat", "food", "llama");
this.addlevel(5, true); this.addlevel(5, true);
this.addlevelgridwid(5, 6); this.addlevelgridwid(5, 6);
this.addlevelgoals("bag", 1); this.addlevelgoals("bag", 1);
this.addlevelgoals("turn", 10); this.addlevelgoals("turn", 10);
//this.addlevelgoals(5, "points", 600); //this.addlevelgoals(5, "points", 600);
this.addlevelallowedthings("cat", "food", "llama");
// introduce goats! // introduce goats!
this.addlevel(6, true); this.addlevel(6, true);
this.addlevelallowedthings("goat");
this.addlevelgoals("goat", 3); this.addlevelgoals("goat", 3);
this.addlevelthings("goat", 10, "cat", 50, "food", 30, "llama", 10); // higher than normal goat chance this.addlevelthings("goat", 10, "cat", 50, "food", 30, "llama", 10); // higher than normal goat chance
this.addlevelforcethings("goat", 1); this.addlevelforcethings("goat", 1);
this.addlevel(7, false); this.addlevel(7, false);
this.addlevelallowedthings("goat", "cat", "food", "llama");
this.addlevelgoals("llama", 6); this.addlevelgoals("llama", 6);
this.addlevelgoals("goat", 3); this.addlevelgoals("goat", 3);
this.addlevel(8, false); this.addlevel(8, false);
this.addlevelallowedthings("goat", "cat", "food", "llama");
this.addlevelgoals("llama", 6); this.addlevelgoals("llama", 6);
this.addlevelgoals("goat", 4); this.addlevelgoals("goat", 4);
this.addlevelgoals("food", 5); this.addlevelgoals("food", 5);
// introduce doors // introduce doors
this.addlevel(9, true); this.addlevel(9, true);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door"); this.addlevelallowedthings("door");
this.addlevelgoals("door", 1); this.addlevelgoals("door", 1);
this.addlevelgoals("llama", 5); this.addlevelgoals("llama", 5);
this.addlevelgoals("cat", 13); this.addlevelgoals("cat", 13);
@ -1592,20 +1683,19 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.addlevel(10, false); this.addlevel(10, false);
this.addlevelgridwid(10, 7); this.addlevelgridwid(10, 7);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door");
this.addlevelgoals("turn", 15); this.addlevelgoals("turn", 15);
// introduce sunlight // introduce sunlight
this.addlevel(11, true); this.addlevel(11, true);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); this.addlevelallowedthings("sunlight");
this.addlevelgoals("cat", 13); this.addlevelgoals("cat", 13);
this.addlevelgoals("food", 5); this.addlevelgoals("food", 5);
this.addlevelgoals("sun", 1); this.addlevelgoals("sunlight", 1);
this.addlevelforcethings("sunlight", 1); this.addlevelforcethings("sunlight", 1);
// introduce whitecat // introduce whitecat
this.addlevel(12, true); this.addlevel(12, true);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "whitecat"); this.addlevelallowedthings("whitecat");
this.addlevelgoals("cat", 15); this.addlevelgoals("cat", 15);
this.addlevelgoals("whitecat", 1); this.addlevelgoals("whitecat", 1);
this.addlevelgoals("llama", 6); this.addlevelgoals("llama", 6);
@ -1613,24 +1703,45 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// introduce toad // introduce toad
this.addlevel(13, true); this.addlevel(13, true);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad"); this.addlevelallowedthings("toad");
this.addlevelgoals("toad", 1); this.addlevelgoals("toad", 1);
this.addlevelgoals("cat", 20); this.addlevelgoals("cat", 20);
this.addlevelgoals("llama", 5); this.addlevelgoals("llama", 5);
this.addlevelforcethings("toad", 1); this.addlevelforcethings("toad", 1);
this.addlevel(14, false); this.addlevel(14, false);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad");
this.addlevelgoals("cat", 25); this.addlevelgoals("cat", 25);
this.addlevelgoals("llama", 6); this.addlevelgoals("llama", 6);
this.addlevelgoals("food", 15); this.addlevelgoals("food", 15);
this.addlevel(15, false); // introduce bricks
this.addlevel(15, true);
this.addlevelgridwid(15, 8); this.addlevelgridwid(15, 8);
this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad"); this.addlevelallowedthings("brick");
this.addlevelgoals("cat", 30); this.addlevelgoals("brick", 2);
this.addlevelgoals("llama", 7); this.addlevelbricks(3, 3,
this.addlevelgoals("food", 20); 4, 4
);
this.addlevel(16, false);
this.addlevelbricks(3, 3, 4, 3,
3, 4, 4, 4
);
this.addlevelgoals("brick", 4);
this.addlevel(17, false);
this.addlevelbricks(0,4, 1,4, 2,4, 3,4, 4,4, 5,4, 6,4, 7,4);
this.addlevelgoals("cat", 25);
this.addlevelgoals("llama", 6);
/*
hard brick pattern
this.addlevelbricks(2, 2, 5, 2,
2, 5, 5, 5
);
*/
for (i = 1; i < this.levels.length; i++) { for (i = 1; i < this.levels.length; i++) {
var extrastars; var extrastars;
@ -1671,18 +1782,27 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
populategrid : function() { populategrid : function() {
var i; var i;
while (!anyvalidmoves()) { while (!anyvalidmoves()) {
var x,y,found; var x,y,found,i;
console.log("populating grid..."); console.log("populating grid...");
clearthings(); clearthings();
// populate initial things // add bricks
for (i = 0; i < game.levels[curlevel].bricks.length; i++) {
x = game.levels[curlevel].bricks[i].gridx;
y = game.levels[curlevel].bricks[i].gridy;
things.push(new thing(x, y, "brick"));
console.log("adding brick at " + x + "," + y);
}
// populate initial things in all other spots
for (y = 0; y < GRIDH; y++) { for (y = 0; y < GRIDH; y++) {
for (x = 0; x < GRIDW; x++) { for (x = 0; x < GRIDW; x++) {
// start off above the grid if (!getgridthing(x, y)) {
things.push(new thing(x, y, "random")); things.push(new thing(x, y, "random"));
} }
} }
}
// fix up problems // fix up problems
donesomething=true; donesomething=true;
@ -1698,8 +1818,11 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// while we don't have enough... // while we don't have enough...
while (countthingsoftype(wanttype) < wantnum) { while (countthingsoftype(wanttype) < wantnum) {
// add one. // add one.
var idx; var idx = -1;
// don't overwrite bricks
while (idx == -1 || things[idx].type == "brick") {
idx = rnd(things.length); idx = rnd(things.length);
}
things[idx].type = wanttype; things[idx].type = wanttype;
donesomething = true; donesomething = true;
} }
@ -1944,7 +2067,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// goal description // goal description
var ess = "s"; var ess = "s";
if (this.levels[curlevel].goals[n].count == 1) { if (this.levels[curlevel].goals[n].type == "food") {
ess = "";
} else if (this.levels[curlevel].goals[n].count == 1) {
ess = ""; ess = "";
} }
@ -3108,13 +3233,13 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// next one // next one
x = midpoint2 + gridsize; x = midpoint2 + gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize); //ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize; x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize); //ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize; x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize); //ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize; x += gridsize;
@ -3136,7 +3261,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2;
shadowtext(ctx, "Tissue Box", HELPTEXTSIZE, pointscol, shadowtext(ctx, "Tissue Box", HELPTEXTSIZE, pointscol,
THINGSIZE*1.5, y); THINGSIZE*1.5, y);
shadowtext(ctx, "Wakes all sleeping cats.", HELPTEXTSIZE, pointscoldark, shadowtext(ctx, "All sleeping cats wake up.", HELPTEXTSIZE, pointscoldark,
THINGSIZE*1.5, y + HELPTEXTYSPACE); THINGSIZE*1.5, y + HELPTEXTYSPACE);
ctx.drawImage(image['tissues'], textxspace, cury, THINGSIZE, THINGSIZE); ctx.drawImage(image['tissues'], textxspace, cury, THINGSIZE, THINGSIZE);
cury += GRIDSIZE; cury += GRIDSIZE;
@ -3144,7 +3269,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2;
shadowtext(ctx, "Shears", HELPTEXTSIZE, pointscol, shadowtext(ctx, "Shears", HELPTEXTSIZE, pointscol,
THINGSIZE*1.5, y); THINGSIZE*1.5, y);
shadowtext(ctx, "Immediately clears all " + llamatext + "s.", HELPTEXTSIZE, pointscoldark, shadowtext(ctx, "All " + llamatext + "s immediately run away.", HELPTEXTSIZE, pointscoldark,
THINGSIZE*1.5, y + HELPTEXTYSPACE); THINGSIZE*1.5, y + HELPTEXTYSPACE);
ctx.drawImage(image['shears'], textxspace, cury, THINGSIZE, THINGSIZE); ctx.drawImage(image['shears'], textxspace, cury, THINGSIZE, THINGSIZE);
cury += GRIDSIZE; cury += GRIDSIZE;
@ -3152,10 +3277,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2;
shadowtext(ctx, "Magic Carpet", HELPTEXTSIZE, pointscol, shadowtext(ctx, "Magic Carpet", HELPTEXTSIZE, pointscol,
THINGSIZE*1.5, y); THINGSIZE*1.5, y);
shadowtext(ctx, "Grants a magic fez to all cats.", shadowtext(ctx, "Cats are given a magic fez.",
HELPTEXTSIZE, pointscoldark, HELPTEXTSIZE, pointscoldark,
THINGSIZE*1.5, y + HELPTEXTYSPACE); THINGSIZE*1.5, y + HELPTEXTYSPACE);
shadowtext(ctx, "Fez wearing cats are not scared of " + llamatext + "s.", shadowtext(ctx, "Fez-wearing cats are not scared of " + llamatext + "s.",
HELPTEXTSIZE, pointscoldark, HELPTEXTSIZE, pointscoldark,
THINGSIZE*1.5, y + HELPTEXTYSPACE*2); THINGSIZE*1.5, y + HELPTEXTYSPACE*2);
ctx.drawImage(image['magiccarpet'], textxspace, cury, THINGSIZE, THINGSIZE); ctx.drawImage(image['magiccarpet'], textxspace, cury, THINGSIZE, THINGSIZE);
@ -3263,6 +3388,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
y += HELPTEXTYSPACE; y += HELPTEXTYSPACE;
shadowtext(ctx, "+" + GOATPOINTS + " points per goat", HELPTEXTSIZE,pointscol, x, y); shadowtext(ctx, "+" + GOATPOINTS + " points per goat", HELPTEXTSIZE,pointscol, x, y);
y += HELPTEXTYSPACE;
y += HELPTEXTYSPACE;
y += HELPTEXTYSPACE;
y += HELPTEXTYSPACE; y += HELPTEXTYSPACE;
y += HELPTEXTYSPACE; y += HELPTEXTYSPACE;
cury = y; cury = y;
@ -3681,12 +3809,19 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize); ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize; x += gridsize;
cury = y;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Cats must be awake to attack white cats.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
} else if (curlevel == 13) { } else if (curlevel == 13) {
cury = this.drawhelpsubtitle(ctx, "Toad", cury); cury = this.drawhelpsubtitle(ctx, "Toads", cury);
ctx.textAlign = "left"; ctx.textAlign = "left";
ctx.textBaseline = "bottom"; ctx.textBaseline = "bottom";
@ -3824,6 +3959,206 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// line to toad falling // line to toad falling
drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], "#dddd00", LINEWIDTH, PATHARROWSIZE); drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], "#dddd00", LINEWIDTH, PATHARROWSIZE);
cury = y;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Cats must be awake to slap toads.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
} else if (curlevel == 15) {
var tempslashes;
cury = this.drawhelpsubtitle(ctx, "Bricks", cury);
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Like doors, bricks don't fall downwards.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "Hit bricks with parades to damage them.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
// top line of brick demo
x = imgsize;
y = cury;
row1y = y;
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
linex[1] = x + imgsize/2;
liney[1] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['brick'], x, y, imgsize, imgsize);
linex[2] = x + imgsize/2;
liney[2] = y + imgsize/2;
x += gridsize;
x = imgsize;
y += gridsize;
row2y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[0] = x + imgsize/2;
liney[0] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
// line to show path
drawline(ctx, linex[0], liney[0], linex[1], liney[1], PATHLINECOLGOOD, LINEWIDTH);
drawarrow(ctx, linex[1], liney[1], linex[2], liney[2], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
// arrow to middle
drawarrow(ctx, x + gridsize/2, row2y, midpoint2 - 10, row2y, "red", HELPLINEWIDTH, HELPARROWSIZE);
// damage explanation
ctx.textAlign = "left";
ctx.textBaseline = "middle";
shadowtext(ctx, "(3 damage)", HELPTEXTSIZE,"#dddd00", midpoint2 + gridsize*3 , row2y);
x = midpoint2;
y = cury;
row1y = y;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['brick'], x, y, imgsize, imgsize);
tempslashes = [ imgsize * 0.10, imgsize * 0.25, imgsize * 0.90, imgsize * 0.75 ];
drawslashes(ctx, x, y, tempslashes);
x += gridsize;
x = midpoint2;
y += gridsize;
row2y = y;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
cury = y;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "After " + BRICKHP + " damage, bricks will break.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
// top line of brick breaking demo
x = imgsize;
y = cury;
row1y = y;
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
linex[1] = x + imgsize/2;
liney[1] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['brick'], x, y, imgsize, imgsize);
tempslashes = [ imgsize * 0.20, imgsize * 0.15, imgsize * 0.90, imgsize * 0.75,
imgsize * 0.20, imgsize * 0.75, imgsize * 0.90, imgsize * 0.15,
imgsize * 0.33, imgsize * 0.25, imgsize * 0.80, imgsize * 0.25,
imgsize * 0.33, imgsize * 0.65, imgsize * 0.65, imgsize * 0.65 ];
drawslashes(ctx, x, y, tempslashes);
linex[2] = x + imgsize/2;
liney[2] = y + imgsize/2;
x += gridsize;
x = imgsize;
y += gridsize;
row2y = y;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[0] = x + imgsize/2;
liney[0] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
// line to show path
drawline(ctx, linex[0], liney[0], linex[1], liney[1], PATHLINECOLGOOD, LINEWIDTH);
drawarrow(ctx, linex[1], liney[1], linex[2], liney[2], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
// arrow to middle
x = x + gridsize/2;
y = row2y;
x2 = midpoint2 - 10;
y2 = y;
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
x = midpoint2;
y = cury;
row1y = y;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['pow'], x, y, imgsize, imgsize);
x += gridsize;
x = midpoint2;
y += gridsize;
row2y = y;
//ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
cury = y;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Toads and white cats can also break bricks.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
} }
ctx.textAlign = "center"; ctx.textAlign = "center";
@ -4219,8 +4554,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
console.log("changing last clicked thing thing at " + lastmx/GRIDSIZE + "," + lastmy/GRIDSIZE ); console.log("changing last clicked thing thing at " + lastmx/GRIDSIZE + "," + lastmy/GRIDSIZE );
what = getthingxy(lastmx, lastmy); what = getthingxy(lastmx, lastmy);
if (what != undefined) { if (what != undefined) {
what.name = "forcedllama"; what.name = "xxx changed xx";
what.type = "llama"; what.type = "sunlight";
game.dirty = true; game.dirty = true;
} }
} else if (ch == 'm') { } else if (ch == 'm') {
@ -4499,10 +4834,11 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var i; var i;
imagenames = ['cat', 'catfull', 'catscared', 'llama', 'cheese', 'title', imagenames = ['cat', 'catfull', 'catscared', 'llama', 'cheese', 'title',
'goat','door','lock','catwalkl','catwalkr','starfull','starempty', 'goat', 'lock','catwalkl','catwalkr','starfull','starempty',
'sunlight', 'toad', // special things 'door', 'sunlight', 'toad', 'whitecat', // special things
'bag', 'bagpop', 'fez', 'pow', // effects 'brick', // obstacles
'tissues', 'shears', 'magiccarpet', 'whitecat' ]; 'bag', 'bagpop', 'fez', 'pow', 'brickpop', // effects
'tissues', 'shears', 'magiccarpet' ];
nimages = 0; nimages = 0;
maximages = 0; maximages = 0;
@ -4663,7 +4999,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
for (i = 0; i < curpath.length; i++) { for (i = 0; i < curpath.length; i++) {
// ... except doors // ... except doors
if (curpath[i].type == "door") { if (curpath[i].type == "door") {
game.progress("door", 1); //game.progress("door", 1);
console.log("path has doors!"); console.log("path has doors!");
// add animation // add animation
things.push(new thing(curpath[i].gridx, curpath[i].gridy, "text", "x" + (globmulti+1))); things.push(new thing(curpath[i].gridx, curpath[i].gridy, "text", "x" + (globmulti+1)));
@ -4843,7 +5179,7 @@ function getrandomtype() {
var roll,tot,type = null,i; var roll,tot,type = null,i;
var thinglist,maxroll = 0; var thinglist,maxroll = 0;
var speciallist = null; var speciallist = null;
var dodb = true; var dodb = false;
if (curlevel >= game.levels.length) { if (curlevel >= game.levels.length) {
thinglist = null; thinglist = null;
@ -4862,8 +5198,10 @@ function getrandomtype() {
} }
} }
if (dodb) console.log("speciallist is " + speciallist); //if (dodb) console.log("speciallist is " + speciallist);
// normally we use default chances for objects, but some levels
// have special pre-defined chances.
if (thinglist == undefined || thinglist.length == 0) { if (thinglist == undefined || thinglist.length == 0) {
var f; var f;
thinglist = new Array(); thinglist = new Array();
@ -4908,7 +5246,7 @@ function getrandomtype() {
if (matchesgoal) { if (matchesgoal) {
var count; var count;
console.log("****** " + thingtype + " matches goal."); if (dodb) console.log("****** " + thingtype + " matches goal.");
// check if any exist // check if any exist
count = countalivethingsoftype(lookforthing); count = countalivethingsoftype(lookforthing);
if (count <= 1) { if (count <= 1) {
@ -4937,7 +5275,12 @@ function getrandomtype() {
if (dodb) { if (dodb) {
for (i = 0; i < thinglist.length; i++) { for (i = 0; i < thinglist.length; i++) {
console.log(thinglist[i].type + ": " + ((thinglist[i].pct / maxroll)*100) + "% [roll " + maxroll + "/" + maxroll + "]"); var logline;
logline = thinglist[i].type + ": " + ((thinglist[i].pct / maxroll)*100) + "% [roll " + thinglist[i].pct + "/" + maxroll + "]";
if (thinglist[i].type == "special") {
logline = logline + " - " + speciallist;
}
console.log(logline);
} }
} }
@ -4974,10 +5317,12 @@ function thing(gridx, gridy, type, text, col) {
this.matched = false; // temp for 'match3' things this.matched = false; // temp for 'match3' things
this.gotfez = false; // for powerups this.gotfez = false; // for powerups
this.slashes = []; // drawing slashes on bricks when damaged
// list x,y coords. 0=x1 1=y2 3=x2 4=y2 etc.
if (type == "random") { if (type == "random") {
type = getrandomtype(); type = getrandomtype();
console.log("got random type "+ type); //console.log("got random type "+ type);
} }
// used for various things // used for various things
if (type == "sunlight") { if (type == "sunlight") {
@ -5037,6 +5382,11 @@ function thing(gridx, gridy, type, text, col) {
} }
this.lifetime = 0; this.lifetime = 0;
if (this.type == "brick") {
this.hp = BRICKHP;
} else {
this.hp = -1;
}
this.gridx = gridx; this.gridx = gridx;
if (gridy == "top") { if (gridy == "top") {
@ -5061,6 +5411,9 @@ function thing(gridx, gridy, type, text, col) {
if (this.type == "bagpop") { if (this.type == "bagpop") {
this.yspeed = 0 - rndfloat(8); this.yspeed = 0 - rndfloat(8);
this.xspeed = 0 - rndfloat(16) - 1; this.xspeed = 0 - rndfloat(16) - 1;
} else if (this.type == "brickpop") {
this.yspeed = 0 - rndfloat(8);
this.xspeed = rndfloat(32) - 16;
} else { } else {
this.yspeed = 0; this.yspeed = 0;
this.xspeed = 0; this.xspeed = 0;
@ -5109,8 +5462,8 @@ function thing(gridx, gridy, type, text, col) {
} }
this.canfall = function() { this.canfall = function() {
// doors can't fall after their initial drop // doors and bricks can't fall after their initial drop
if (this.type == "door") { if ((this.type == "door") || (this.type == "brick")) {
if ((this.gridy >= 0) && (this.isnew == false)) { if ((this.gridy >= 0) && (this.isnew == false)) {
return false; return false;
} }
@ -5196,10 +5549,10 @@ function thing(gridx, gridy, type, text, col) {
if (this.type == "food") { if (this.type == "food") {
points = FOODPOINTS; points = FOODPOINTS;
game.progress("food", 1); //game.progress("food", 1);
} else if (this.type == "llama") { } else if (this.type == "llama") {
points = LLAMAPOINTS; points = LLAMAPOINTS;
game.progress("llama", 1); //game.progress("llama", 1);
} else if (this.type == "cat") { } else if (this.type == "cat") {
if (this.issleepy()) { if (this.issleepy()) {
points = SLEEPYCATPOINTS; points = SLEEPYCATPOINTS;
@ -5210,10 +5563,10 @@ function thing(gridx, gridy, type, text, col) {
if (this.gotfez) { if (this.gotfez) {
points *= 2; points *= 2;
} }
game.progress("cat", 1); //game.progress("cat", 1);
} else if (this.type == "goat") { } else if (this.type == "goat") {
points = GOATPOINTS; points = GOATPOINTS;
game.progress("goat", 1); //game.progress("goat", 1);
} }
// multiplier for path position // multiplier for path position
@ -5311,9 +5664,8 @@ function thing(gridx, gridy, type, text, col) {
ctx.textBaseline = "middle"; ctx.textBaseline = "middle";
shadowtext(ctx, this.name, this.size, this.color, BOARDX + this.x,BOARDY + this.y); shadowtext(ctx, this.name, this.size, this.color, BOARDX + this.x,BOARDY + this.y);
} else { } else {
if (this.type == "cat") {
var myimage; var myimage;
if (this.type == "cat") {
if (this.state == "parade") { if (this.state == "parade") {
myimage = image['cat']; myimage = image['cat'];
} else if (this.isscared()) { } else if (this.isscared()) {
@ -5323,25 +5675,12 @@ function thing(gridx, gridy, type, text, col) {
} else { } else {
myimage = image['cat']; myimage = image['cat'];
} }
} else if (this.type == "llama") {
myimage = image['llama'];
} else if (this.type == "food") { } else if (this.type == "food") {
myimage = image['cheese']; myimage = image['cheese'];
} else if (this.type == "goat") {
myimage = image['goat'];
} else if (this.type == "door") {
myimage = image['door'];
} else if (this.type == "sunlight") {
myimage = image['sunlight'];
} else if (this.type == "toad") {
myimage = image['toad'];
} else if (this.type == "whitecat") {
myimage = image['whitecat'];
} else if (this.type == "bagpop") {
myimage = image['bagpop'];
} else if (this.type == "pow") {
myimage = image['pow'];
} else { } else {
myimage = image[this.type];
}
if (myimage == undefined || myimage == null) {
console.log("ERROR - no image for type " + this.type); console.log("ERROR - no image for type " + this.type);
console.log(this); console.log(this);
} }
@ -5378,6 +5717,9 @@ function thing(gridx, gridy, type, text, col) {
ctx.drawImage(myimage, BOARDX + myx, BOARDY + myy, howbig, howbig); ctx.drawImage(myimage, BOARDX + myx, BOARDY + myy, howbig, howbig);
// draw slashes on bricks
drawslashes(ctx, BOARDX + myx, BOARDY + myy, this.slashes);
if (this.gotfez) { if (this.gotfez) {
// fw = 0.78 * howbig; // fw = 0.78 * howbig;
// fh = 0.625 * howbig; // fh = 0.625 * howbig;
@ -5507,6 +5849,8 @@ function thing(gridx, gridy, type, text, col) {
this.kill = function() { this.kill = function() {
// kill ourselves // kill ourselves
game.progress(this.type, 1);
var idx = things.indexOf(this); var idx = things.indexOf(this);
things.splice(idx, 1); things.splice(idx, 1);
} }
@ -5543,7 +5887,7 @@ function thing(gridx, gridy, type, text, col) {
// add "pow" // add "pow"
things.push(new thing(toad.gridx, toad.gridy, "pow")); things.push(new thing(toad.gridx, toad.gridy, "pow"));
game.progress("toad", 1); //game.progress("toad", 1);
console.log("slap"); console.log("slap");
} }
@ -5575,7 +5919,7 @@ function thing(gridx, gridy, type, text, col) {
whitecat.addabove(); whitecat.addabove();
whitecat.startexplode(); whitecat.startexplode();
game.progress("whitecat", 1); //game.progress("whitecat", 1);
console.log("whitecat"); console.log("whitecat");
} }
@ -5616,13 +5960,41 @@ function thing(gridx, gridy, type, text, col) {
return false; return false;
} }
this.breakbrick = function() {
var i,nshards = 7;
for (i = 0; i < nshards; i++) {
things.push(new thing(this.gridx, this.gridy, "brickpop"));
}
this.givepoints();
this.addabove();
this.kill();
}
this.losehp = function() {
this.hp--;
console.log("brick hp is at " + this.hp);
if (this.hp <= 0) {
game.dirty = true; // need to redraw
this.breakbrick();
} else {
// add a slash from a random x/y to a random x/y
addslash(this.slashes, THINGSIZE, THINGSIZE);
}
}
this.startexplode = function(why) { this.startexplode = function(why) {
if (this.type == "brick") {
// break it instead
this.breakbrick();
} else {
this.expcount=1; this.expcount=1;
this.expmax=EXPLODETICKS; this.expmax=EXPLODETICKS;
this.expfadespeed = EXPLODEFADESPEED; this.expfadespeed = EXPLODEFADESPEED;
this.state = "explode"; this.state = "explode";
this.explodereason = why; this.explodereason = why;
} }
}
this.startshrink = function() { this.startshrink = function() {
this.expcount=1; this.expcount=1;
@ -5688,7 +6060,7 @@ function thing(gridx, gridy, type, text, col) {
var belowthing = null,atbottom = false; var belowthing = null,atbottom = false;
if (this.type == "bagpop") { if ((this.type == "bagpop") || (this.type == "brickpop")) {
game.dirty = true; // need to redraw game.dirty = true; // need to redraw
// regular gravity // regular gravity
@ -5819,7 +6191,7 @@ function thing(gridx, gridy, type, text, col) {
this.calcgridxy(); this.calcgridxy();
// cat parade into a bag? // cat parade into a bag or wall?
if (this.state == "parade") { if (this.state == "parade") {
var bag; var bag;
// hit a bag? // hit a bag?
@ -5828,7 +6200,6 @@ function thing(gridx, gridy, type, text, col) {
if (bag.cats < bag.capacity) { if (bag.cats < bag.capacity) {
this.path = []; this.path = [];
this.startshrink(); this.startshrink();
console.log("aaa");
bag.cats++; bag.cats++;
if (bag.cats >= bag.capacity) { if (bag.cats >= bag.capacity) {
@ -5836,6 +6207,16 @@ console.log("aaa");
game.addbagpop(bag.y); game.addbagpop(bag.y);
} }
} }
} else {
var brick;
brick = gridxyhasthingtype(this.gridx, this.gridy, "brick");
if (brick != undefined) {
// parade cat explodes.
this.path = [];
this.startexplode();
brick.losehp();
}
} }
} }
@ -5843,9 +6224,12 @@ console.log("aaa");
if (xdone && ydone) { if (xdone && ydone) {
this.poppath(); this.poppath();
console.log("poppath for " + this.name + " - new len is " + this.path.length);
// path finished? // path finished?
if (this.path == undefined || this.path.length == 0) { if (this.path == undefined || this.path.length == 0) {
if (this.state == "catparade" ){ if (this.state == "parade" ){
console.log("calling kill for parading " + this.type);
this.kill(); this.kill();
} else { } else {
this.state = "stop"; this.state = "stop";
@ -6055,19 +6439,28 @@ function mainloop() {
for (i = 0; i < things.length; i += 1) { for (i = 0; i < things.length; i += 1) {
if (things[i].type == "sunlight" && things[i].gridy >= 0 && !things[i].isnew && if (things[i].type == "sunlight" && things[i].gridy >= 0 && !things[i].isnew &&
things[i].state != "swapping" && things[i].counter == 0) { things[i].state != "swapping" && things[i].counter == 0) {
if ((things[i].gridy >= GRIDH-1)) { var thingbelow,willdie = false;
thingbelow = getgridthing(things[i].gridx, things[i].gridy+1);
if (thingbelow != undefined && thingbelow.type == "brick") {
// bricks stop sun
willdie = true;
} else if ((things[i].gridy >= GRIDH-1)) {
// at bottom - disappear
willdie = true;
}
if (willdie) {
// at bottom - disappear // at bottom - disappear
things[i].addabove(); things[i].addabove();
things[i].startexplode("sun"); things[i].startexplode("sun");
game.progress("sun", 1); //game.progress("sun", 1);
} else { } else {
var thingbelow; // move down (swap with thing below us)
// move down
things[i].pushpath(things[i].x, things[i].y + GRIDSIZE); things[i].pushpath(things[i].x, things[i].y + GRIDSIZE);
things[i].state = "swapping"; things[i].state = "swapping";
things[i].counter = 1; things[i].counter = 1;
thingbelow = getgridthing(things[i].gridx, things[i].gridy+1);
if (thingbelow != undefined && thingbelow.state != "swapping" && if (thingbelow != undefined && thingbelow.state != "swapping" &&
thingbelow.type != "sunlight") { thingbelow.type != "sunlight") {
thingbelow.pushpath(things[i].x, things[i].y); thingbelow.pushpath(things[i].x, things[i].y);
@ -6142,7 +6535,7 @@ function matchthreefrom(what, locdb) {
var nn; var nn;
// matched! // matched!
for (nn = 0; nn < setthings.length; nn++) { for (nn = 0; nn < setthings.length; nn++) {
console.log(" "+setthings[nn].name + " x=",setthings[nn].x + ",y=" + setthings[nn].y); //console.log(" "+setthings[nn].name + " x=",setthings[nn].x + ",y=" + setthings[nn].y);
setthings[nn].matched = true; setthings[nn].matched = true;
} }
gotmatch = true; gotmatch = true;

BIN
images/brick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
images/brickpop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
images/origdoor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

48
todo
View File

@ -11,13 +11,33 @@ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/
------------------- -------------------
*only increase chance of goal items if you haven't already met the goal.
*make increase chance work for "special" things!!! (eg. white cat)
*stop increasing goal progress once we hit the required amount
*seperate goal names and goal associated things
OBSTACLES on later levels *move goal progress increments to thing.kill() function
fixed position. *Make 'allowedthings' default to previous level's one.
*fix lev6 help
*bugfix: whitecats aren't ever appearing randomly?
*new object: bricks
*Don't allow extending path off the top of the grid.
*fix incorrect pluralisation "foods" in goal text
??????????????
no points for cats hitting bricks
give points when things DIE, not when you start a parade.
make points for parades come from the _side_ of the screen.
(where the cats/whatever disappear)
make kill() take an arg ("don't give progress/points")
adjust brick points goal
??????????????
new door fell down on top of new goat!!
(or the other way around ??)
check code for doors falling when off the top of the screen.
check code for adding new objects at top of screen.
Powerup to break bricks
other colour cats other colour cats
@ -29,14 +49,22 @@ more goals:
more prizes: ??? more prizes: ???
mouse - place to clear all cats in grid/column mouse - place to clear all cats in grid/column
whitecat - place to clear 3 x 3 grid around it
overeat (cheese changes to niblet bags, can eat without sleep) overeat (cheese changes to niblet bags, can eat without sleep)
arrow/signpost - cat parades bounce off and take out htings in the path arrow/signpost - cat parades bounce off and take out htings in the path
diff colour cats which only match themselves diff colour cats which only match themselves
actual fireworks when you achieve a goal rather than a flash.
fireworks later.
random levels after 100
generate w/h increases (up to a maximum)
generate goals
generate obstacles
use existing maxturns code
--------- ---------
@ -54,10 +82,6 @@ sofa/curtain
parade over to scratch parade over to scratch
blow up and pow! blow up and pow!
fireworks when you achieve a goal
*flash for now
fireworks later.
show points for each element along path?? show points for each element along path??