From 748c619c50e357e284805b818130e8ba30f84261 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Tue, 30 Aug 2016 14:55:26 +1000 Subject: [PATCH] *help text for turn limit *match 3 llamas to explode them *adjust stars required to unlock levels *from lev5 onwards, shopping bags on right. *powerups *sneeze (wake up all) *shears - clears all llamas *magic carpet - drag to give cats a fez. Worth heaps of points. *help for bags/prizes *tweak required scores --- cat.html | 869 +++++++++++++++++++++++++++++++++++------ images/bag.png | Bin 0 -> 4640 bytes images/bagpop.png | Bin 0 -> 362 bytes images/fez.png | Bin 0 -> 3338 bytes images/magiccarpet.png | Bin 0 -> 6287 bytes images/shears.png | Bin 0 -> 5106 bytes images/tissues.png | Bin 0 -> 6078 bytes todo | 63 +-- 8 files changed, 784 insertions(+), 148 deletions(-) create mode 100644 images/bag.png create mode 100644 images/bagpop.png create mode 100644 images/fez.png create mode 100644 images/magiccarpet.png create mode 100644 images/shears.png create mode 100644 images/tissues.png diff --git a/cat.html b/cat.html index 956b075..018c2ec 100644 --- a/cat.html +++ b/cat.html @@ -73,6 +73,7 @@ var FLASHSPEED = 0.05; var TURNSBARSPEEDUP = 0.02; var TURNSBARSPEEDDOWN = 0.01; +var BAGCAPACITY = 6; // how many cats to pop a bag // for background var catalpha = 1.0; @@ -89,9 +90,14 @@ var GOALVERB = { 'cats': 'Clear', 'goats': 'Clear', 'doors': 'Enter', - 'sun cycles': 'Wait out', + 'suns': 'Wait out', + 'bags': 'Burst', }; +var prizetypes = [ + "tissues", "shears", "magiccarpet", +]; + var wipe = { to: "", dir: "", @@ -168,6 +174,7 @@ var GRIDH = null; var MAXDIRS = 4; var DIRXMOD = [ 0, 1, 0, -1 ]; var DIRYMOD = [ -1, 0, 1, 0 ]; +var DIRNAME = [ "n", "e", "s", "w"]; var NUMWINIMAGES = 12; var WINIMGZOOMSPEED = 0.1; @@ -229,7 +236,7 @@ var SHRINKLOSE= (DEF_THINGSIZE / SHRINKTICKS); var LINEWIDTH=2; var CROSSWIDTH=2; -var BOTTOMBORDERWIDTH=5; +var BOTTOMBORDERWIDTH=3; var LEVSELGRIDW = 5; var LEVSELGRIDH = 6; @@ -238,6 +245,8 @@ var PATHARROWSIZE = 10; var PATHLINECOLGOOD = "#00ee00"; var PATHLINECOLBAD = "#ee0000"; +var FALLARROWSIZE = 4; + var PARADELENGTH = 3; @@ -657,7 +666,7 @@ function thingsmoving() { } for (i = 0; i < things.length; i += 1) { if (things[i].state == "explode") { - return "chomp"; + return things[i].explodereason; } } for (i = 0; i < things.length; i += 1) { @@ -675,7 +684,8 @@ console.log("not a cat"); return false; } - if (isadjacenttotype(what, "llama")) { + //if (isadjacenttotype(what, "llama")) { + if (what.isscared()) { // cats adjacent to llamas are frozen console.log("next to a llama"); return false; @@ -962,6 +972,7 @@ var game = { curh: null, levels: null, state: "", + explodereason: "", cheat: 0, winimgsize: 0, frameNo: 0, @@ -975,6 +986,15 @@ var game = { addfirework : function() { this.screenflash = 1.0; + game.dirty = true; + }, + + addbagpop : function(gridy) { + var i,nshards = 10; + game.progress("bags", 1); + for (i = 0; i < nshards; i++) { + things.push(new thing(GRIDW, gridy, "bagpop")); + } }, fullscreen : function(i) { @@ -1069,7 +1089,6 @@ var game = { }; })(); - if (debug) { window.onerror = function (errorMsg, url, lineNumber) { alert('Error: ' + errorMsg + ' Script: ' + url + ' Line: ' + lineNumber); @@ -1159,12 +1178,15 @@ var game = { }, initlevelvars : function() { + var i; + var nbags; // kill any existing objects clearthings(); overdesc = ""; clearpath(); + // set grid size if (game.levels[curlevel].gridsize == undefined) { GRIDSIZE = DEF_GRIDSIZE; @@ -1179,6 +1201,35 @@ var game = { GRIDH = game.levels[curlevel].gridh; BOARDX = game.levels[curlevel].boardx; } + + + // add shopping bags + game.levels[curlevel].bags = []; + // 0-4 = no bags + // 5 - 14 = 1 bag + // 15 - 24 = 2 bags + // 25 - 34 = 3 bags + nbags = Math.floor((curlevel+5) / 10); + for (i = 0; i < nbags; i++) { + var bagy = rnd(GRIDH); + while (getbagaty(bagy)) { + bagy = rnd(GRIDH); + } + this.addlevelbag(curlevel, bagy); + } + + + }, + + addlevelbag : function (lev, y ) { + var mybag; + mybag = new Object(); + mybag.y = y; + mybag.cats = 0; + mybag.prize = ""; + mybag.capacity = this.levels[lev].gridw; + mybag.prize = prizetypes[rnd(prizetypes.length)]; + this.levels[lev].bags.push(mybag); }, addlevel : function (lev, hashelp) { @@ -1190,6 +1241,7 @@ var game = { mylevel.forcelist = new Array(); mylevel.allowedthings = new Array(); mylevel.maxturns = lev + 4; // default + mylevel.bags = []; if (lev == 1) { mylevel.gridsize = DEF_GRIDSIZE; @@ -1209,6 +1261,7 @@ var game = { this.levels[lev] = mylevel; playerdata.levscore[lev] = 0; + }, addlevelgridwid: function (lev, newwid) { @@ -1226,9 +1279,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); }, // thingtype pct - addlevelthings: function (lev) { - var i,idx; - for (i = 1 ; i < arguments.length; i += 2) { + addlevelthings: function () { + var i,idx,lev; + lev = this.levels.length - 1; + for (i = 0 ; i < arguments.length; i += 2) { idx = this.levels[lev].thinglist.push(new Object()) - 1; this.levels[lev].thinglist[idx].type = arguments[i]; this.levels[lev].thinglist[idx].pct = arguments[i+1]; @@ -1236,9 +1290,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); }, // thingtype howmany - addlevelforcethings: function (lev) { - var i,idx; - for (i = 1 ; i < arguments.length; i += 2) { + addlevelforcethings: function () { + var i,idx,lev; + lev = this.levels.length - 1; + for (i = 0 ; i < arguments.length; i += 2) { idx = this.levels[lev].forcelist.push(new Object()) - 1; this.levels[lev].forcelist[idx].type = arguments[i]; this.levels[lev].forcelist[idx].howmany = arguments[i+1]; @@ -1253,17 +1308,20 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); }, // thing1, thing2, etc - addlevelallowedthings : function (lev) { - var i; - for (i = 1 ; i < arguments.length; i++) { + addlevelallowedthings : function () { + var i,lev; + lev = this.levels.length - 1; + for (i = 0 ; i < arguments.length; i++) { this.levels[lev].allowedthings.push(arguments[i]); } }, // goal1type goal1count goal2type goal2count etc... - addlevelgoals : function (lev) { - var i,idx; - for (i = 1 ; i < arguments.length; i += 2) { + addlevelgoals : function () { + var i,idx,lev; + lev = this.levels.length - 1; + + for (i = 0 ; i < arguments.length; i += 2) { idx = this.levels[lev].goals.push(new Object()) - 1; this.levels[lev].goals[idx].type = arguments[i]; this.levels[lev].goals[idx].count = arguments[i+1]; @@ -1343,8 +1401,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); break; case "llamas": // actually a bit more than this, since you need cats to get rid of llamas. - min += (LLAMAPOINTS) * this.levels[lev].goals[i].count; - turnsreq += this.levels[lev].goals[i].count * 2; // assume 1 llama every 2 turns + min += (LLAMAPOINTS) * this.levels[lev].goals[i].count; + turnsreq += this.levels[lev].goals[i].count * 1.5; break; case "cats": // use smaller amount of catpoints min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count; @@ -1368,7 +1426,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * 3 * 2 * this.levels[lev].goals[i].count; break; turnsreq += this.levels[lev].goals[i].count * 1; - case "sun cycles": + case "suns": min += SLEEPYCATPOINTS*5 * this.levels[lev].goals[i].count; turnsreq += this.levels[lev].gridh; break; @@ -1397,16 +1455,16 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); if (this.levels[lev].gridsize != DEF_GRIDSIZE) { var ratio; ratio = (this.levels[lev].gridw * this.levels[lev].gridh) / - (DEF_GRIDW * DEF_GRIDH) * 2; + (DEF_GRIDW * DEF_GRIDH); min *= ratio; } this.levels[lev].starpoints = new Array(); - this.levels[lev].starpoints[0] = Math.floor(Math.max(min, pointsgoal)); - this.levels[lev].starpoints[1] = Math.floor(Math.max(min * 2, pointsgoal*1.5)); - this.levels[lev].starpoints[2] = Math.floor(Math.max(min * 3, pointsgoal*2)); + this.levels[lev].starpoints[0] = Math.floor(min); + this.levels[lev].starpoints[1] = Math.floor(min * 1.5); + this.levels[lev].starpoints[2] = Math.floor(min * 2); if ((turnsreq > this.levels[lev].maxturns) || forceturnsreq) { this.levels[lev].maxturns = turnsreq; @@ -1422,65 +1480,92 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); console.log("doing level init"); this.levels = []; this.addlevel(1, true); - this.addlevelgoals(1, "food", 5); + this.addlevelgoals("food", 5); this.setstarpoints(1, 50, 60, 80); - this.addlevelthings(1, "cat", 50, "food", 50); + this.addlevelthings( "cat", 50, "food", 50); this.addlevel(2, true); - this.addlevelgoals(2, "cats", 12); - this.addlevelthings(2, "cat", 45, "food", 55); + this.addlevelgoals("cats", 12); + this.addlevelthings("cat", 45, "food", 55); this.addlevel(3, true); - this.addlevelallowedthings(3, "cat", "food", "llama"); - this.addlevelgoals(3, "llamas", 3); + this.addlevelallowedthings("cat", "food", "llama"); + this.addlevelgoals("llamas", 4); this.addlevel(4, true); - this.addlevelgoals(4, "llamas", 5); - this.addlevelgoals(4, "food", 5); - this.addlevelallowedthings(4, "cat", "food", "llama"); + this.addlevelgoals("llamas", 5); + this.addlevelgoals("food", 5); + this.addlevelallowedthings("cat", "food", "llama"); - this.addlevel(5, false); + this.addlevel(5, true); this.addlevelgridwid(5, 6); - this.addlevelgoals(5, "turns", 10); + this.addlevelgoals("bags", 1); + this.addlevelgoals("turns", 10); //this.addlevelgoals(5, "points", 600); - this.addlevelallowedthings(5, "cat", "food", "llama"); + this.addlevelallowedthings("cat", "food", "llama"); // introduce goats! this.addlevel(6, true); - this.addlevelgoals(6, "goats", 3); - this.addlevelthings(6, "goat", 10, "cat", 50, "food", 30, "llama", 10); // higher than normal goat chance - this.addlevelforcethings(6, "goat", 1); + this.addlevelgoals("goats", 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(7, "goat", "cat", "food", "llama"); - this.addlevelgoals(7, "turns", 15); - this.addlevelgoals(7, "llamas", 2); - this.addlevelgoals(7, "goats", 2); + this.addlevelallowedthings("goat", "cat", "food", "llama"); + this.addlevelgoals("llamas", 6); + this.addlevelgoals("goats", 3); this.addlevel(8, false); - this.addlevelallowedthings(8,"goat", "cat", "food", "llama"); - this.addlevelgoals(8, "turns", 20); - this.addlevelgoals(8, "llamas", 3); + this.addlevelallowedthings("goat", "cat", "food", "llama"); + this.addlevelgoals("llamas", 6); + this.addlevelgoals("goats", 4); + this.addlevelgoals("food", 5); // introduce doors this.addlevel(9, true); - this.addlevelallowedthings(9,"goat", "cat", "food", "llama", "door"); - this.addlevelgoals(9, "doors", 1); - this.addlevelforcethings(9, "door", 1); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door"); + this.addlevelgoals("doors", 1); + this.addlevelgoals("llamas", 5); + this.addlevelgoals("cats", 13); + this.addlevelforcethings("door", 1); this.addlevel(10, false); this.addlevelgridwid(10, 7); - this.addlevelallowedthings(10,"goat", "cat", "food", "llama", "door"); - //this.addlevelgoals(10, "points", 2000); - this.addlevelgoals(10, "turns", 15); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door"); + this.addlevelgoals("turns", 15); // introduce sunlight this.addlevel(11, true); - this.addlevelallowedthings(11,"goat", "cat", "food", "llama", "door", "sunlight"); - this.addlevelgoals(11, "turns", 10); - this.addlevelgoals(11, "sun cycles", 1); - this.addlevelforcethings(11, "sunlight", 1); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelgoals("cats", 13); + this.addlevelgoals("food", 5); + this.addlevelgoals("suns", 1); + this.addlevelforcethings("sunlight", 1); + this.addlevel(12, false); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelgoals("cats", 20); + this.addlevelgoals("food", 10); + this.addlevelgoals("llamas", 6); + + this.addlevel(13, false); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelgoals("cats", 20); + this.addlevelgoals("llamas", 6); + this.addlevelgoals("food", 10); + + this.addlevel(14, false); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelgoals("cats", 25); + this.addlevelgoals("llamas", 6); + this.addlevelgoals("food", 15); + + this.addlevel(15, false); + this.addlevelgridwid(15, 8); + this.addlevelallowedthings("goat", "cat", "food", "llama", "door", "sunlight"); + this.addlevelgoals("cats", 30); + this.addlevelgoals("llamas", 7); + this.addlevelgoals("food", 20); for (i = 1; i < this.levels.length; i++) { var extrastars; @@ -1490,8 +1575,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); } // calc stars to unlock - extrastars = Math.floor(i / 5); - this.levels[i].starsrequired = (i-1) + extrastars; + //extrastars = Math.floor(i / 5); + //this.levels[i].starsrequired = (i-1) + extrastars; + this.levels[i].starsrequired = Math.floor(1.2 * (i-1)); } @@ -1520,7 +1606,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); populategrid : function() { var i; while (!anyvalidmoves()) { - var x,y; + var x,y,found; console.log("populating grid..."); clearthings(); @@ -1533,20 +1619,34 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); } } - // force items - if (game.levels[curlevel].forcelist != undefined) { - for (i = 0; i < game.levels[curlevel].forcelist.length; i++) { - var wanttype,wantnum; - wanttype = game.levels[curlevel].forcelist[i].type; - wantnum = game.levels[curlevel].forcelist[i].howmany; + // fix up problems + donesomething=true; + while (donesomething) { + donesomething=false; + // force items + if (game.levels[curlevel].forcelist != undefined) { + for (i = 0; i < game.levels[curlevel].forcelist.length; i++) { + var wanttype,wantnum; + wanttype = game.levels[curlevel].forcelist[i].type; + wantnum = game.levels[curlevel].forcelist[i].howmany; - // while we don't have enough... - while (countthingsoftype(wanttype) < wantnum) { - // add one. - var idx; - idx = rnd(things.length); - things[idx].type = wanttype; - } + // while we don't have enough... + while (countthingsoftype(wanttype) < wantnum) { + // add one. + var idx; + idx = rnd(things.length); + things[idx].type = wanttype; + donesomething = true; + } + } + } + + // ensure no matches to start with + for (i = 0; i < things.length; i++) { + if (matchthreefrom(things[i])) { + things[i].type = getrandomtype(); // change its type + donesomething=true; + } } } } @@ -1554,6 +1654,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // now move everything up so they'll fall down into the initial // positions. for (i = 0; i < things.length; i++) { + things[i].matched = false; // un-match it. things[i].gridy -= GRIDH; things[i].updatexy(); } @@ -1647,11 +1748,23 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); switch (thingsmoving()) { case "parade": col = "#00ff00"; - texttodraw = "CAT PARADE!" + texttodraw = "CAT PARADE!"; break; case "chomp": col = "#00cc00"; - texttodraw = "Chomp!" + texttodraw = "Chomp!"; + break; + case "matchthree": + col = "#00cc00"; + texttodraw = "OVERLOAD!"; + break; + case "sun": + // do nothing + break; + case "shears": + col = "#00cc00"; + texttodraw = "Shears!"; + // do nothing break; default: // show current object in path @@ -1722,10 +1835,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); ctx.fillRect(bx, by, bw, bh); //outline - ctx.strokeStyle = "cyan"; + ctx.strokeStyle = "white"; ctx.lineWidth = BOTTOMBORDERWIDTH; ctx.beginPath(); - ctx.rect(bx+(borderwidth/2), by+(borderwidth/2), bw-(borderwidth/2), bh-(borderwidth/2)); + ctx.rect(bx+(borderwidth/2)-1, by+(borderwidth/2)-1, bw-(borderwidth/2), bh-(borderwidth/2)); ctx.stroke(); // draw goals @@ -2064,6 +2177,11 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); var helpcol = "#00cc00"; var pointscoldark = "#888800"; var pointscol = "#dddd00"; + var llamatitle = llamatext[0].toUpperCase() + llamatext.substring(1); + var aoran; + + if (llamatext[0] == 'a') aoran = "an"; + else aoran = "a"; //ctx = this.context; @@ -2414,19 +2532,19 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); ctx.textBaseline = "bottom"; shadowtext(ctx, "Each level has one of more goals to fulfil.", HELPTEXTSIZE,helpcol, textxspace, cury); cury += HELPTEXTYSPACE; - shadowtext(ctx, "Complete all goals to progress to the next level!", HELPTEXTSIZE,helpcol, textxspace, cury); + shadowtext(ctx, "Complete all goals to complete the level!", HELPTEXTSIZE,helpcol, textxspace, cury); cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE; // GAME OVER HELP - cury = this.drawhelpsubtitle(ctx, "End of Game", cury); + cury = this.drawhelpsubtitle(ctx, "Failure", cury); ctx.textAlign = "left"; ctx.textBaseline = "bottom"; - shadowtext(ctx, "The game ends when there are no valid moves left,", HELPTEXTSIZE,helpcol, textxspace, cury); + shadowtext(ctx, "If you run out of valid moves, or the turn counter", HELPTEXTSIZE,helpcol, textxspace, cury); cury += HELPTEXTYSPACE; - shadowtext(ctx, "or if the turn counter runs out.", HELPTEXTSIZE,helpcol, textxspace, cury); + shadowtext(ctx, "reaches zero, you must try the level again.", HELPTEXTSIZE,helpcol, textxspace, cury); cury += HELPTEXTYSPACE; } else if (curlevel == 2) { @@ -2634,10 +2752,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); - - } else if (curlevel == 3) { - var llamatitle = llamatext[0].toUpperCase() + llamatext.substring(1); + cury = this.drawhelpsubtitle(ctx, llamatitle + "s", cury); ctx.textAlign = "left"; @@ -2739,6 +2855,95 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE; + + cury = this.drawhelpsubtitle(ctx, llamatitle + " Overload", cury); + + ctx.textAlign = "left"; + ctx.textBaseline = "bottom"; + shadowtext(ctx, "Three or more " + llamatext + "s in a row defies reality.", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; + shadowtext(ctx, "They will vanish in " + aoran + " " + llamatitle + " Overload.", HELPTEXTSIZE,helpcol, textxspace, cury); + + cury += HELPTEXTYSPACE; + cury += HELPTEXTYSPACE; + + // top line of llama overload + x = imgsize; + y = cury; + row1y = y; + ctx.drawImage(image['catscared'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['cheese'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['catscared'], x, y, imgsize, imgsize); + x += gridsize; + + x = imgsize; + y += gridsize; + row2y = y; + + ctx.drawImage(image['llama'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['llama'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['llama'], x, y, imgsize, imgsize); + + // arrow to middle + x = x + gridsize; + y = row1y + (imgsize); + + x2 = midpoint2 - 10; + y2 = y; + + drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE); + + + // top line of post-overload + x = midpoint2; + y = row1y; + + //ctx.drawImage(image['catscared'], x, y, imgsize, imgsize); + linex[0] = x + imgsize/2; + liney[0] = y + imgsize/2; + x += gridsize; + + //ctx.drawImage(image['cheese'], 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[4] = x + imgsize/2; + liney[4] = y + imgsize/2; + x += gridsize; + + x = midpoint2; + y = row2y; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + linex[1] = x + imgsize/2; + liney[1] = y + imgsize/2; + x += gridsize; + + ctx.drawImage(image['cheese'], x, y, imgsize, imgsize); + linex[3] = x + imgsize/2; + liney[3] = y + imgsize/2; + x += gridsize; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + linex[5] = x + imgsize/2; + liney[5] = y + imgsize/2; + + + // falling down liens + drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], "#660000", LINEWIDTH, FALLARROWSIZE); + drawarrow(ctx, linex[2], liney[2], linex[3], liney[3], "#660000", LINEWIDTH, FALLARROWSIZE); + drawarrow(ctx, linex[4], liney[4], linex[5], liney[5], "#660000", LINEWIDTH, FALLARROWSIZE); + } else if (curlevel == 4) { cury = this.drawhelpsubtitle(ctx, "Later Levels", cury); @@ -2762,6 +2967,105 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); shadowtext(ctx, "Sunlight (level 11)", HELPTEXTSIZE,pointscol, THINGSIZE*1.5, cury + THINGSIZE/2 - HELPTEXTYSPACE/2); ctx.drawImage(image['sunlight'], textxspace, cury, THINGSIZE, THINGSIZE); cury += GRIDSIZE; + } else if (curlevel == 5) { + cury = this.drawhelpsubtitle(ctx, "Shopping Bags", cury); + ctx.textAlign = "left"; + ctx.textBaseline = "bottom"; + shadowtext(ctx, "Cat find shopping bags irresistable.", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; + shadowtext(ctx, "Lead a cat parade into a shopping bag to fill it up.", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; + + // top line of bag demo + 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['cat'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + linex[1] = x + imgsize/2; + liney[1] = y + imgsize/2; + x += gridsize; + + + ctx.drawImage(image['bag'], x, y + imgsize/2 - imgsize*0.1, imgsize, imgsize*0.2); + x += gridsize; + + + + drawarrow(ctx, linex[0], liney[0], + linex[1], liney[1], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE); + + + // arrow to next one + + drawarrow(ctx, midpoint2 - gridsize, y+gridsize/2, + midpoint2 + gridsize*0.75, y+gridsize/2, "red", HELPLINEWIDTH, HELPARROWSIZE); + + // next one + x = midpoint2 + gridsize; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + x += gridsize; + + ctx.drawImage(image['cat'], x, y, imgsize, imgsize); + x += gridsize; + + + ctx.drawImage(image['bag'], x, y + imgsize/2 - imgsize*0.5, imgsize, imgsize); + x += gridsize; + + y += gridsize; + y += gridsize; + + cury = y; + shadowtext(ctx, "Full shopping bags explode to reveal a random prize.", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; + shadowtext(ctx, "Tap the prize for a special effect!", HELPTEXTSIZE,helpcol, textxspace, cury); + cury += HELPTEXTYSPACE; + cury += HELPTEXTYSPACE; + + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; + shadowtext(ctx, "Tissue Box", HELPTEXTSIZE, pointscol, + THINGSIZE*1.5, y); + shadowtext(ctx, "Wakes all sleeping cats.", HELPTEXTSIZE, pointscoldark, + THINGSIZE*1.5, y + HELPTEXTYSPACE); + ctx.drawImage(image['tissues'], textxspace, cury, THINGSIZE, THINGSIZE); + cury += GRIDSIZE; + + y = cury + THINGSIZE/4 - HELPTEXTYSPACE/2; + shadowtext(ctx, "Shears", HELPTEXTSIZE, pointscol, + THINGSIZE*1.5, y); + shadowtext(ctx, "Immediately clears all " + llamatext + "s.", HELPTEXTSIZE, pointscoldark, + THINGSIZE*1.5, y + HELPTEXTYSPACE); + ctx.drawImage(image['shears'], textxspace, cury, THINGSIZE, THINGSIZE); + cury += GRIDSIZE; + + 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.", + HELPTEXTSIZE, pointscoldark, + THINGSIZE*1.5, y + HELPTEXTYSPACE); + 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); + cury += GRIDSIZE; + + } else if (curlevel == 6) { cury = this.drawhelpsubtitle(ctx, "Goats", cury); @@ -3152,10 +3456,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE; - - shadowtext(ctx, "After reaching the the bottom of the play area, suns will set.", HELPTEXTSIZE,helpcol, textxspace, cury); + shadowtext(ctx, "Suns set after reaching the the bottom of the play area.", HELPTEXTSIZE,helpcol, textxspace, cury); cury += HELPTEXTYSPACE; - } ctx.textAlign = "center"; @@ -3381,7 +3683,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); }, drawsides : function() { - var x,y,w,h,y2,h2; + var x,y,w,h,y2,h2,i; var turnscol = "#00dddd"; /// left - turns left @@ -3393,24 +3695,26 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); h2 = game.turnsbarpct * (h-2); //y2 = y + (h - game.turnsbarh); - y2 = y + (h - h2); + y2 = y + (h - h2) -1; // black background - ctx.fillStyle = "black"; ctx.beginPath(); - ctx.rect(x+1,y+1,w-1,h-1); + ctx.fillStyle = "black"; + ctx.fillRect(x+1,y+1,w-1,h-1); ctx.stroke(); // turns left bar if (game.turnsleft > 0) { var gradient; + // blue gradient bar showing turns left ctx.beginPath(); - gradient = ctx.createLinearGradient(0, 0, 0, h2); gradient.addColorStop(0, "#0000ff"); - gradient.addColorStop(1, "#000055"); + gradient.addColorStop(1, "#000066"); + ctx.fillStyle = gradient; + ctx.fillRect(x+1,y2,w-1,h2); ctx.stroke(); @@ -3418,14 +3722,35 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); ctx.textAlign = "center"; ctx.textBaseline = "top"; shadowtext(ctx, Math.floor(game.turnsleft), TURNSLEFTTEXTSIZE, turnscol, x + (w/2), y2 + 2); + shadowtext(ctx, "turn" + (game.turnsleft == 1) ? "" : "s", TURNSLEFTTEXTSIZE, turnscol, x + (w/2), y2 + 2 + + TURNSLEFTTEXTSIZE); } // border - ctx.strokeStyle = "white"; - ctx.lineWidth = 2; ctx.beginPath(); - ctx.rect(x,y,w,h); + ctx.strokeStyle = "#dddddd"; + ctx.lineWidth = 2; + ctx.rect(x+1,y,w,h); ctx.stroke(); + + // right: bags + if (game.levels[curlevel].bags != undefined) { + for (i = 0; i < game.levels[curlevel].bags.length; i++) { + var bagh,thisbag; + thisbag = game.levels[curlevel].bags[i]; + x = BOARDX + (GRIDW * GRIDSIZE); + y = BOARDY + (thisbag.y * GRIDSIZE); + if (thisbag.cats < thisbag.capacity) { + bagh = THINGSIZE*0.1; // base height + bagh += (thisbag.cats / thisbag.capacity) * (THINGSIZE*0.9); // increase based on fullness + ctx.drawImage(image['bag'], x, y + GRIDSIZE/2 - bagh/2, THINGSIZE, bagh); + } else if (thisbag.prize != "") { // not collected yet + var size = SCREENW - (GRIDW*GRIDSIZE + BOARDX) ; + // bag is open! + ctx.drawImage(image[thisbag.prize], x, y + GRIDSIZE/2 - size/2, size, size); + } + } + } }, drawgrid : function() { @@ -3504,8 +3829,34 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); game.cheat = 1; } else if (ch == 'c') { playerdata.clearall(); + } else if (ch == 'f') { + var i; + for (i = 0; i < things.length; i++) { + if (things[i].type == "cat") things[i].gotfez = true; + } + game.dirty = true; } else if (ch == 't') { game.addfirework(); + } else if (ch == 'l') { + var what; + 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"; + game.dirty = true; + } + } else if (ch == 'm') { + var what; + console.log("checking for matches from " + lastmx/GRIDSIZE + "," + lastmy/GRIDSIZE ); + what = getthingxy(lastmx, lastmy); + if (what != undefined) { + if (matchthreefrom(what, true)) { + console.log("--found match"); + } else { + console.log("--no match"); + } + } } else if (ch == 'n') { var i; score += 10; @@ -3565,6 +3916,15 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); // just show description overdesc = onthing.getdesc(); } + } else { + var bag; + // did you click on a bag? + bag = getbagaty(Math.floor(adjusty / GRIDSIZE)); + if ((bag != undefined) && (adjustx > GRIDSIZE*GRIDW)) { + if (bag.cats >= bag.capacity) { + collectprize(bag); + } + } } } else if (game.state == "gameover") { if ((realx >= tapx) && (realx <= tapx + tapw) && @@ -3762,7 +4122,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); var i; imagenames = ['cat', 'catfull', 'catscared', 'llama', 'cheese', 'title', - 'goat','door','sunlight','lock','catwalkl','catwalkr','starfull','starempty' ]; + 'goat','door','sunlight','lock','catwalkl','catwalkr','starfull','starempty', + 'bag', 'bagpop', 'fez', + 'tissues', 'shears', 'magiccarpet' ]; nimages = 0; maximages = 0; @@ -3785,10 +4147,10 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); realy = coords[3]; // remember coords for touch screens - if (event.type == "touchmove") { - lastmx = adjustx; - lastmy = adjusty; - } + //if (event.type == "touchmove") { + lastmx = adjustx; + lastmy = adjusty; + //} event.preventDefault(); @@ -3895,7 +4257,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio); curpath[i].givepoints(); curpath[i].addabove(); //curpath[i].kill(); - curpath[i].startexplode(); + curpath[i].startexplode("chomp"); } } @@ -3964,6 +4326,12 @@ function rnd(num) { return roll; } +function rndfloat(num) { + var roll; + roll = Math.random() * num; + return roll; +} + function onein(num) { var roll; roll = Math.floor(Math.random() * num); @@ -4042,10 +4410,59 @@ function shadowtext(ctx, text, size, col, x, y) { ctx.fillText(text, x, y); } +function collectprize(bag) { + var i; + + if (bag.prize == "") return; + + game.addfirework(); + + switch (bag.prize) { + case "tissues": // all sleepy cats wake up + for (i = 0; i < things.length; i++) { + if (things[i].type == "cat") { + things[i].eaten = false; + } + } + break; + case "shears": // clear all llamas + for (i = 0; i < things.length; i++) { + if (things[i].type == "llama") { + things[i].givepoints(); + things[i].addabove(); + things[i].startexplode("shears"); + } + } + break; + case "magiccarpet": + for (i = 0; i < things.length; i++) { + if (things[i].type == "cat") things[i].gotfez = true; + } + break; + } + game.dirty = true; + + // mark bag as collected + bag.prize = ""; +} + +function getbagaty(gridy) { + var i; + if (game.levels[curlevel].bags != undefined) { + for (i = 0; i < game.levels[curlevel].bags.length; i++) { + if (game.levels[curlevel].bags[i].y == gridy) { + return game.levels[curlevel].bags[i]; + } + } + } + return null; +} + function getrandomtype() { var roll,tot,type = null,i; var thinglist,maxroll = 0; var speciallist = null; + var dodb = false; if (curlevel >= game.levels.length) { thinglist = null; @@ -4064,7 +4481,7 @@ function getrandomtype() { } } - console.log("speciallist is " + speciallist); + if (dodb) console.log("speciallist is " + speciallist); if (thinglist == undefined || thinglist.length == 0) { var f; @@ -4074,8 +4491,8 @@ function getrandomtype() { // must be sorted from low to high! if (!game.isbanned(curlevel, 'door')) thinglist.push({ type: 'door', pct: 10 } ); if (speciallist != undefined) { - console.log("specials are possible"); - thinglist.push({ type: 'special', pct: 10 } ); + if (dodb) console.log("specials are possible"); + thinglist.push({ type: 'special', pct: 5 } ); } if (!game.isbanned(curlevel, 'goat')) thinglist.push({ type: 'goat', pct: 10 } ); if (!game.isbanned(curlevel, 'llama')) thinglist.push({ type: 'llama', pct: 10 } ); @@ -4089,8 +4506,10 @@ function getrandomtype() { } - for (i = 0; i < thinglist.length; i++) { - console.log(thinglist[i].type + ": " + ((thinglist[i].pct / maxroll)*100) + "% [roll " + maxroll + "/" + maxroll + "]"); + if (dodb) { + for (i = 0; i < thinglist.length; i++) { + console.log(thinglist[i].type + ": " + ((thinglist[i].pct / maxroll)*100) + "% [roll " + maxroll + "/" + maxroll + "]"); + } } roll = rnd(maxroll); @@ -4098,7 +4517,7 @@ function getrandomtype() { for (i = 0; i < thinglist.length; i++) { tot += thinglist[i].pct; if (roll <= tot) { - console.log("rolled " + roll + "/" + maxroll + " --> " + thinglist[i].type + " [<= " + tot + "]"); + if (dodb) console.log("rolled " + roll + "/" + maxroll + " --> " + thinglist[i].type + " [<= " + tot + "]"); type = thinglist[i].type; break; @@ -4123,6 +4542,9 @@ function coord(x,y) { function thing(gridx, gridy, type, text, col) { this.opacity = 1.0; this.isnew = true; + this.matched = false; // temp for 'match3' things + + this.gotfez = false; // for powerups if (type == "random") { type = getrandomtype(); @@ -4202,7 +4624,14 @@ function thing(gridx, gridy, type, text, col) { //console.log("adding thing at gridy = " + gridy); } this.gridy = gridy; - this.yspeed = 0; + + if (this.type == "bagpop") { + this.yspeed = 0 - rndfloat(8); + this.xspeed = 0 - rndfloat(16) - 1; + } else { + this.yspeed = 0; + this.xspeed = 0; + } if (this.type == "text") { this.state = "text"; } else { @@ -4267,7 +4696,8 @@ function thing(gridx, gridy, type, text, col) { if (this.type != "cat") { return false; } - if (isadjacenttotype(this, "llama")) { + //if (isadjacenttotype(this, "llama")) { + if (this.isscared()) { return false; } @@ -4332,6 +4762,10 @@ function thing(gridx, gridy, type, text, col) { } else { points = CATPOINTS; } + // fez multiplier + if (this.gotfez) { + points *= 2; + } game.progress("cats", 1); } else if (this.type == "goat") { points = GOATPOINTS; @@ -4344,6 +4778,7 @@ function thing(gridx, gridy, type, text, col) { // global multiplier (doors etc) thismulti += globmulti; + points *= thismulti; @@ -4367,10 +4802,23 @@ function thing(gridx, gridy, type, text, col) { } + this.isscared = function() { + if (this.type != "cat") return false; + if (this.isanimating()) return false; + + if (isadjacenttotype(this, "llama")) { + if (!this.gotfez) { + return true; + } + } + + return false; + } + this.getdesc = function() { var desc = ""; if (this.type == "cat") { - if (isadjacenttotype(this, "llama")) { + if (this.isscared()) { if (this.issleepy() == true) { desc = "scared sleepy cat"; } else { @@ -4399,6 +4847,7 @@ function thing(gridx, gridy, type, text, col) { var yoff; var inpath = false; var howbig,myx,myy; + var fhowbig,fw,fh,fx,fy; //ctx = game.context; @@ -4423,7 +4872,7 @@ function thing(gridx, gridy, type, text, col) { if (this.state == "parade") { myimage = image['cat']; - } else if (isadjacenttotype(this, "llama")) { + } else if (this.isscared()) { myimage = image['catscared']; } else if (this.issleepy() == true) { myimage = image['catfull']; @@ -4440,18 +4889,32 @@ function thing(gridx, gridy, type, text, col) { myimage = image['door']; } else if (this.type == "sunlight") { myimage = image['sunlight']; + } else if (this.type == "bagpop") { + myimage = image['bagpop']; } else { console.log("ERROR - no image for type " + this.type); console.log(this); } howbig = this.size; + fw = (image['fez'].width / myimage.width) * this.size; + fh = (image['fez'].height / myimage.height) * this.size; myx = this.x; myy = this.y; + + fx = (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (fw/2); + fy = this.y; if (inpath) { var growpct = 50; + howbig = howbig * ((100+growpct) / 100); myx -= (growpct/2/100) * this.size; myy -= (growpct/2/100) * this.size; + + fw = fw * ((100+growpct) / 100); + fh = fh * ((100+growpct) / 100); + + fx = (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (fw/2); + fy -= (growpct/2/100) * this.size; } /* hilight non-snapped things @@ -4464,6 +4927,18 @@ function thing(gridx, gridy, type, text, col) { */ ctx.drawImage(myimage, BOARDX + myx, BOARDY + myy, howbig, howbig); + + if (this.gotfez) { + // fw = 0.78 * howbig; + // fh = 0.625 * howbig; + + + // centre + //fx = BOARDX + (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (fw/2); + //fy = BOARDY + (this.gridy * GRIDSIZE) + (fh/6); + + ctx.drawImage(image['fez'], BOARDX + fx, BOARDY + fy, fw, fh); + } } /* @@ -4617,7 +5092,7 @@ function thing(gridx, gridy, type, text, col) { // make food explode //food.addabove(); //food.kill(); - food.startexplode(); + food.startexplode("chomp"); // mark that we've eaten something this.eaten = true; @@ -4633,16 +5108,19 @@ function thing(gridx, gridy, type, text, col) { return false; } - this.startexplode = function() { + this.startexplode = function(why) { this.expcount=1; this.expmax=EXPLODETICKS; this.state = "explode"; + this.explodereason = why; } this.startshrink = function() { this.expcount=1; this.expmax=SHRINKTICKS; this.state = "shrink"; + this.xspeed = 0; + this.yspeed = 0; } this.startparade = function() { @@ -4700,7 +5178,40 @@ function thing(gridx, gridy, type, text, col) { var dofall = false; var belowthing = null,atbottom = false; - if (this.state == "explode") { + + if (this.type == "bagpop") { + game.dirty = true; // need to redraw + + // regular gravity + if ((this.gridy >= GRIDH-1)) { + atbottom = true; + } + if (!atbottom) { + game.dirty = true; // need to redraw + // accelerate + this.yspeed += GRAVITY; + + // move + this.y += this.yspeed; + this.x += this.xspeed; + + // don't go below bottom of screen + if (this.y > GRIDSIZE * GRIDH) { + atbottom = true; + } + + // calc new gridx / gridy + this.calcgridxy(); + + if ((this.gridy >= GRIDH-1)) { + atbottom = true; + } + } + + if (atbottom) { + this.kill(); + } + } else if (this.state == "explode") { game.dirty = true; // need to redraw this.expcount++; if (this.expcount >= this.expmax) { @@ -4729,6 +5240,7 @@ function thing(gridx, gridy, type, text, col) { } } } else if (this.state == "shrink") { + var xcutoff; game.dirty = true; // need to redraw this.expcount++; if (this.expcount >= this.expmax) { @@ -4742,12 +5254,19 @@ function thing(gridx, gridy, type, text, col) { // adjust x/y this.x = (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2); this.y = (this.gridy * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2); + + // going in to a bag ? + xcutoff = SCREENW - this.size*2; + if (this.x > xcutoff) { + this.x = xcutoff; + } } } else if ((this.state == "parade") || (this.state == "swapping")) { // move towards next cell in path var nextx = this.path[0].x; var nexty = this.path[0].y; var xdone = 0, ydone = 0; + var goingright = false; game.dirty = true; // need to redraw @@ -4757,6 +5276,7 @@ function thing(gridx, gridy, type, text, col) { this.startshrink(); } else { if (this.x < nextx) { + goingright = true; this.x += this.pathspeed; if (this.x >= nextx) { this.x = nextx; @@ -4790,9 +5310,30 @@ function thing(gridx, gridy, type, text, col) { this.calcgridxy(); + // cat parade into a bag? + if (this.state == "parade") { + var bag; + // hit a bag? + bag = getbagaty(this.gridy); + if (goingright && (this.gridx >= GRIDW) && (bag != undefined)) { + if (bag.cats < bag.capacity) { + this.path = []; + this.startshrink(); +console.log("aaa"); + bag.cats++; + + if (bag.cats >= bag.capacity) { + game.dirty = true; // need to redraw + game.addbagpop(bag.y); + } + } + } + } + // at destination? if (xdone && ydone) { this.poppath(); + // path finished? if (this.path == undefined || this.path.length == 0) { if (this.state == "catparade" ){ @@ -4891,10 +5432,9 @@ function mainloop() { // move "turns left" bar towards its correct location. game.moveturnsleftbar(); - gridalpha = wipe.getval(1.0, "up", "down", 1.0); ctx.globalAlpha = gridalpha; - if (game.dirty || wipe.isactive()) { + if (game.dirty || wipe.isactive() || (game.screenflash > 0)) { // clear game.clear(); // draw grid @@ -4949,6 +5489,9 @@ function mainloop() { pathdoor.addabove(); pathdoor.startshrink(); pathdoor = null; + } else if (matchthree()) { + // matched three things in a row? + // if so, don't finish level yet. } else if (levelfinished()) { // important: check for this BEFORE gameover. // otherwise levels with turn limits won't work. @@ -4976,8 +5519,8 @@ function mainloop() { if ((things[i].gridy >= GRIDH-1)) { // at bottom - disappear things[i].addabove(); - things[i].startexplode(); - game.progress("sun cycles", 1); + things[i].startexplode("sun"); + game.progress("suns", 1); } else { var thingbelow; // move down @@ -5000,6 +5543,96 @@ function mainloop() { } } +function canmatchthree(what) { + if (what.isanimating()) return false; // ignore moving things, though there shouldnt be any anyway + + switch (what.type) { + case "llama": return true; + } + return false; +} + +function isongrid(x, y) { + if (x >= 0 && x < GRIDW && y >= 0 && y < GRIDH) { + return true; + } + return false; +} + +function matchthreefrom(what, locdb) { + var setthings = []; + var n,gotmatch = false; + + if (locdb == undefined) debug = false; + + if (!canmatchthree(what)) return false; + if (what.matched) return false; // ignore things already in sets of 3 + + for (n = 0; n < MAXDIRS; n++) { + var gotone = true; + if (locdb) console.log("matchthreefrom() - checking " + DIRNAME[n]); + setthings = []; + setthings.push(what); + while ( gotone ) { + var newx,newy; + gotone = false; + newx = setthings[setthings.length-1].gridx + DIRXMOD[n]; + newy = setthings[setthings.length-1].gridy + DIRYMOD[n]; + if (isongrid(newx, newy)) { + newthing = getgridthing(newx, newy); + if (newthing != null) { + if (locdb) console.log(" -> " + newthing.type); + if (canmatchthree(newthing) && + newthing.type == setthings[setthings.length-1].type) { + // matched + setthings.push(newthing); + gotone = true; + if (locdb) console.log(" -> matches!"); + } else { + if (locdb) console.log(" doesn't match."); + } + } else { + if (locdb) console.log(" nothing there."); + } + } else { + if (locdb) console.log(" off grid."); + } + } + if (locdb) console.log("matched " + setthings.length); + if (setthings.length >= 3) { + var nn; + // matched! + for (nn = 0; nn < setthings.length; nn++) { + console.log(" "+setthings[nn].name + " x=",setthings[nn].x + ",y=" + setthings[nn].y); + setthings[nn].matched = true; + } + gotmatch = true; + } + setthings = []; + } + return gotmatch; +} + +function matchthree() { + var i,n; + var checklen = 3; + var matches = 0; + // for each grid pos, search n/s/e/w for matches of 3 the same. + for (i = 0; i < things.length; i++) { + if (matchthreefrom(things[i])) matches++; + } + + // clear anything which matched + for (i = 0; i < things.length; i++) { + if (things[i].matched) { + things[i].givepoints(); + things[i].addabove(); + things[i].startexplode("matchthree"); + things[i].matched = false; + } + } +} + function levelfinished() { var i; // past last level! diff --git a/images/bag.png b/images/bag.png new file mode 100644 index 0000000000000000000000000000000000000000..4b044c1be4257d97e4b015385f355b74f24cb070 GIT binary patch literal 4640 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 W0hbeqwXNU)00009rA<# literal 0 HcmV?d00001 diff --git a/images/bagpop.png b/images/bagpop.png new file mode 100644 index 0000000000000000000000000000000000000000..73b3c131beefdc891b52f0411b954168f08fc13a GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^AT~P(8;~?yb0--{aTa()7Bet#3xhBt!>litpVO_-;oBhKVK9eDq%Zq};tp26RuvhBgR%z{x|sZ% z4sVDIEZbdMdpGaC{N|oHXIAKNwVgX$;S*y%-GhI|Ugm^jv%FF_9*oLUoO(cU!rEpA z8^-4s|2Ks&s!m8$FcFO5SjVEr6u@!fjl|~MCC~Nbb;a-9y*hV)=AQqVd+oh^4!wU9 zcY1f^op$5b)4y+fwSUr{9i@-9im6{U*iv=#{%N-jJ2P&*-17O4(7xvf{jwhyi#jAK zFg@CSv*t&^T4Tw{0vR2AY)AVuMJB2nR?eD~CRv|qk?~DkC?yIM2%fHfF6*2UngH_* Bh*kgq literal 0 HcmV?d00001 diff --git a/images/fez.png b/images/fez.png new file mode 100644 index 0000000000000000000000000000000000000000..5f832b87aba63adc1f2883170308ba035d7f0cab GIT binary patch literal 3338 zcmV+l4fXPgP) zI_NiD&#m9nL4P5%T!5#miMmtUZhsotFiz|o_n?AzL8NKj(=b`=hQp1#zIJptoa@Qj z_~HJUJ6G2y?GrXx`*IW7PUq&^`MsB(+Vj~zvbQ=Pd8-fp=SO~immFK(?|EfU+vpFH z`A9Et0mL&PM{k`t%vdAnT#wQDBPQQCL0&W51;IfS0|Y0axIzqyyCFnWBT>3e`or%a z%|C2R#&^v3mcD-AEC2ZX{|m?+zw=OxU;T}bNtZq-qL+K}eM&cHo-j9XMYECn%IK^i zq7WAX{z{^K;S?SNA|MEg;O>|^A_7vbi7MdWMhJ?dfFJ<~fgt*@C8Y`5F4>KWVQUjuanf>20-~0QqvaD~j!L;E zQm?6kLp?gcJ#PksTQ0lv_K&?~AP;`v`WsKIz4#gL+L5>l>W~sz77-JL z@dnNQZ7f~1gYhHZK@zm9sm`FhR`J=(RTaG4oPuz7R24HrRZqJvB6yvgh~Pm9A<`av z|I(G8{o~cw0}{5L-2b6#KY09=!~fK^ZO>8?b3@EaLZ{6iW+ggOCOVz$6hwK%PP;yRQL;>S$28L{AK&=gbI;uUdO&pR$;#p9Z_3H= z3@H~HWOH)v0AU;x=iYcR%Xc4T{J>$_?BuS++{rm(W|$c{B`jrfwlW^a9XuDbW=76= z2Fl%WGGHb5Y7S*HvODfZHbWZw_#08{G$3)*ztYUfIhDaVlP#07W4qwIA3KL5fBQIj zHPgA)gqJ!Q!_9E3c_dU|8Ougzna(oFos5t~Xx-_|$O0Y%Gyzw|#OW+EPHlOQ2zbCI z-9A6`=cCsH5>G=FRHFzcikTO>xYO%LhVR?M^MC&gXdsB-qPS&r3#rV@3aSJoXH*2i z%4EDmB{mTeP!x}VDxDhv1*|5&-~t*#5g4;dxx}|dU;Z25x;F&!U)TQf&#WGPgb+eW zL<%k3oZ*2vzIp3YoJFKWzN~oL<*G7w6!N;&3oSh4S&YWCj6e*0#mHS5Fa%P&`wT46~)m-C@eyRcU zjHuA%j#O)usFG4DV;yqJB^rRIjJx2ImQ%03aO)ca$z9qnQ~lf`m2*3KtgLJ>qK6>3 z2q|x|Kq4~=DBwZ?Bao-E3s}nKo5JVIaMMFRk zf|MwErL4D^W}JTYH9)S}e#2QFkeG8(BrhH{d&jen9cO9K(212i@VfF-yW#aER#wkM z@J+8Wiw-7rY>fm{u;rRjQp&Z^HB=wA^{^W4R*m433m^KqPo8%gkjdGLhhhsU8sdW1 za1Q&CqtBgWVbI6TYYsSCji8-o086e&<+QsK5VU?|rlc~}i859xwMHeB+GWL~St>=@ zs$+0>f)`Jvmgw3FXxYTC?K?Zv+>C{B9;DmwDy&^0$J@8Ts5Sc3T z4A4yH>*T;^tL^TyXQoLTV=VNnGVf5CuqhBz)%0w$PGhEqQ-ca*?~s!x{~17z{?Lv4 zpSCByJsEe^BpRyF+Y@=^#28Lwgj!(%alvqs*MxW6BPte zDcq06FDY6&MY9=2aVLgQ+Jf4FP=cf zX0(}#fKg1{)ak0$o}B;TkK9qwTJ$!XCN$KRmXhdUGhfhR-@P_7E{=vkwz7~@iW!b4 zgH8x`Tjh#QS?ZbM~*B52VLkuV23MmRZf-s>wt$T|K zjW|Js5VhuRrH>T8>vXeW8kH?IpzN4TMM7{F%mq~?gs{c#RO=(fy!w`wGfM&k%bDJR zA!lB+ai@0k;d&vLK3f#W80~L3b!1HJHHgb;y|$|0bw|X_2`Y${nt^R5_olwfOr=Us zQbMt{29;#r%%_|ZIp@=g;Pf4clF4{5n!So=$F)N(DqpMwipf%6FDYl~N|m znzPhpnz_Kzp}>W|xj^={FYG?}$Rly@wf*?g2Ap_ggWwH2Kd_UylvqC5v9#2cN)21` zKxfGqR1opH<+izvGcBysNvl@gnG>oxwAzzLgq$5!pH=)K8j6dPth$X(h-V8+2O4%< zVQf1zm)+!Zi&xzJYXEU!@7!;n{n7E~=Pwzse7Cdj+8sQ8{|g))k2!B?uGj@H)wuEi zk=k=mi#j-kYEy(#m{SI8pqJQw(U9#26H6EL znBNjQY0+X+JeldH&2px4-;`8+5PSd(B^*dSd+(|MB1pTylAj?V}#YA5ENi z%2|D?V{$^UWaQu^Z&3~8D%r_9Kue42%nBNAD3PR26er+B9g?~Zlgw~InA_cF+quH% zJY&ZX%(Jk|$dZZHSf@PN_2&L;E{y-mLu1>oxX1q2U6lOfk%zPOxa{IxkIBNZJLYze zesXlq@cgr^6T&u0Ynf9=Th@R6^-cE&3cY<+-fN7n{obi5II4fK}!^yV{z zxrY9d5f=Ik7dztOh`BS3W-#*D-yltJ2{EaK=hwp8J<)dGyzA<_?tWXl@yEY-^>eH1 z>*sb8d*HyYJa{F*xc%Mv$)orFbXxCzWYVoi@B9MQ?m*K1Vh|S->uKZAHW3meMEW@5 z>Ym)m*}6G5J!wL(b(fY9mg9Kk3HSLn>C%g1TYm7=zCE`ey7((EzukXx%z$h>@C!e+ z@!Yewt*%U%BzgG4Pu%z3xAKA~{`D6R#MLj@An%BO8(osc?Ye!<_$;MM28q>KA*c(R<``ShDVeIMV= zW7dFlE5|RlT7?fZ#H;w-wnq1$e{qozI4_5@JS;ICJiBVivaV7K4k!} ze(fgZd;BPEqK!TugVJ>!Xpb27es$|ZI}Ux?-Vs3Z_}CdHLq`G|+N7|!{b}A|haS20 zJ@3{KmnNgL?$Y6iI6qpQG;;Wz1|()3Y{bFbUw0uss>7w7O>g^6r#9yAeWwBWZ=s0F zv!7F^PA&5X7rcBfgWS2}az8$QRn_}`o_e3(`>W@zXMsN;KfQ7`_g>b_-50gK>-bOB zRP&c65B+WQ!p%4N&w1`CzrG~rZ!$JC2#S%M*p=* z+;C~t{|VOGw!ah%q$6Jvd;0EF|v_*6caizvqPq zCwGqV=#IYP_0?Xnqw8}acj{llQtr+U5#aiVdja^}1@QB$=KfhMzvprpz?{lD&vf;s ze|})s^eSg-tMbEn#*p<+`k{I#}V{(;t&!z02+umJA6s*P(O?ERyHu<7r7 zthp!u_WkoW`WM8a9baGkDfNLM@W#iiV zKPmuIqrU%jwVwkwDy>$^cW0fQpZmU!K>+lKYKunwV9|%6%wuVTneH4i@ zn)cI^YvLvSW?n4a#YnlCg$b2YqQf+M`w4p$HXicutZ8*znm^0Jz>w!7tV? z;fXg!xZ|u~ylbSmzB?tfyJZR49;8`2j;4AzRBR?UG|kDK8ZF)wOA?P`nJI>?Rp9;@ zRsIk&y@#ll58+ZHN+2UwvOj|LC$N zZg{N!?fbfQJA{4pAFIifosNl;y?(5uuAMMK+|>DPo>+1*VL@=>H@>3GT(-=7PXHX} z--NB#-E-lgRBZDtyDwrlBsONfQe z#HUz@NSw@OsqwesbB8f40gthne0~eNMqH?rIjw4pGa4(K(pL2kZ@ajmOSop^#Q(mI zjW@04>hEm>;9DP`%Rm0=(7Ud8^tSe(sQ1Q33-+nwIr*w0%Ef6j&eqIoj6R)l{|r9W z@e^w7QKxCa*)4N!-`@YO06ct6D{JrX!~Ak2bpKxM>xYXoKC^9PCM9xos3qq2?ZK{; zDMg~>Ts0^@lSy|SqtcUeq1gvtO_TS19;RJGpmS3^Ph8h>;IOo2YFL<0=|9_`$``8xhLH^`u2Lvz1)KVk((?Yi z`e7VSnW(hTot$E4ZW-q)J5XQkBfDxIj#|aV@f}V}>#WOLzjENw_hi6{TN~#8t}pY- z1IJo}ihC|TUmAJxFik^6ro$}=l^l*Jke8}3@#DB%oOKZ%1?7Zqd(~3u` zP|2G(c^85wa4hLd3?zm2(SkhJAh=KyriQ|_sJuAkDa)Pwosb$YF^`<+CjU$W!5RaTlXGt{eJi7@WlQ}3g1~S^^9dNvMc&^zaD5s z5i`_>MC^)8%XANpRmRjjxLgi~*N%N)xA`fq4ZkKvSG zA|z#y1rwpXgE_uE)cQaWt3XniGCD}>Ny=6kRa-zXw2HV_0B4+9UkRtuk8Mukk#f}g zZTzZCzT%MZ2T&xPM&AfwX&lGZf>*0yb!`{Zri-JQTCCDhULQ;m_uJ?~6H6ldY)w`N zzxhgf$J?L4mG`|Fvi1*61(WIQ&FQj1fZfzpoq{B*)R&LpHj+%#&B7KSSQ;i1ZlmN0 zV964hVio?n58?8)AP}SlH{-e&A0o$!r?NnM8l&_)F6(7leO3Hw@}EhXbp&OTyyKx= z*-O@R6BG*s%}2>_A%=D>vK2@6Oi-(psAPR;&VHJ;{kR03aH4~8X9X^b6kQgLuFb5i zdVqu*LT+f5;NgLF#8fXIXp585{T$200hc(IE`J!f>m5EI_3ukuU46r+%UGvunfeG` zZJbomMM;U%K@v%yLNOdFGUR;KR16g?1wku7U_NGGB_0uE(ZFvOiFo{=M~RwA8iQ3F z%$$vGO%M}@=un?!+APqjRj5{nLC{H60_-hb&bZjds=%G>(7%tze-45oA&4SXayO#w z!F1K*Qvwu?IN5wN1LbBawwrbF=Sb(>WKAFWNs}eC7!a3|w3}&;&crg)Wb%Uub`jkwQ16RyJXg(taTQ99f&k(JKFvIY^X6pr8~sn;=LEMnR@71gs4RZ@xD zkMP0Bk4cz49Dh|K8p|_Ukw|Ddl08b%Oyc&;$1nDy${ze~g@iIDzW9(g1vV zX}mhG7k=1RtP)-vUqHm(OU^K9^;pPxfvHdjaf`;tQ4$H0h(F7KK7(;<2C7iT ztGMwfZX`jbWEC)-41OnrR~87kp*!D5t@vwB5534f{c3clnw*hAD5n@qhtSBN1XNzn zUrJQ!#%1?2X)Qq&3m9e&zhV)0o5-ZW&NGlnv(ocL+QWzFJt-j+W#UamwwPaMz;zb2 zldm%Bp23UV4z1x5ovAiT%ITaPec4GFp2KekL&>i$5Jz&>sj`4Dkk(lp-$HwhAJsn} zS7nTv$OH!(uO}B+$Z6r7c+z9!r?Z?L-^$-aZ$r#Ihb$_9L%NiwVj1X_3Wi}4^+&PL zNft)v2+JIFzKv1I^7nPulCcuppZ+H9`UowdamI{B@*_IudVbEn{3_he0c3kWf)v6q z4GgP->hj=rX&7b+6OB&eDta>^YTI3$dEpdOY8;`gF*+246XQ$>D+tQRv5X#^@(B*- zm!i24U4lL9?Ni`y7c27diPERMQt|ZXPq+wq-K6bCsx%W#=;ri9H;yohPd|uwbOcf= z_0c358~RFT*8p5}ZsApqmzMmyGQ=l+7%2t7h@y)TuNpTeu=| z4}HZ&^q1z~6$WV!ouJKkj8@-Kc4Ssivcm*~B)0n;%C?AUSMVw#g-Qw0B@)pz`t)UV zXHUgeYsgRLIewy%I(-ivsZ9hXGYmJKjbBYMk_pii7I2JyR@Zisu6V{>KU>?z=7TA| zusWcO<}0`AmezQ0|4j@|>%=`Gj#a^sXRsu^7t83U**%V9i6s4X^!hI0)zoF|FI`12 zv>M&^;5ZtCIg$RHfu_W%_SfT4!o+=Xnu7`UjCPUG+*J9Sd32zIm^{G}-&4F^x{6_Y z5tggSggl4t@(0Q4CXMa`G-$^$%cF?)AY~y=NNYe9ZBqI)s;dEyG)=Srx5)Y{NM=8# z97gU-<2H31)4}#RWTiZA--oD@dytKt%!^5wwv=~mKKN!R`iZ3hEn6ymb0{B>dkWP! zMlX^*#L;Ag1@%oV)OIjh3K8`|D3)hjox!gB^&mzFvyZs_D`v=#)1q#s!SyuN%5e;1 z1X;-8mCIzxCOuh)q+v0w8zh2pd~%RyM>?>OsSyt{X)a>8vYa=v7jP)EgsdjtQ z(}PDkgN2D@j8_(*l%A$aJxWYC$fDZ4v}q?8H|m%ydpMF?hA7PemEnaIZp z=@YbuzCqmm2zdeK&w(X#;OJ4X7MKjZbd2nTLxVES05_uyeUCzAHl`HkNVbhR!S0X* zpzCR2x=>kCrC7+$FwJhLQe6asjVzT%IW#q!J;@aeXB}$Q9s<%ZmJpXw}Q+ah_A*Tgz25C87p_!!j!>Cf0 ziF}2_nH<;#Lxmvy`dr4GcO;9B#UJ# zw4n74+;a0fG`GMXSTS~wF! z9-%Fgz*kwyEb)i5grT+$wx5{8;lqBqN9)j?L8gntbesz32Sj>akU2d1992;$yU#(W z9K&?gfs@Kg016f=w%;XMBr7vnIPoB<{y6@&BFUv|DiDjHblU15) z=P=u)(dh1>QR_w%$|#aWSvZMbDv>q)xa=t`$0DUm6znKDVK%?+ZKoutj2K-syS-hEl zMgkMB5Ob%PiUrA(rYPo2{6UAsA5n3S9p)Ra*08rbM^H6c-gXwEba;aVVA(dN?dX$b z5B=p25H@}aGmCU;GIqL`ytD>AcoDU+T`aFX$bw)elB80y{CQE3dn9rLl4$kEJ@$!u zpEXtEIawB5im6ITbFvbUPfQxofvgZKn5k+(JW|~@@4#G-$h_fvfu!zXdp6F?6Rj+Y z{RVPVXyQ=}a}|fOOPSV9YCHjIwE$ycT2+-dV}Y88=G0`ZVyaMNMreet z$kpU!4{>LRQ+(Zg!goKWso_v8NJ3>tLqOWm5ES-SX%nNSX%}_dT}(UiVqR@5ocD;U z+$zd(PZ0%y)g8I%hN|$Fq)O*g?Oz?9csn2P#G2SwD?;I4OF{@) zws1rR7uJxBz9*{c`(y5MXKhI86Y!==b|6*v_5S?-Yx>&xT9el_N|C7|b-TyoS4@@k z>yAt*{sXB5lZ67R1TkM20S7I32`=S>*kYK`+;PrJ+)A;sh<%xVCX;%Y8#``is90fq zJc!S!5UKWY;o>4EGjQ{cS2;Iv8y)_EUw(9c>8`4CIU+1NQvQ4^2wVO~R5ZOw^v z)$);7`W~3mXv!|pay*)7SCI64C6LP(gna9FnhNlW^NxOi3%pp3XL7@jp8LNt{JWR7 z^7oJTy%UVD3!$M@xaH7o zXrP_(Ob_k$=U5tk4kH7dJFCgNCBE|6Dc&e93K&0FQ_l=fh7bQD_j@3|Tkq=~ zsx);crAtp{qBrhJ&Wv|X2t=eQA|B|;)nHj7t84cWlCtE)1-zEMoC$j-rmK!Kp^{wvo#^XLhLchCO{PyU@U6!RE$5zY1T zoI9yx zJg+jNx*EOWCoBzc+lNbEZLN)eFM8wl$+sD|bOkrQzT=$$JicDCJ+kREN8C@%{)&Fd zUrLkDhRYLt;+Jn0i<~uZvfZm4n5t{b7K>{lioP~gR%dsoWIFRp*)`FDCiK(l?L`x; z$+;cvU-+jBoXU4HA;6@V9R znaeqMA9@eUeM)=d=O4xB`Od6X{(@!W$7|kM`u;*#$bYd`&VDiKDc=$HWxvwmbAGV& z9UWnJeDafjSn)5fSD)T`J%-~rF8)7|?_Ac-FE5Y0=bUd|w($Kce0;t7!=Bqn@mDIM zB#GV8D(?`$Bmc7OuMPl7a0g!6KB&D21+MtouD?0}{sSd^>gi^mAC&+A002ovPDHLk FV1ks-IoALH literal 0 HcmV?d00001 diff --git a/images/shears.png b/images/shears.png new file mode 100644 index 0000000000000000000000000000000000000000..04d442eb9bc8ff1d845ffa712cb1e90268ef4cb2 GIT binary patch literal 5106 zcmVtA;0000TX;fHrLvL+uWo~o;00000Lvm$d zbY)~9cWHEJAV*0}P-HG;2LJ#QXh}ptRA}DaT6b6!=k|WTnb~D`*s zoBBNYUC{Th-Pv!>KJRzlbLO1$4e%GRb7$mNr%olh;v)g`XBK_;-9`X_NQJ}s1qGL4 zc5fL604tY%gOrqn50*UnvkSLv-w36toY7QjQ{KFJ)4wRc=-c6=MlI{y$)j?AY&1rV z4#G!|ty|akirf@V{f7>u<3PY*f}`7YT3HA z|H7}ATwDFmP&hg^$MArFk0<79uq$c{0DxoJS$6hzqS{Q2SFc~&|CoL~Ei5c_#KNza zelW!UGWm%Ureoi}9WYgxWy+)`*KF+V07_9-{#J1_BlEz#d2?4$N&x^zjvn|pWe)(+ z(OdgxWj#K5>((7qRaHSIlS7bM!sD|x2Sb-E9r@9D{(S@m1)s9CvOMk3zyX9($RrFz zBI5GB>=ARno|BZFbx#2R(c2O%1_`6DR66`PkS!fBL3zK~oTSXfOJ7>zZk6YjerUx*iCj(3h7%PPAZ* z29y@&y6)e*=hC6W2OD^LdLlM9w(iCJ?x^pE5rR|ZDzow-!$#uUh~;S7&<(!6{(s8A z_eWw{WMtgSy!GQP=yZD2vrt0dD+6r>$B+JT+|L+}0RM6K?QHC}G;Gocg28~7c?A$Fwb1YY zZ`7lpsMzvkTI#u7JHK;IIFx{>=;*qY?PFuMFJ&c?WfTM~%WPm-ZY2kkQeS_6df-45 zMvk2DyGCMTcQt(S^x54zw=>KN^7CP)ki!58bOtTJNFXTGu(dL)?D}b&4qwgtDyv=B zZn$;ja@~me(c`9sGAt9vFa&}i%oYUWW4%zhCGm&D_BF&4kNvt_FYwptRpG%kBsuP}9t1aQ{8&D*X$UP+-XD~4_0n4)BI4KAr zp&<0Zv4le_(^Ai|e*PnooE-lPBYR_ZfDl5JYE_6^i{{k2o)su>1VaG{p1jQ zin1!5{NAJN)Fq*d`~hIe%4M}*;iaS;gO`^temEXKf>I%t5QZUyR4<@_Ao37Jv4mmS z2@(l+!pqZ7|3kt-C{z~c(`NvV#_xxjX+3FP{_|UpvY)g_zj_TuQ3O~Cz{eu zWOjc~-wOb6?%XN#>eU|r5Fa1cvbgxoy-VjW;B`R(cvb;cB8S!}LL>x~02~KcD;3~a z%DcI^c`skIICV`#1m=f?)NXBm_*fi<`3}da)THlOmK`Pt0;nj0fIt+*>ReDAQtAtX>vYd*!W#LInVj%Vl3M40DHJ7_b}%mg69iNWd@*7>4^3#-_XG79i=4PT&=2badU-H&qE^WKqvtS0mBf0WkEq9GAs;woq1kv&gr-# zvF86v;(yrHrC+_I&>8i&L1{Bl6af*SRQ&l)3J9VAQ8Ypn=zXJL2=?&_xJU@Wj$IL7 zFkp74o;;1p%1Y=t1$3+oqEP_HQE&_eM+KOhS)#1;4H`DE`B`wg3?=uCqF@S2Aqv&f7g3!H2mnD4U^Md3>2=1cs>)QE)O5s< zp#kMlyCRQQR%yM{PNhKrpy!k@2qFlfkeF~_L<3lnLTPG>%Bm_jJ3A+ATC?7-PWAIw zuU&Mdf^dX@e>q&gP}f)NH@51md21J9R82ov(^)yszpmFjBNgNG*B53`{Y zD0qg0z)B#O%OGks0Hsh`nu8jQAXJ2-vt#6%>S?9VV@Sq>a4fx<)vm0V#dm6_~o+|)VJXyCWCZrd6vl_?le z0An;jDm4KWc(5D;5D}Hd#gIxRFbV>4p8qs+`RZj;*R9(KL&@{HGs(Ge{Yr0u9;cKl zYOaZ*2udkLQG_UpF!K6$h6O=@U=)mbuV1ntASaSeKyNTYFHrz6f+G|R%fO)3L24p{ zi9!y&P7hm4a||8OYnZ2B(2?sGkHOu;xAuk^=~pk{=KVBu{H)8_yu7?=dcFP^Ua!gi z5{U$Ig%Tz*#XDt4O{APsttKXN8Qhw?Lc*|+Q65r-3UZ|iEWm-hu^lf}ENPp1+7Kb{DS$!{ji90khynoM z$+IUgRhr^datg}IE5S1yIF%9#30IvbbUJ7?8W5!=Or(+%KHT4Y6r(V6YH!eo^=1oE0CXF56DS#02ZX;Nh1t9#sFd&3Lq#{I70R8u4Q7{@| z6a?@_0TpHC5O@P9X9B`7U>O2ag#x@@kC%@hL*R`luPBF!LaloC{E6qiyAO6dG_V$q zA5W3A{>dLCxh_0sI^?Z1AM zmEEAQAU{?Rg&b3*>GCSAVSP?+jsqyruu((J_;Fvj1`Z#SSL>dy!M5$2F+OPW`GMX8 z1eH?Nn-KCY`PCFbHQ%d015^+oQUUJnpFywJMX&znhM^uFy7DZwVo|cI_0pcIkqEz%e`kOqw(f z>()gUbn4VWQc_y#A&4SMN{Z{}=H}$BT(Ra>TwDx}9646|vIl_e+qYuMlwfS$vfjH* ztJX(kGPwz108j#sW3hA3ZWxV5I5upEc5T}r>(L{vf#*BVo%>D3xpODctJi@4vbpuU zjhHs|OKJc9Ju~xOOV1MN-&a>k7CC3IY|#6W_?~( zURouJ;=4VrZ*LD?5b!i72icFaA@KT_bLK3(8y*(=tHc2yc-kxwLJU27_a0zlYoj#^ z0v={(tJ2P#Nu-oA`wzs_uI%5(fdk(oDry@hO$yF+b94E@(!z42OeT|2N?~hbjhlBe zAmKQ)Y2k*GscGgXQ<9#nT^D)p_iV<+?ZdRGA*Fr#_9`zdDDpJ$JW5K78|J^xeKI|G z_T7zJ!f-O>Ozq14mvY^J;Ayk5b?c@Uj*S~%v9Po>qo8>5{3*;$O_7><8d=$oQQywy zO3c3RyZu>vfdPKWkDfgB;spcRwrN#9^UGjo_x3#tYhCuglksV#fRFFs;q~oo3prMTdztsuM-L|? z@Kn#P-56GP$OFLq`SY=9<610V9+vw$FRyd%%a^Z`PMkv8xpOr&02QfV4gjM@P5eW9 zTefb(=#k?pnzwMBZ)Ir#-pC{U`j4H%!^4LEW7Y!fi``u}WdCaz6Ew=|ZE;DurlO*$ zR4Rc=rNWCBFJNI|v0|XNcUVZsTy5{}-Ej8OA0K0l92Jo8BKM_lVNn6x-8K7D#nKR+MZv141>p+lRpA--PTHS2doZU0p}$tSAM3}=K)9MR9SFKy=HM7#Fr zOhZ>K8Vdj`Ll@M|4VXD|Iso8Md^{Qd#h5NWgFFj+_UcBx2YJ#y{d&?Cty~44L0-Ek zr33(0tq%QNdm}~#Z0ypl6K&e82^~JlpHEFobgXl-uR&yF^{Z^@m(J1Md-h!&I>f)J zt*z}|y-q7iB@)=xw`1~)-b@%Y#OF%z^vTV?S-2Du0O4!H{=-fr0HAT>#^2Plwtl2m zo8!*y3@$M-d4E#!QR&1fUmztV4s{mo+PMJ$_QdQWv**n8@Eht=+N*bW>gm;&c5rV` zyY}c_IW2fn&~Gc|Bfde{og+4 z{|vra^c7aE497Q%7BtSvdKg(&_SRdY(Ll!wU^&j9Qpy*fJAGk2A;h?N=>n_>{W%vL zh~1;w^xf8!vMPNyOEWWgbm@SOpS90Z$Q6$y5{Xg}1Z%zC@Z6x&$5Dv8-&VXelDejX zwUKM_=;j0LjNXH3!IP#vefl&~r`NM(<>er(6!k1E&JP~s={0luTy4uw+hgq5KqyQV zm@#<qdJbUTVVV30v*jigbYQmvS%T`ojDkCh+t!<#M zszh#X?zR;x7CTT%nf-eYtdBc*6wO?lH7Ktrp8){9dV1mPh0_3l^XJdwL1u;_zp&tz z+D!F~`A}rPaN!~h89W$4LE|d?hmG(sQ>)|aSzE)P)#6y<4|511qE63;RcJJ*tg1wt zwk>@Q9gf)r0KI$k#r5kK(Ztan@d?Sas!CJh`y;Yh;%UD=r#oV&XR)E3s<-Fr7i8udK2 zvu*s0-~-06K)=IHotyYOIl8o(IDT?w&2?YDfivH}eH$@yL;$2RDI}cqn!UY!lC`zX zkZoJHJDt05!S(*V>_X;4B>mOG>YiV%R%SaoHbRH?9p4QyR;>=jvH0XjJ6qdzhYlTu zMxz18F`X+lm8({-SXr@o^A5}V_p%G|p<~pTfKzdY_RtHLQXBv33}H;bswJTd>5Q3^ zkM`@=vvW-sJAQo7|GuUDyP?(TY>Wbr!ovLF0B}4x4(aLXc$j&+`uD1;v*Qe^#5D^?FrM)C&M^ z-bzRNcAaWxfcgJ{!Gpazy0vVc-o&v9Bb9JasZ`-C%N@6>S5N%u*|V{U#}f5NjwH>x zcKs?kyLYL*>FwW*=FOeq?AV;q7|O!j-P_N1Y32gL5GZ6OMnM2~>{w!A+`;(YeUpj( zP|3e}Q-bWr+4T9doHV&y{zRwMenJJoA@Aku{L^V?_s1VSKE~T;0D1K2$#2^DKL^UN UR)M_BV*mgE07*qoM6N<$f~VEHLI3~& literal 0 HcmV?d00001 diff --git a/images/tissues.png b/images/tissues.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6b6e16af2e5ef96f2ca0c58881629e5bd9fdeb GIT binary patch literal 6078 zcmV;v7eVNWP)u83J(ND#fc!H#Rdl?A`PJj zdaCZO>DH|~o?-8mKhCWJ5?`J}@RN7yb89$v-&1?7^;^F+ZQ-|gEiJDwI$ZmIu2WU+ z`0SU1&T_MAqCk^d?rolV-3NZ*+WQXe<+0O8J^0zXmyyQ}|I&Ms-klep zsbNH{MerlTHTTf9w_b8pbLFQa_p|r>4~d`>a}l;Oij)S+Abb3Mv(T?jjujO zr^YAsu1l}86Hh)VJ$myo*}vXHdv=NHy3yah0uCKoWO{mR6$K-To~Fu76b0|F)*ds! z{P$g&ed_1ee>eQe=o{-Jx?xpODS9(ybR!6U7J zRpAfMH*3Iifd48&BqHM?AR?&pL>tdz+YvWQHCVR)=DIRaI4 z;}~P|R}|2ko#UUb{5rd?`yR`8?!YFF)Cj2+D8@Wx{18uG*Jk_v0=ph~G{y&5Q3Sy$ zBzUYCsFZLMwH@8bp&NDm=*{&LkNKzPyz5W*1F7-|DFC3~YDjTtLpP{FPUhuvRq;N(ndlb zQUHt!22j8tI8_p$UkpiW#eHeP-d$cl_RmK=;rJ__|MCC%Yy1g1q~%osCit*wfPQPnl;uRh0^Tqi!wK!ll-j_1UeJd^a! z?{oi-9o(aeqsn}%&W)~$Nh2DPfXNW&DHu!O!2%%`F@h-AzN65OkBp5!a(8p-td*iI zfAhl6@AD2fDM&+a8ZE*BN&qJ_|Y2Ewa$}^u?p%0Ef{GV=P4#EFPmd z60ETpRl1tdSjh#WoTLGt@dMaQ4`VDgS+0RpQg*(kO{9ot2{y87K@C~m# zcKxOkHy`&0J+U$-!UT%JD~d<)U@Rj4iiHQtT)n*W_{_6wVUYu!9upH2L=uw3j;eH7 zH(}VEC~553zY=lZija7v5Ue6g5H$bN6sI1KAQGbebTkNqar>(ZzV$61<#XG<1HhG6 zei48tP0frwaozOGwq1D9hnn}_|C-pllYZxnXN|6Z{E5SOU$w>B%EAHm<&97 zdm$bHls+k4GEx-8VkJbZ!4!g>CbF0R(g@i8p7*l(z3<^kfAcl~ZvXywirc?%-P6L| zd(Yi-<>#NYSj=Xkm42lyskoUVnEu@p5br}{WDsu+)`EJ)t6zh=F$V8FsFKDB#u%J) zWJ#Z$-~BGPUGy<1wwOGoz*ryVe2VFLtSbHWAx#mAZAbfvA_sT%i6>Le9d2;zY>mCW zYydIAU=cCsU_T}Zmg9D}_3tX++BbcWUAN!G+iw37o8S8$0B-xhyEe?Tyfs}hg$dUI>Rk2z4V^XfB$JS ztc*W8@}})dXh(59#aEyZLl%LlM}(y!KFgWh7=wu5y(h4e3-3MZJ!ultTWPbh*d)1c z2fKd$6Yja{YTAui;-LsS&|o^Nq)6 z{e*(TJ{2;QjR)Jzj4CD&?uY|yBf^F${g$J%(xOl@{)cKW2PHgkLS z(E0Jtxc?t-<)?e^WwhN#s}ZH~A>?omK`_OLu$3^COIwuyi@~EtP$72#?})-c>LbGvT)E{PCf>ely6O%N{lmoH{sU=J;+YfkrU^#lChwZoMHkPoV!6lBQ z*C*+8X*HKPc;ok&{mQr5!4j2)9$pnUT_Wl`NT6*jVHi>{2GM{hRD59QhZ&h>L?}LT zIL%lRr7>iwqy`&>lw+VE^u*8&L&B9lI&eW9M1|ZEhPd60mk-aoptXBpb28VwR9$n^ ze79Sz#@4zF3MQmbDBu)Q@nk+D1Oib~&3#*q(nE=@Febv}aLjDWQCKN*^vpC1cilsO z-);_Vzn4R|-ob&zJ%pW%LSpHS8B8Qt@2Gf>T8NCLkU4CaLp2gdcLcQ6&kG#qDdC_P zAw5Ts2_y3vQ7RmqsWGw8MdOUozS0?wAnPNd_|;m&=LD!m$TAoEUgCpZt9Q=)p2jK8 zg?NDjb_oq)CbdY_6^RHaYKT`$s-6I$Bq1IMNU)*eOvY5X#|s~Qki$*KRdJa+uieVN zZ*Il!et?m>!IlE1Ml7JDVZu1qCU8c(}Ap}Gn zHCH2buuu9#L64bG81?~?kMK@uNQzoeN$C^g#gX_v4e4^mlH+irz}#Yw!=Ji>z*tIB zCTR*ZAv@%#mmO0h2^%vPkYdq~JZ7dQxi<@9C67#0j;2 zM$sCwz>owEQ5b0_#0c#O>X}8BQ!@34c&ymG^b#cyLl9V3s#P>lbj}z7pQos)rbHOl zX#q(~v{FaICPYyi#j&IbeUlQCaUk;?=sCJp*qGJX>rn}mo;O%y5HV{_kRS}DJUJ>sp;%Zb7(?K}V@XglJQyIj3+UZ$8^~#jt-8V5z1aEEoV?PxJpE9EI~J;(p8)&SvjH;38ij^Pd!=*SgeQG zUP{dwNMNB_;IYGopEWF21QZ;Kcb+s&wbSWnV8UP?6Cfl6gK)*5U{Ty!K@lMcd5s>3 z!HB^Io-F87m4GqV!x}@Xp3EqjDe^#1S+Sm>ELTDSq2eJ_CBu;!*w-=a?T4He_SiHP za912aHzTPONvvgPCCzPSpQ0t^DO;so)LMFn{QcBw@(}98t zI;b@~N@_BqEGcxGEgN|CEis}pC`<*g$e^8|7?cn&3V}eP;PIs5(JaKNXCEErv_U2? zNtvUvD&;U{B2@PGElre)TH1IzUa1p;K#C(K#XG}K_ZNBLSdRncA}a?|;&MP72>oJ2 z5n-sE(F=t}C1j`>L!46UXDp5eM13J>I_eEi;4N_=v?|JYGiI@CumcjzyvM1dSS(X5 zSNgTdF&Bhk;Kb(e(6#b(@Ld%%sND?^C`2fVka_51Nqv#B1dLE75W^;4A;EJfOE@kJ zvBt5>d3vg-dOCQVD5-ivEQ-aWBtFDO2}_d|iu+>33G|d+(b9ELL{aA`tvFgkA)?A? z!!gn}SPx6nWu|5m;*zBlgD)Azim-iN0Ec>|5Cl{vr>IYkU0xj-y6Tk|{Y5tz8XC%b zX9Jt3c+9~1Uce93VSr%Z1d68s)Uc##@ETB%Dic1WitqqE0t#$OD;%^Pmgvz?j{*e@ zP6b1lH!21VEQ>;;&v3uRzR41i^HdrRpQZH5AG*{5H$^oIz*%N@Ht+3!4`tyu@QeDvS?c{n1N-$43Gfe)RU06oQ>uj zA!2aKAj6h?tw5?7p$IV^!B8Tv-nx<#5agAls$c7et)d`KEc=fx5#8S*Eeo|oSQ(25 z+5we@#}@+VczgiOsUkyjJ%ZRF){;bqmGKheN!g9eY`S~n#)-e@v}auQ##cV032@cN zu6bC+`_c=xFr1F`y|K5Q!i@=a)g-4kQn_y+oLr?=fGoxIiiTkdb+hD~2pjSSnpln0iPZrG+m0 zr;4mwNQfk)-ZGgzZu5@u$DDlOlV5k<6^}Z$*yWNB@r`%>HHAl=#2H)8_=QcMVDZ3w zKlHSLvDN6mnm-2&x;d+gQ6U_-L(URrfRS8)zzFex>?}fz5{pOhYa}YF4`v&Z*JuSS zPCb3KlwwCvjgcxcI30q{rJ;f zcFF=Dc`KLy)s-AIS>Y*v{QQ5n)fZGoYOWX-;uw>6O$VD=?bfckfgt!nm<*A;$$%o7 zcUnRWUUUCm<&T~?VhwN@96~|zCa9AfGocvJ{CP$UaSB1n({nH!E1ep+z+h0Ml`yoB z(w;0pF`(WH+)#OBZf0`xmq(uZl#ieD#ux423m@Ux!1or87v(*oW|(k z3?8Eb7K^IKizgdcZXjxo4nXmQtKngH$Y~4A!k!bb9IQA0HNJ;M=T2nYu2Jds!; zEQz>0p;n6*#gj*!R2(5f<{YDKgK^NS8Vaew^c+JN;-LyrR9&o8r@lXa^l_hi(Zzr9 zH4#}mSn>6X{|{%LckZt|-!MfJYOPrLacOu2!3+up2E>+I-sJDB{aoV;lmt&E0}>o$ zjoAPx_90^r89WmNl{~MoYVe{&7z~!tNLlVU@Q$GGSQ!ans7$>)-kGVaziINg$N$-e z^WXeOFaGqqzp^U)^&j|5-p4%e#lO~oM}GKltl#!woFoZlf=5}~2P$ghQLc9w5BxMCpVc{(H`T$7_D$A?})qW>pKf{^ivt zH-326?X&hQefCdlN4b8hVvkCnVwTAj$|VbT*JOcG(R9FT+_ zo(PjqZ3fxjs{aRgp0#0#tz*L^w!&~>_`XVM>}qrDG1tE8Qy1K|y3a4Z`yz&C#yRVC zFZ~ahVh7iM;s#!D{_|KT5(7U_)oow<>l?0Z+*zkfC*Sx#*!;LtdFJb0^dCCL7l4~TyN!F&Z}9r_-uJLKzxUZ&YKOk^oulK0 z#Zz6kcTRVH{`B_zLLts#1Vd)>iBACtB_Bik0sPAvFe(KC5oSqfpkyckLMnsEpgDhl zFkK(w>?ag2zhijw7siiz?2n%Jkw0kwJPUZsM?c52-?rruImhsC4oKYcnVWd(YagC9 z-E~hheBk|;O!k(RHuXE5=XU4jU)0-waDAuKA{m6j5Hl!>1|3+Gx`b2-*e3}c&D|su zr7wyoWO%|TVtC`s_H{GkA3lAf{l>;iKRv(te=mRkCwTe0&VNMDF#TUoh}?4VEiC@{ z7G8MiyB|8gm#@9`(n@>w&^latW^2#vtJ^zwpBOJSaFWmb+@NzDBGk##;GGf=YKi=` zMkaaatPIz(+J<$XsLf1X@|YK#_Q2_{esK!$h4aqm*yGORiElXj5kJEBOC6Ef`iUEP z()njS?B2INdR^GuzN7BFe`4?6-GAKKwf9;5`Gvr#MD_Pst({)|mCgv=eDSwfn49Cp7rbKa-VGnP zT6#P86g03W#1G8AD&D^H`OMBA;j)B+v5ZQA1fb%IIL zl2K%#9CXw5V^@r9+W6s@UH{>o0B;+4GN*1ihjTynR{p=fZura%|K{FxxBbLk{q*xs zy5YaP>h0e;{*@p6_UUgrecMg9tqo(pxaBYZQ|$d;0082*r--7n6951J07*qoM6N<$ Ef<5zmfB*mh literal 0 HcmV?d00001 diff --git a/todo b/todo index 9919298..95a3f16 100644 --- a/todo +++ b/todo @@ -9,12 +9,37 @@ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/ --- check here for ios +*help text for turn limit +*match 3 llamas to explode them +*adjust stars required to unlock levels +*from lev5 onwards, shopping bags on right. +*powerups + *sneeze (wake up all) + *shears - clears all llamas + *magic carpet - drag to give cats a fez. Worth heaps of points. +*help for bags/prizes -*multiplier for path length -*turn limit -*help for path length multiplier -help for turn limit + +more goals: + form x parades of length y + + +-------------- +toad - if in a parade, drops down and clears below. + +more prizes: ??? + 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) + +arrow/signpost - cat parades bounce off and take out htings in the path + +diff colour cats which only match themselves + +--------- + PLAYTEST: ... adjust point goal calculation code now that we have multiplier. @@ -23,26 +48,13 @@ PLAYTEST: -...then add more levels - "enter 1 door" is a dumb goal cause you can just delay doing it - (but not if i put in a turn limit) +foot/human/cat toy - adjacent cat pushes it, clear the horiz. line. - -foot/human - cats push it, clear the horiz. line. - -powerups - earn by... entering doors with a parade of 9? - sneeze (wake up all) - overeat (cats can eat any amount) --- niblet bag - magic carpet - drag to give cats a fez. Worth heaps of points. - -furniture - fixedin place +sofa/curtain + fixedin place like doors parade over to scratch blow up and pow! - - fireworks when you achieve a goal *flash for now fireworks later. @@ -57,18 +69,12 @@ show points for each element along path?? --------------- -implement grid sizes for later levels - increases every 5 levels - -turn limits for later levels? - -wipes between screens - -- some kind of cat that doesn't fall? way for cat to 'climb' and not fall ? -special things - 5% chance of any +other special things - 5% chance of any { white cat - @@ -86,9 +92,6 @@ special things - 5% chance of any } -more goals: - form x parades of length y - survive x moves sounds: chomp