*random levels.

*bugfix:  cat-in-boat to goat should okay
*when forcing an goal object because we have none, make the chance higher based on how many things we're dropping.
*add more win images
* make win images sequential rather than random.
This commit is contained in:
Rob Pearce 2016-09-04 11:47:42 +10:00
parent 1546c6f4ed
commit 807bd533f1
18 changed files with 384 additions and 105 deletions

421
cat.html
View File

@ -200,7 +200,7 @@ var DIAGDIRXMOD = [ 0, 1, 1, 1, 0, -1, -1, -1 ];
var DIAGDIRYMOD = [ -1, -1, 0, 1, 1, 1, 0, -1 ];
var DIAGDIRNAME = [ "n", "ne", "e", "se", "s", "sw", "w", "nw"];
var NUMWINIMAGES = 12;
var NUMWINIMAGES = 26;
var WINIMGZOOMSPEED = 0.1;
var SCREENW = 480;
@ -228,6 +228,8 @@ var TEXTSIZETOTSTARS = 16; // in points
var TEXTSIZELEVSCORE = 8; // in points
var TEXTSIZELEVSTARS = 10; // in points
var TEXTSIZELEVSCROLL = 22; // in points
var HELPLINEWIDTH=4;
var HELPARROWSIZE=15;
var HELPTITLESIZE = 18;
@ -599,11 +601,11 @@ function isvalidpath(mypath) {
nextone.type == "box" && nextone.boxfull) {
// full boxes can parade on to other full boxes
} else if ((thisone.type == "goat") && (ccount == 0) &&
((nextone.type == "cat" && catcolmatches(nextone, firstone)) || nextone.type == "llama" || nextone.type == "goat")) {
// goat can go to llama or correctly coloured cat
((nextone.type == "cat" && catcolmatches(nextone, firstone)) || nextone.type == "llama" || nextone.type == "goat") || (nextone.type == "box" && nextone.boxfull == true)) {
// goat can go to llama or correctly coloured cat or cat-in-box
// ok
} else if ((nextone.type == "door") && (count >= PARADELENGTH) && (fcount == 0) && (ccount == 0) && (count >= 3) &&
(thisone.type == "goat" || thisone.type == "cat" || thisone.type == "llama")) {
(thisone.type == "goat" || thisone.type == "cat" || thisone.type == "llama" || (thisone.type == "box" && thisone.boxfull == true))) {
// completed parades can extend into doors
} else if ((thisone.type == "cat") && nextone.type == "llama" && (ccount == 0)) {
// no parades on level 1
@ -1212,16 +1214,35 @@ var game = {
frameNo: 0,
turnsleft: 0,
levseloff: 0,
rng: null,
goatdir: 1,
goatx: 0,
goaty: 0,
goalbooster: 0, // extra chance of a goal object appearing
turnsbarpct: 0,
screenflash: 0,
newestlevel: null,
canvas: null,
setrndseed : function(seed) {
if (this.rng != undefined) {
delete this.rng;
}
this.rng = new RNG(seed);
},
seedrnd : function(min, max) {
return this.rng.rndrange(min, max);
},
addfireworks : function() {
var delay = 0;
for (i = 0; i < FIREWORKCOUNT; i++) {
@ -1417,6 +1438,8 @@ var game = {
if (game.turnsleft < 0) game.turnsleft = 0;
game.dirty = true;
game.goalbooster = 0;
},
resize : function() {
@ -1451,6 +1474,7 @@ var game = {
score = 0;
globmulti = 0;
this.frameNo = 0;
this.goalbooster = 0;
},
initlevelvars : function() {
@ -1485,17 +1509,24 @@ var game = {
// 5 - 14 = 1 bag
// 15 - 24 = 2 bags
// 25 - 34 = 3 bags
nbags = Math.floor((curlevel+5) / 10);
nbags = game.getmaxbags(curlevel);
for (i = 0; i < nbags; i++) {
this.addlevelbag(curlevel);
}
},
getmaxbags : function(lev) {
var max;
max = Math.floor((lev+5) / 10)
if (max > 4) max = 4;
return max;
},
// x1, x2, y2, x3, y3....
addlevelbricks : function () {
var lev,newbrick,i;
lev = this.levels.length - 1;
lev = this.newestlevel;
for (i = 0 ; i < arguments.length; i += 2) {
newbrick = new Object();
newbrick.gridx = arguments[i];
@ -1523,6 +1554,13 @@ var game = {
addlevel : function (lev, hashelp) {
var mylevel;
var plev;
// find previous level
for (plev = lev-1; plev >= 0; plev--) {
if (this.levels[plev] != undefined) break;
}
mylevel = new Object();
mylevel.hashelp = hashelp;
mylevel.goals = new Array();
@ -1531,6 +1569,7 @@ var game = {
mylevel.maxturns = lev + 4; // default
mylevel.bags = [];
mylevel.bricks = [];
mylevel.random = false;
if (lev == 1) {
mylevel.gridsize = DEF_GRIDSIZE;
@ -1541,20 +1580,20 @@ var game = {
mylevel.catcols = 1;
} else {
// default to size of previous one
mylevel.gridsize = this.levels[lev-1].gridsize;
mylevel.thingsize = this.levels[lev-1].thingsize;
mylevel.gridw = this.levels[lev-1].gridw;
mylevel.gridh = this.levels[lev-1].gridh;
mylevel.boardx = this.levels[lev-1].boardx;
mylevel.gridsize = this.levels[plev].gridsize;
mylevel.thingsize = this.levels[plev].thingsize;
mylevel.gridw = this.levels[plev].gridw;
mylevel.gridh = this.levels[plev].gridh;
mylevel.boardx = this.levels[plev].boardx;
// default to # cat colours from previous one
mylevel.catcols = this.levels[lev-1].catcols;
mylevel.catcols = this.levels[plev].catcols;
}
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]);
for (i = 0; i < this.levels[plev].allowedthings.length; i++) {
mylevel.allowedthings.push(this.levels[plev].allowedthings[i]);
}
}
@ -1562,9 +1601,84 @@ var game = {
playerdata.levscore[lev] = 0;
this.newestlevel = lev;
},
addlevelgridwid: function (lev, newwid) {
levhasgoal : function(lev, gtype) {
var i;
for (i = 0; i < game.levels[lev].goals.length; i++) {
if (game.levels[lev].goals[i].type == gtype) {
return true;
}
}
return false;
},
genrandomlevel : function (lev) {
var ngoals,i,pctleft;
// set random seed based on level
game.setrndseed(lev+50);
ngoals = game.seedrnd(2,3);
// first create the level
if (game.levels[lev] == undefined) {
game.addlevel(lev, false);
}
// generate goals
pctleft = 100;
for (i = 0; i < ngoals; i++) {
var allgoals = [],goal,goalpct;
// make list of all possible goals
for (goal in GOALVERB) {
if (!game.levhasgoal(lev, goal) && (goal != "turn")) {
allgoals.push(goal);
}
}
// pick a random goal
goal = allgoals[game.seedrnd(0,allgoals.length-1)];
// generate a percentage of max count for this goal
// this will be replaced with an actual number in a second.
if (i == ngoals-1) {
// last one
goalpct = pctleft;
} else {
goalpct = game.seedrnd(pctleft/4,pctleft/2);
}
game.addlevelgoals(goal, goalpct);
}
for (i = 0; i < ngoals; i++) {
var max,maxcount;
// turn goal percentages into actual numbers
max = game.getgoalmax(lev, game.levels[lev].goals[i].type);
maxcount = Math.floor((game.levels[lev].goals[i].count / 100) * max)
if (maxcount < 1) maxcount = 1;
game.levels[lev].goals[i].count = maxcount;
// add forced things based on goals
switch (game.levels[lev].goals[i].type) {
case "brick":
game.addlevelforcethings(game.levels[lev].goals[i].type, maxcount);
break;
}
}
// calculate star point cutoffs, max turns, etc
game.calclevparams(lev);
game.levels[lev].random = true;
},
addlevelgridwid : function (lev, newwid) {
var ratio;
ratio = newwid / DEF_GRIDW;
@ -1581,7 +1695,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// thingtype pct
addlevelthings: function () {
var i,idx,lev;
lev = this.levels.length - 1;
lev = this.newestlevel;
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];
@ -1592,7 +1706,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// thingtype howmany
addlevelforcethings: function () {
var i,idx,lev;
lev = this.levels.length - 1;
lev = this.newestlevel;
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];
@ -1610,7 +1724,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// thing1, thing2, etc
addlevelallowedthings : function () {
var i,lev;
lev = this.levels.length - 1;
lev = this.newestlevel;
for (i = 0 ; i < arguments.length; i++) {
this.levels[lev].allowedthings.push(arguments[i]);
}
@ -1625,7 +1739,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// goal1type goal1count goal2type goal2count etc...
addlevelgoals : function () {
var i,idx,lev;
lev = this.levels.length - 1;
lev = this.newestlevel;
for (i = 0 ; i < arguments.length; i += 2) {
idx = this.levels[lev].goals.push(new Object()) - 1;
@ -1707,6 +1821,42 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.levels[lev].starpoints[2] = p3;
},
getgoalmax : function (lev, gtype) {
var max = -1;
switch (gtype) {
case "food":
max = lev * 1.2;
break;
case "llama":
max = lev * 0.5;
break;
case "cat":
max = lev * 1.5;
break;
case "goat":
max = lev * 0.25;
break;
case "brick":
max = lev * 0.1;
break;
case "door":
max = lev * 0.1;
break;
case "sun":
max = lev * 0.6;
break;
case "bag":
nbags = game.getmaxbags(lev);
break;
default: // should never happen
max = lev * 0.2;
break;
}
max = Math.floor(max);
if (max < 1) max = 1;
return max;
},
calclevparams : function( lev ) {
var i,num;
var min = 0,pointsgoal = false;
@ -1743,14 +1893,13 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
if (!game.isbanned(curlevel, "door")) {
num *= 1.5;
}
min += num;
break;
case "door":
// double the value of a minimum-score parade
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * 3 * 2 * this.levels[lev].goals[i].count;
break;
turnsreq += this.levels[lev].goals[i].count * 1;
break;
case "sun":
min += SLEEPYCATPOINTS*5 * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].gridh;
@ -1798,10 +1947,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// must be an integer
this.levels[lev].maxturns = Math.floor(this.levels[lev].maxturns);
/*
// calc stars to unlock
//extrastars = Math.floor(lev / 5);
//this.levels[lev].starsrequired = (lev-1) + extrastars;
// must use 'lev-1' so that level 1 requires no stars.
// 1.2 * level num
if (lev < 5) {
@ -1809,9 +1956,23 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
} else {
this.levels[lev].starsrequired = Math.floor(1.5 * (lev-1));
}
*/
},
getstarsrequired : function (lev) {
var req;
// calc stars to unlock
// must use 'lev-1' so that level 1 requires no stars.
// 1.2 * level num
if (lev < 5) {
req = Math.floor(1.2 * (lev-1));
} else {
req = Math.floor(1.5 * (lev-1));
}
return req;
},
initlevels : function ( ) {
var mylevel,i,n;
@ -2650,7 +2811,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
},
levellocked : function (lev) {
if (playerdata.totstars < game.levels[lev].starsrequired) return true;
if (playerdata.totstars < game.getstarsrequired(lev)) return true;
return false;
},
@ -4916,6 +5077,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var gridcol = "#000000";
var crosscol = "#bbbbbb";
var textcol = "#dddd00";
var scrollcol = "#dddd00";
var titlecol = "#00aaee";
var scorecol = "#00dd00";
var starcol = "#dddd00";
@ -4950,20 +5112,81 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
gridalpha = wipe.getval(1.0, "up", "down", 1.0);
levnum = 1 + game.levseloff;
// grid
ctx.globalAlpha = gridalpha;
for (y = 0; y < LEVSELGRIDH*GRIDSIZE; y += GRIDSIZE) {
for (x = 0; x < LEVSELGRIDW*GRIDSIZE; x += GRIDSIZE) {
var levy = LEVSEL_Y + y + GRIDSIZE/4;
var randomlev = false;
if (this.levelexists(levnum)) {
var nextsize = GRIDSIZE * 0.75;
// "prev" ?
if (x == 0 && y == 0 && game.levseloff > 0) {
/*
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = gridcol;
gridgrad = this.context.createLinearGradient(x, y, LEVSEL_X+x+GRIDSIZE, LEVSEL_Y+y+GRIDSIZE);
gridgrad.addColorStop(0, "#eeee00");
gridgrad.addColorStop(1, gridblack);
ctx.fillStyle = gridgrad;
ctx.fillRect(LEVSEL_X + x, LEVSEL_Y + y, GRIDSIZE-1, GRIDSIZE-1);
ctx.stroke();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
shadowtext(ctx, "<<", TEXTSIZELEVSCROLL, scrollcol,
LEVSEL_X + x + GRIDSIZE/2, LEVSEL_Y + y + GRIDSIZE/2);
*/
ctx.drawImage(image['prevlev'],
LEVSEL_X + x + GRIDSIZE/2 - nextsize/2, LEVSEL_Y + y + GRIDSIZE/2 - nextsize/2,
nextsize,nextsize);
continue;
} else if (y >= (LEVSELGRIDH*GRIDSIZE - GRIDSIZE) && x >= (LEVSELGRIDW*GRIDSIZE - GRIDSIZE)) {
// "next" ?
/*
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = gridcol;
gridgrad = this.context.createLinearGradient(x, y, LEVSEL_X+x+GRIDSIZE, LEVSEL_Y+y+GRIDSIZE);
gridgrad.addColorStop(0, "#eeee00");
gridgrad.addColorStop(1, gridblack);
ctx.fillStyle = gridgrad;
ctx.fillRect(LEVSEL_X + x, LEVSEL_Y + y, GRIDSIZE-1, GRIDSIZE-1);
ctx.stroke();
*/
ctx.drawImage(image['nextlev'],
LEVSEL_X + x + GRIDSIZE/2 - nextsize/2, LEVSEL_Y + y + GRIDSIZE/2 - nextsize/2,
nextsize,nextsize);
/*
ctx.textAlign = "center";
ctx.textBaseline = "middle";
shadowtext(ctx, ">>", TEXTSIZELEVSCROLL, scrollcol,
LEVSEL_X + x + GRIDSIZE/2, LEVSEL_Y + y + GRIDSIZE/2);
*/
continue;
}
// create it if required.
if (!game.levelexists(levnum)) {
game.genrandomlevel(levnum);
}
randomlev = game.levels[levnum].random;
//if (this.levelexists(levnum)) {
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = gridcol;
gridgrad = this.context.createLinearGradient(x, y, LEVSEL_X+x+GRIDSIZE, LEVSEL_Y+y+GRIDSIZE);
//gridgrad.addColorStop(0, "#eeee00");
//if ((playerdata.levscore[levnum] > 0) && !this.levellocked(levnum)) {
if ( this.levellocked(levnum)) {
gridgrad.addColorStop(0, "#eeeeee");
} else {
@ -4976,13 +5199,6 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
ctx.stroke();
// show level num
ctx.textAlign = "center";
ctx.textBaseline = "middle";
shadowtext(ctx, levnum, TEXTSIZELEVSELECT, textcol,
LEVSEL_X + x + GRIDSIZE/2,levy);
if (this.levellocked(levnum)) {
var lockh = GRIDSIZE / 2.8;
@ -4990,6 +5206,16 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var lockx = LEVSEL_X + x + GRIDSIZE/2 - lockw/2;
var locky = LEVSEL_Y + y + TEXTSIZELEVSELECT*1.5;
// show level num
ctx.textAlign = "center";
ctx.textBaseline = "middle";
shadowtext(ctx, levnum, TEXTSIZELEVSELECT,
//randomlev ? "red" : textcol,
textcol,
LEVSEL_X + x + GRIDSIZE/2,levy);
// locked
ctx.drawImage(image['lock'], lockx, locky, lockw, lockh);
@ -5012,7 +5238,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
ctx.textBaseline = "top";
shadowtext(ctx, this.levels[levnum].starsrequired,
shadowtext(ctx, game.getstarsrequired(levnum),
TEXTSIZELEVSTARS, "#cccccc",
starreqx, starreqy);
@ -5025,12 +5251,15 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// show level num
ctx.textAlign = "center";
ctx.textBaseline = "middle";
shadowtext(ctx, levnum, TEXTSIZELEVSELECT, textcol,
shadowtext(ctx, levnum, TEXTSIZELEVSELECT,
//randomlev ? "red" : textcol,
textcol,
LEVSEL_X + x + GRIDSIZE/2,levy);
// show hiscore
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// get player hiscore
hiscore = playerdata.getlevscore(levnum);
@ -5054,21 +5283,22 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// show hiscore
hiscore = playerdata.getlevscore(levnum);
if (hiscore != undefined) {
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
if (hiscore == 0) {
shadowtext(ctx, "NEW!", TEXTSIZELEVSCORE, "#ee44ee",
LEVSEL_X + x + GRIDSIZE/2,scorey);
} else {
hiscore = addcommas(hiscore) + "pts";
shadowtext(ctx, hiscore, TEXTSIZELEVSCORE, scorecol,
LEVSEL_X + x + GRIDSIZE/2,scorey);
}
if (hiscore == undefined) hiscore = 0;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
if (hiscore == 0) {
shadowtext(ctx, "NEW!", TEXTSIZELEVSCORE, "#ee44ee",
LEVSEL_X + x + GRIDSIZE/2,scorey);
} else {
hiscore = addcommas(hiscore) + "pts";
shadowtext(ctx, hiscore, TEXTSIZELEVSCORE, scorecol,
LEVSEL_X + x + GRIDSIZE/2,scorey);
}
}
} else {
//} else {
// level doesn't exist
/*
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = gridcol;
@ -5081,7 +5311,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// cross it out
drawcross(ctx,LEVSEL_X + x, LEVSEL_Y + y, LEVSEL_X + x + GRIDSIZE-1, BOARDY + y + GRIDSIZE-1, crosscol, 3);
}
*/
//}
// outline square
ctx.beginPath();
@ -5433,7 +5664,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// find where you clicked
if ((realx >= levsel_contx) && (realx <= levsel_contx + levsel_contw) &&
(realy >= levsel_conty) && (realy <= levsel_conty + levsel_conth)) {
//game.setstate("title");
// back to title screen
wipe.start("title", "out", 15);
} else {
var gridx,gridy,levsel;
@ -5443,13 +5674,26 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
//gridx = Math.floor((realx - BOARDX) / GRIDSIZE);
//gridy = Math.floor((realy - BOARDY) / GRIDSIZE);
levsel = (gridy*LEVSELGRIDW) + gridx + 1;
if ((gridx == LEVSELGRIDW-1) && (gridy == LEVSELGRIDH - 1)) {
// "next"
game.levseloff += ((LEVSELGRIDW*LEVSELGRIDH)-1);
} else if (game.levseloff > 0 && gridx == 0 && gridy == 0) {
// "next"
game.levseloff -= ((LEVSELGRIDW*LEVSELGRIDH)-1);
if (game.levseloff < 0) game.levseloff = 0;
if (game.levelexists(levsel) && !game.levellocked(levsel)) {
curlevel = levsel;
} else {
levsel = game.levseloff + (gridy*LEVSELGRIDW) + gridx + 1;
if (game.levseloff > 0) levsel--;
game.initgamevars();
game.helporstartlev();
//if (game.levelexists(levsel) && !game.levellocked(levsel)) {
if (!game.levellocked(levsel)) {
curlevel = levsel;
game.initgamevars();
game.helporstartlev();
}
}
}
} else if (game.state == "help") {
@ -5605,7 +5849,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// get a new cat picture for if we win
if (winimg != undefined) delete winimg;
winimg = new Image();
var n = rnd(NUMWINIMAGES);
//var n = rnd(NUMWINIMAGES);
var n = curlevel % NUMWINIMAGES;
winimg.src = "images/win" + n + ".png";
this.winimgsize = 0.1;
@ -5646,6 +5891,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
'starfull','starempty', 'stargrey', 'curtain','curtainshred', 'curtainfall',
'door', 'sunlight', 'toad', 'whitecat', // special things
'box', 'boxfront', 'boxback',
'nextlev','prevlev',
'brick', // obstacles
'bag', 'bagpop', 'fez', 'pow', 'brickpop', // effects
'tissues', 'shears', 'magiccarpet' ];
@ -5875,12 +6121,41 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
},
}
// Seeded random numbers, from http://stackoverflow.com/questions/424292/seedable-javascript-random-number-generator
function RNG(seed) {
// LCG using GCC's constants
this.m = 0x80000000; // 2**31;
this.a = 1103515245;
this.c = 12345;
this.state = seed ? seed : Math.floor(Math.random() * (this.m-1));
}
RNG.prototype.rndint = function() {
this.state = (this.a * this.state + this.c) % this.m;
return this.state;
}
RNG.prototype.rndfloat = function() {
// returns in range [0,1]
return this.rndint() / (this.m - 1);
}
RNG.prototype.rndrange = function(start, end) {
// returns in range [start, end): including start, excluding end
// can't modulu nextInt because of weak randomness in lower bits
var rangeSize = end - start;
var randomUnder1 = this.rndint() / this.m;
return start + Math.floor(randomUnder1 * rangeSize);
}
RNG.prototype.rndchoice = function(array) {
return array[this.rndrange(0, array.length)];
}
function getimgsize(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return { width: srcWidth*ratio, height: srcHeight*ratio };
}
}
// returns number in range 0 .. num-1
function rnd(num) {
@ -6026,6 +6301,7 @@ function getrandomtype() {
var thinglist,maxroll = 0;
var speciallist = null;
var dodb = false;
var goalthings;
if (curlevel >= game.levels.length) {
thinglist = null;
@ -6060,12 +6336,13 @@ function getrandomtype() {
thinglist.push({ type: 'special', pct: 5 } );
}
if (!game.isbanned(curlevel, 'box')) thinglist.push({ type: 'box', pct: 5 } );
if (!game.isbanned(curlevel, 'goat')) thinglist.push({ type: 'goat', pct: 8 } );
if (!game.isbanned(curlevel, 'llama')) thinglist.push({ type: 'llama', pct: 12 } );
if (!game.isbanned(curlevel, 'goat')) thinglist.push({ type: 'goat', pct: 12 } );
if (!game.isbanned(curlevel, 'llama')) thinglist.push({ type: 'llama', pct: 10 } );
if (!game.isbanned(curlevel, 'food')) thinglist.push({ type: 'food', pct: 40 } );
if (!game.isbanned(curlevel, 'cat')) thinglist.push({ type: 'cat', pct: 45 } );
}
goalthings = [];
// increase the chance of something appearing if
// a. it's a goal
@ -6102,11 +6379,15 @@ function getrandomtype() {
count = countalivethingsoftype(lookforthing);
if (count <= 1) {
console.log("****** no things of type " + lookforthing);
// extra chance!
thinglist[i].pct *= 4;
if (thinglist[i].pct < 30) thinglist[i].pct = 30;
console.log("extra chance of " + thingtype + "(" + lookforthing + ")");
//thinglist[i].pct *= goalbooster;
game.goalbooster += 15;
if (thinglist[i].pct < game.goalbooster) thinglist[i].pct = game.goalbooster;
console.log("extra chance of " + thingtype + "(" + lookforthing + ") - " + game.goalbooster);
dodb = true;
goalthings.push(thingtype);
// if the thing in question is 'special',
// cheat on the random check later to make sure we
@ -6149,6 +6430,11 @@ dodb = true;
}
}
if (goalthings.indexOf(type)) {
console.log("resetting goalbooster");
game.goalbooster = 0;
}
if (type == null || type == undefined) {
console.log("couldn't find type! roll is " + roll);
type = 'cat';
@ -6488,7 +6774,7 @@ function thing(gridx, gridy, type, text, col) {
points = LLAMAPOINTS;
//game.progress("llama", 1);
} else if (this.type == "box") {
points = BOXCATPOINTS;
points = CATBOXPOINTS;
} else if (this.type == "cat") {
if (this.issleepy()) {
points = SLEEPYCATPOINTS;
@ -7569,11 +7855,12 @@ function mainloop() {
}
// mark things as not new
for (i = 0; i < things.length; i += 1) {
if (things[i].gridy >= 0) things[i].isnew = false;
if ((things[i].gridy >= 0) && !things[i].isanimating()) things[i].isnew = false;
}
// suns move down once
for (i = 0; i < things.length; i += 1) {
if (things[i].type == "sunlight" && things[i].gridy >= 0 && !things[i].isnew &&
if (things[i].type == "sunlight" &&
isonscreen(things[i].gridx, things[i].gridy) && !things[i].isnew &&
things[i].state != "swapping" && things[i].counter == 0) {
var thingbelow,willdie = false;
thingbelow = getgridthing(things[i].gridx, things[i].gridy+1);
@ -7614,6 +7901,8 @@ function mainloop() {
function canmatchthree(what) {
if (what.isanimating()) return false; // ignore moving things, though there shouldnt be any anyway
if (!isonscreen(what.gridx, what.gridy)) return false;
switch (what.type) {
case "llama": return true;
}
@ -7632,8 +7921,8 @@ function matchthreefrom(what, locdb) {
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++) {

BIN
images/nextlev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/prevlev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/win12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

BIN
images/win13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

BIN
images/win14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

BIN
images/win15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

BIN
images/win16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

BIN
images/win17.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

BIN
images/win18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

BIN
images/win19.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

BIN
images/win20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

BIN
images/win21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

BIN
images/win22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
images/win23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

BIN
images/win24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

BIN
images/win25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

68
todo
View File

@ -10,53 +10,48 @@ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/
-------------------
*random levels.
*bugfix: cat-in-boat to goat should okay
*when forcing an goal object because we have none, make the chance higher based on how many things we're dropping.
*add more win images
* make win images sequential rather than random.
tweak random goal numbers
sometimes add random bricks
randoms:
add 1-4 bricks
quads:
pick quad
add 1-2 bricks
flip to others
vert flip
pick side
add 1-3 bricks
flip
horz flip
pick top/bottom
add 1-3 bricks
flip
new door fell down on top of new goat!!
(or the other way around ??)
check code for doors falling when off the top of the screen.
check code for adding new objects at top of screen.
*attempt to fix bug with multiple things on top of each other
*check code for doors falling when off the top of the screen.
*check code for adding new objects at top of screen.
change 'thing' to have a constructor!!
then remove dupe hp code
*change layout of levselect screen
*points for catbox in parade!
*make curtain be a kind of 'special'
*Boxes are great!
*cats enter as part of a chomp, to become a catbox
*catboxes auto-ambush any llama which falls nearby
*catboxes are anonymous, so they can join parades of any colour
*parades starting with a catbox can include any colour cats.
*catboxes can even chomp food!
update validmoves check
remaining levels.
22/23/24 - curtains (shred 2, 4, 6)
24/25/26 - boxes
26/27/28 - cat toys
29/30 - ???
goal: x parades of y length!!!
random levels.
---
1-3 goals
Get max goal counts for level
Split up 100% worth of count over the chosen goals.
ie. 60% of 1, 25% of another, 15% of the third
or. 70% of 1, 30% of another
----
move things like "get required stars for level" out of addlevel()
@ -71,11 +66,6 @@ more prizes: ???
arrow/signpost - cat parades bounce off and take out htings in the path
random levels after 100
generate w/h increases (up to a maximum)
generate goals
generate obstacles
use existing maxturns code
---------