From 9176b45a50a8c4f1dcbdfe8a0f0936207b951d12 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Wed, 31 Aug 2016 13:55:35 +1000 Subject: [PATCH] *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 --- cat.html | 571 +++++++++++++++++++++++++++++++++++++------- images/brick.png | Bin 0 -> 4264 bytes images/brickpop.png | Bin 0 -> 1818 bytes images/door.png | Bin 4973 -> 5440 bytes images/origdoor.png | Bin 0 -> 4973 bytes todo | 48 +++- 6 files changed, 518 insertions(+), 101 deletions(-) create mode 100644 images/brick.png create mode 100644 images/brickpop.png create mode 100644 images/origdoor.png diff --git a/cat.html b/cat.html index 62d176c..1fc09fe 100644 --- a/cat.html +++ b/cat.html @@ -74,6 +74,8 @@ var TURNSBARSPEEDUP = 0.02; var TURNSBARSPEEDDOWN = 0.01; 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 var catalpha = 1.0; @@ -90,14 +92,16 @@ var GOALVERB = { 'cat': 'Clear', 'goat': 'Clear', 'door': 'Enter', - 'sun': 'Wait out', + 'sunlight': 'Wait out', 'bag': 'Burst', 'toad': 'Slap', 'whitecat': 'Attack', + 'brick': 'Break', }; var GOALNAME = { 'whitecat': 'white cat', + 'sunlight': 'sun', }; var prizetypes = [ @@ -300,6 +304,21 @@ function loadimage(name, 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) { var i; if (things == undefined) return null; @@ -572,6 +591,10 @@ function canextendpath(overthing) { if (!overthing) return false; + if (!isongrid(overthing.gridx, overthing.gridy)) { + return false; + } + pathtype = getpathtype(); if ( isadjacent(overthing, curpath[curpath.length-1]) && // adjacent to last thing in path? @@ -829,6 +852,50 @@ function isadjacenttotype(what, wanttype, exceptionthing) { 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) { ctx.strokeStyle = col; 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 ) { var mybag; mybag = new Object(); @@ -1294,9 +1373,9 @@ var game = { mylevel.goals = new Array(); mylevel.thinglist = new Array(); mylevel.forcelist = new Array(); - mylevel.allowedthings = new Array(); mylevel.maxturns = lev + 4; // default mylevel.bags = []; + mylevel.bricks = []; if (lev == 1) { mylevel.gridsize = DEF_GRIDSIZE; @@ -1313,6 +1392,14 @@ var game = { 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; playerdata.levscore[lev] = 0; @@ -1388,6 +1475,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); progress : function(type, amt) { var i; + if (game.state != "running") return false; + // past last level! 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; turnsreq += this.levels[lev].goals[i].count * 1; 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": // assume you'll get a parade on most turns. 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.addlevel(1, true); this.addlevelgoals("food", 5); + this.addlevelallowedthings("cat", "food"); this.setstarpoints(1, 50, 60, 80); 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.addlevel(3, true); - this.addlevelallowedthings("cat", "food", "llama"); + this.addlevelallowedthings("llama"); this.addlevelgoals("llama", 4); this.addlevel(4, true); this.addlevelgoals("llama", 5); this.addlevelgoals("food", 5); - this.addlevelallowedthings("cat", "food", "llama"); this.addlevel(5, true); this.addlevelgridwid(5, 6); this.addlevelgoals("bag", 1); this.addlevelgoals("turn", 10); //this.addlevelgoals(5, "points", 600); - this.addlevelallowedthings("cat", "food", "llama"); // introduce goats! this.addlevel(6, true); + this.addlevelallowedthings("goat"); this.addlevelgoals("goat", 3); this.addlevelthings("goat", 10, "cat", 50, "food", 30, "llama", 10); // higher than normal goat chance this.addlevelforcethings("goat", 1); this.addlevel(7, false); - this.addlevelallowedthings("goat", "cat", "food", "llama"); this.addlevelgoals("llama", 6); this.addlevelgoals("goat", 3); this.addlevel(8, false); - this.addlevelallowedthings("goat", "cat", "food", "llama"); this.addlevelgoals("llama", 6); this.addlevelgoals("goat", 4); this.addlevelgoals("food", 5); // introduce doors this.addlevel(9, true); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door"); + this.addlevelallowedthings("door"); this.addlevelgoals("door", 1); this.addlevelgoals("llama", 5); this.addlevelgoals("cat", 13); @@ -1592,20 +1683,19 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); this.addlevel(10, false); this.addlevelgridwid(10, 7); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door"); this.addlevelgoals("turn", 15); // introduce sunlight this.addlevel(11, true); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelallowedthings("sunlight"); this.addlevelgoals("cat", 13); this.addlevelgoals("food", 5); - this.addlevelgoals("sun", 1); + this.addlevelgoals("sunlight", 1); this.addlevelforcethings("sunlight", 1); // introduce whitecat this.addlevel(12, true); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "whitecat"); + this.addlevelallowedthings("whitecat"); this.addlevelgoals("cat", 15); this.addlevelgoals("whitecat", 1); this.addlevelgoals("llama", 6); @@ -1613,24 +1703,45 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // introduce toad this.addlevel(13, true); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad"); + this.addlevelallowedthings("toad"); this.addlevelgoals("toad", 1); this.addlevelgoals("cat", 20); this.addlevelgoals("llama", 5); this.addlevelforcethings("toad", 1); this.addlevel(14, false); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad"); this.addlevelgoals("cat", 25); this.addlevelgoals("llama", 6); this.addlevelgoals("food", 15); - this.addlevel(15, false); + // introduce bricks + this.addlevel(15, true); this.addlevelgridwid(15, 8); - this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight", "toad"); - this.addlevelgoals("cat", 30); - this.addlevelgoals("llama", 7); - this.addlevelgoals("food", 20); + this.addlevelallowedthings("brick"); + this.addlevelgoals("brick", 2); + this.addlevelbricks(3, 3, + 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++) { var extrastars; @@ -1671,16 +1782,25 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); populategrid : function() { var i; while (!anyvalidmoves()) { - var x,y,found; + var x,y,found,i; console.log("populating grid..."); 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 (x = 0; x < GRIDW; x++) { - // start off above the grid - things.push(new thing(x, y, "random")); + if (!getgridthing(x, y)) { + things.push(new thing(x, y, "random")); + } } } @@ -1698,8 +1818,11 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // while we don't have enough... while (countthingsoftype(wanttype) < wantnum) { // add one. - var idx; - idx = rnd(things.length); + var idx = -1; + // don't overwrite bricks + while (idx == -1 || things[idx].type == "brick") { + idx = rnd(things.length); + } things[idx].type = wanttype; donesomething = true; } @@ -1944,7 +2067,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // goal description 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 = ""; } @@ -3108,13 +3233,13 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // next one x = midpoint2 + gridsize; - ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + //ctx.drawImage(image['cat'], x, y, imgsize, imgsize); x += gridsize; - ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + //ctx.drawImage(image['cat'], x, y, imgsize, imgsize); x += gridsize; - ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + //ctx.drawImage(image['cat'], x, y, imgsize, imgsize); x += gridsize; @@ -3136,7 +3261,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; shadowtext(ctx, "Tissue Box", HELPTEXTSIZE, pointscol, 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); ctx.drawImage(image['tissues'], textxspace, cury, THINGSIZE, THINGSIZE); cury += GRIDSIZE; @@ -3144,7 +3269,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; shadowtext(ctx, "Shears", HELPTEXTSIZE, pointscol, 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); ctx.drawImage(image['shears'], textxspace, cury, THINGSIZE, THINGSIZE); cury += GRIDSIZE; @@ -3152,10 +3277,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; shadowtext(ctx, "Magic Carpet", HELPTEXTSIZE, pointscol, THINGSIZE*1.5, y); - shadowtext(ctx, "Grants a magic fez to all cats.", + shadowtext(ctx, "Cats are given a magic fez.", HELPTEXTSIZE, pointscoldark, 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, THINGSIZE*1.5, y + HELPTEXTYSPACE*2); ctx.drawImage(image['magiccarpet'], textxspace, cury, THINGSIZE, THINGSIZE); @@ -3263,6 +3388,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); y += HELPTEXTYSPACE; shadowtext(ctx, "+" + GOATPOINTS + " points per goat", HELPTEXTSIZE,pointscol, x, y); + y += HELPTEXTYSPACE; + y += HELPTEXTYSPACE; + y += HELPTEXTYSPACE; y += HELPTEXTYSPACE; y += HELPTEXTYSPACE; cury = y; @@ -3681,12 +3809,19 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); 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, "Cats must be awake to attack white cats.", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; } else if (curlevel == 13) { - cury = this.drawhelpsubtitle(ctx, "Toad", cury); + cury = this.drawhelpsubtitle(ctx, "Toads", cury); ctx.textAlign = "left"; ctx.textBaseline = "bottom"; @@ -3824,6 +3959,206 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // line to toad falling 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"; @@ -4219,8 +4554,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); console.log("changing last clicked thing thing at " + lastmx/GRIDSIZE + "," + lastmy/GRIDSIZE ); what = getthingxy(lastmx, lastmy); if (what != undefined) { - what.name = "forcedllama"; - what.type = "llama"; + what.name = "xxx changed xx"; + what.type = "sunlight"; game.dirty = true; } } else if (ch == 'm') { @@ -4499,10 +4834,11 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); var i; imagenames = ['cat', 'catfull', 'catscared', 'llama', 'cheese', 'title', - 'goat','door','lock','catwalkl','catwalkr','starfull','starempty', - 'sunlight', 'toad', // special things - 'bag', 'bagpop', 'fez', 'pow', // effects - 'tissues', 'shears', 'magiccarpet', 'whitecat' ]; + 'goat', 'lock','catwalkl','catwalkr','starfull','starempty', + 'door', 'sunlight', 'toad', 'whitecat', // special things + 'brick', // obstacles + 'bag', 'bagpop', 'fez', 'pow', 'brickpop', // effects + 'tissues', 'shears', 'magiccarpet' ]; nimages = 0; maximages = 0; @@ -4663,7 +4999,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); for (i = 0; i < curpath.length; i++) { // ... except doors if (curpath[i].type == "door") { - game.progress("door", 1); + //game.progress("door", 1); console.log("path has doors!"); // add animation 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 thinglist,maxroll = 0; var speciallist = null; - var dodb = true; + var dodb = false; if (curlevel >= game.levels.length) { 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) { var f; thinglist = new Array(); @@ -4908,7 +5246,7 @@ function getrandomtype() { if (matchesgoal) { var count; - console.log("****** " + thingtype + " matches goal."); + if (dodb) console.log("****** " + thingtype + " matches goal."); // check if any exist count = countalivethingsoftype(lookforthing); if (count <= 1) { @@ -4937,7 +5275,12 @@ function getrandomtype() { if (dodb) { 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.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") { type = getrandomtype(); - console.log("got random type "+ type); + //console.log("got random type "+ type); } // used for various things if (type == "sunlight") { @@ -5037,6 +5382,11 @@ function thing(gridx, gridy, type, text, col) { } this.lifetime = 0; + if (this.type == "brick") { + this.hp = BRICKHP; + } else { + this.hp = -1; + } this.gridx = gridx; if (gridy == "top") { @@ -5061,6 +5411,9 @@ function thing(gridx, gridy, type, text, col) { if (this.type == "bagpop") { this.yspeed = 0 - rndfloat(8); this.xspeed = 0 - rndfloat(16) - 1; + } else if (this.type == "brickpop") { + this.yspeed = 0 - rndfloat(8); + this.xspeed = rndfloat(32) - 16; } else { this.yspeed = 0; this.xspeed = 0; @@ -5109,8 +5462,8 @@ function thing(gridx, gridy, type, text, col) { } this.canfall = function() { - // doors can't fall after their initial drop - if (this.type == "door") { + // doors and bricks can't fall after their initial drop + if ((this.type == "door") || (this.type == "brick")) { if ((this.gridy >= 0) && (this.isnew == false)) { return false; } @@ -5196,10 +5549,10 @@ function thing(gridx, gridy, type, text, col) { if (this.type == "food") { points = FOODPOINTS; - game.progress("food", 1); + //game.progress("food", 1); } else if (this.type == "llama") { points = LLAMAPOINTS; - game.progress("llama", 1); + //game.progress("llama", 1); } else if (this.type == "cat") { if (this.issleepy()) { points = SLEEPYCATPOINTS; @@ -5210,10 +5563,10 @@ function thing(gridx, gridy, type, text, col) { if (this.gotfez) { points *= 2; } - game.progress("cat", 1); + //game.progress("cat", 1); } else if (this.type == "goat") { points = GOATPOINTS; - game.progress("goat", 1); + //game.progress("goat", 1); } // multiplier for path position @@ -5311,9 +5664,8 @@ function thing(gridx, gridy, type, text, col) { ctx.textBaseline = "middle"; shadowtext(ctx, this.name, this.size, this.color, BOARDX + this.x,BOARDY + this.y); } else { + var myimage; if (this.type == "cat") { - var myimage; - if (this.state == "parade") { myimage = image['cat']; } else if (this.isscared()) { @@ -5323,25 +5675,12 @@ function thing(gridx, gridy, type, text, col) { } else { myimage = image['cat']; } - } else if (this.type == "llama") { - myimage = image['llama']; } else if (this.type == "food") { 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 { + myimage = image[this.type]; + } + if (myimage == undefined || myimage == null) { console.log("ERROR - no image for type " + this.type); console.log(this); } @@ -5378,6 +5717,9 @@ function thing(gridx, gridy, type, text, col) { ctx.drawImage(myimage, BOARDX + myx, BOARDY + myy, howbig, howbig); + // draw slashes on bricks + drawslashes(ctx, BOARDX + myx, BOARDY + myy, this.slashes); + if (this.gotfez) { // fw = 0.78 * howbig; // fh = 0.625 * howbig; @@ -5507,6 +5849,8 @@ function thing(gridx, gridy, type, text, col) { this.kill = function() { // kill ourselves + game.progress(this.type, 1); + var idx = things.indexOf(this); things.splice(idx, 1); } @@ -5543,7 +5887,7 @@ function thing(gridx, gridy, type, text, col) { // add "pow" things.push(new thing(toad.gridx, toad.gridy, "pow")); - game.progress("toad", 1); + //game.progress("toad", 1); console.log("slap"); } @@ -5575,7 +5919,7 @@ function thing(gridx, gridy, type, text, col) { whitecat.addabove(); whitecat.startexplode(); - game.progress("whitecat", 1); + //game.progress("whitecat", 1); console.log("whitecat"); } @@ -5616,12 +5960,40 @@ function thing(gridx, gridy, type, text, col) { 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.expcount=1; - this.expmax=EXPLODETICKS; - this.expfadespeed = EXPLODEFADESPEED; - this.state = "explode"; - this.explodereason = why; + if (this.type == "brick") { + // break it instead + this.breakbrick(); + } else { + this.expcount=1; + this.expmax=EXPLODETICKS; + this.expfadespeed = EXPLODEFADESPEED; + this.state = "explode"; + this.explodereason = why; + } } this.startshrink = function() { @@ -5688,7 +6060,7 @@ function thing(gridx, gridy, type, text, col) { var belowthing = null,atbottom = false; - if (this.type == "bagpop") { + if ((this.type == "bagpop") || (this.type == "brickpop")) { game.dirty = true; // need to redraw // regular gravity @@ -5819,7 +6191,7 @@ function thing(gridx, gridy, type, text, col) { this.calcgridxy(); - // cat parade into a bag? + // cat parade into a bag or wall? if (this.state == "parade") { var bag; // hit a bag? @@ -5828,7 +6200,6 @@ function thing(gridx, gridy, type, text, col) { if (bag.cats < bag.capacity) { this.path = []; this.startshrink(); -console.log("aaa"); bag.cats++; if (bag.cats >= bag.capacity) { @@ -5836,6 +6207,16 @@ console.log("aaa"); 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) { this.poppath(); + console.log("poppath for " + this.name + " - new len is " + this.path.length); + // path finished? 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(); } else { this.state = "stop"; @@ -6055,19 +6439,28 @@ function mainloop() { for (i = 0; i < things.length; i += 1) { if (things[i].type == "sunlight" && things[i].gridy >= 0 && !things[i].isnew && 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 things[i].addabove(); things[i].startexplode("sun"); - game.progress("sun", 1); + //game.progress("sun", 1); } else { - var thingbelow; - // move down + // move down (swap with thing below us) things[i].pushpath(things[i].x, things[i].y + GRIDSIZE); things[i].state = "swapping"; things[i].counter = 1; - thingbelow = getgridthing(things[i].gridx, things[i].gridy+1); if (thingbelow != undefined && thingbelow.state != "swapping" && thingbelow.type != "sunlight") { thingbelow.pushpath(things[i].x, things[i].y); @@ -6142,7 +6535,7 @@ function matchthreefrom(what, locdb) { var nn; // matched! 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; } gotmatch = true; diff --git a/images/brick.png b/images/brick.png new file mode 100644 index 0000000000000000000000000000000000000000..7fbbfe388df058f3c10263d0b4d0244a929451e3 GIT binary patch literal 4264 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 KMNUMnLSTYm@g)EN literal 0 HcmV?d00001 diff --git a/images/brickpop.png b/images/brickpop.png new file mode 100644 index 0000000000000000000000000000000000000000..da21d60d14fa9cf83b6d00513bf9469fdaa4bfb6 GIT binary patch literal 1818 zcmV+#2j%#QP)eug4oN{J-P!3nJaqS5oUCL}5-4djJ>AuHzWV)6o$4M~rLA9=8vX}u)u5r6 zM<*xN>Q5iN{};Coe|PG=r@sBM0Lp3?_G}${^^^5r>ahnlv29|EmS;tbydok;eCAI! zzV}@FV*}d#>CwQeE{(;3d1%`h6Qgz3))Jy9!UQ2AHWOn`ig3iMf2Hx{bFGgQ=u4Z2 zAC8Q?FkTDU(x{TDlEwjJgH^_xDMPgiaU5Y>fLNzu%&!EFs_M%_Pd>Z!p#gnreVqgM z40G<{jhE_y?7OF#GEz%udqq`gdk;Vw1&pn&Fy5%qs8@)i2onT|br@q#3mj3^msE8@ zJ3$of38&KL%&my;KlK6^F5UQGpuP95r`>8gtgrau!uk$;kyli)k3iL6=sP^Y7f`{J(Bci2~LQR@m66(p*y|iKCr12zMIm zjtvYo&XU7DfBe+%uY2S9!aECWVr6y9zPx1wygpwG*uQl+Wwe&yd#UMEih$;}N(pIm zi`yP%-kamX9V~CjH2U$(es%`AOio&)v4_rXve$D`Al@T8dLZ zv&@C_M5Mrn|ZSj$O!uq zD-0wdnfihxU-Br3>5vtP-nA3e{HRc>ySxk4w3r}5Xccdil`JE>)#BYZ-eQyCMBiSv zYxD3fCnUAV5e24q%x(bfIF^4G7M03%mx^|Btb|s&%83X@1OtrL6I#~bkz==SuG69E z+O>KqmEx0!QF?9cs!&?owYfWi@>(UdR6~a<3p);-J<|tdgohKC+vR<3QSX3d(6Z)g zS&(}2tE|P^lW&EaJw+zJx9y=>jmn{4?0fv!wW+z&q1809#Ln~&*aOpzAw4Cm3stUx zo{l{=Oz9m`P=?c(c7E!PKfj+e9o*zq3CX*dDkMhR6Bh$?`ftH zbQ1S{s)_b(D}Ad>`)gIFNEK(A zX-t-R(5_toZsyXpH}BmzFuJUK#Hcbt*Q*jm!iQHui7(2$0fN?>tD3iorRMEgok zM~yyv0qIOY@ZOUImRjU!Wwc@|zg~57-MzU9qC;Nw5d)7~V?LL-94?IlYhH1FxP4y zm}|AC-J*Oxah7UmsD}a7$aRzpOm2_Y+vZq6l-0YmzL`d39*oElwExk(4`^XUnAeQ+ z*OpKfHV>xPfoBkT=KR&U+FYx>e}0+iD|TgP>?~<$sRseo&{B&mmCzDe>Ex73w@4uQ zV@Vu1YEekrYdbKUIz4l3b)d`3ZM;`*U0duaEm|(?IVT)fIPO)e^R4zni>>y-S<~7T zIZGN?YNfTIB?&EIsa&B;tBqkv)+! zk_L`iVQD>dRGlSoh83@Tc5IMpWbn$@w;z7(#XEj4`|seIVWzqlIOvQ_Mb_97suDWZ z#t~nfXb`&0S3(zW{qb*CK2o4QxVxJ!%XCVFgVxC2$VxC$iI^CwGEj9VpE&V{ul`4G zt{-Nby1QvIpY1WmP5)zY`H?U%kDYt_+RylZY0YM3)&B|p4V&th9^6Van*aa+07*qo IM6N<$f{9UWE&u=k literal 0 HcmV?d00001 diff --git a/images/door.png b/images/door.png index dca420497902bd4480b5f725113cff57391105a7..6b1db10812d2f23261a7f50465d024cd34ef546a 100644 GIT binary patch delta 5384 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 diff --git a/images/origdoor.png b/images/origdoor.png new file mode 100644 index 0000000000000000000000000000000000000000..dca420497902bd4480b5f725113cff57391105a7 GIT binary patch literal 4973 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 r|HnW4gWvlVejeA=?V