*multiplier for path length

*turn limit
*help for path length multiplier
This commit is contained in:
Rob Pearce 2016-08-29 19:24:29 +10:00
parent 117a866820
commit 1560330799
2 changed files with 267 additions and 66 deletions

311
cat.html
View File

@ -54,7 +54,7 @@ var debug = true;
// game vars // game vars
var things = []; var things = [];
var score = 0; var score = 0;
var multiplier = 1; var globmulti = 0;
var overdesc = ""; var overdesc = "";
var curpath = []; var curpath = [];
var pathdir = -1; var pathdir = -1;
@ -63,12 +63,15 @@ var pathvalid = false;
var curlevel = 1; var curlevel = 1;
var lastmx = -1, lastmy = -1; var lastmx = -1, lastmy = -1;
var scorecols = [ "#cccc00", "#00cc00", "#00dddd", "#dd00dd" ];
var mbdown = false; var mbdown = false;
var FLASHSPEED = 0.05; var FLASHSPEED = 0.05;
var TURNSBARSPEEDUP = 0.02;
var TURNSBARSPEEDDOWN = 0.01;
// for background // for background
@ -80,8 +83,8 @@ var ctx = null;
var GOALVERB = { var GOALVERB = {
'food': 'Eat', 'food': 'Eat',
'turns': 'Survive', 'turns': 'Survive',
'points': 'Earn', //'points': 'Earn',
'parades': 'Form', //parades': 'Form',
'llamas': 'Clear', 'llamas': 'Clear',
'cats': 'Clear', 'cats': 'Clear',
'goats': 'Clear', 'goats': 'Clear',
@ -964,6 +967,8 @@ var game = {
frameNo: 0, frameNo: 0,
turnsleft: 0, turnsleft: 0,
turnsbarpct: 0,
screenflash: 0, screenflash: 0,
canvas: null, canvas: null,
@ -1114,6 +1119,7 @@ var game = {
} }
game.turnsleft--; game.turnsleft--;
if (game.turnsleft < 0) game.turnsleft = 0;
game.dirty = true; game.dirty = true;
}, },
@ -1148,7 +1154,7 @@ var game = {
initgamevars : function() { initgamevars : function() {
score = 0; score = 0;
multiplier = 1; globmulti = 0;
this.frameNo = 0; this.frameNo = 0;
}, },
@ -1326,6 +1332,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var i,num; var i,num;
var min = 0,pointsgoal = false; var min = 0,pointsgoal = false;
var turnsreq = 0; var turnsreq = 0;
var forceturnsreq = false;
// calculate minimum points required to win // calculate minimum points required to win
// first pass // first pass
for (i = 0; i < this.levels[lev].goals.length; i++) { for (i = 0; i < this.levels[lev].goals.length; i++) {
@ -1341,7 +1348,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
break; break;
case "cats": // use smaller amount of catpoints case "cats": // use smaller amount of catpoints
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count; min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count;
turnsreq += this.levels[lev].goals[i].count * 2; // assume 1 cat every 2 turns turnsreq += this.levels[lev].goals[i].count / 3;
break; break;
case "goats": case "goats":
min += GOATPOINTS * this.levels[lev].goals[i].count; min += GOATPOINTS * this.levels[lev].goals[i].count;
@ -1381,6 +1388,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
*/ */
case "turns": case "turns":
turnsreq = this.levels[lev].goals[i].count; turnsreq = this.levels[lev].goals[i].count;
forceturnsreq = true;
break; break;
} }
} }
@ -1400,9 +1408,12 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.levels[lev].starpoints[1] = Math.floor(Math.max(min * 2, pointsgoal*1.5)); 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[2] = Math.floor(Math.max(min * 3, pointsgoal*2));
if (turnsreq > this.levels[lev].maxturns) { if ((turnsreq > this.levels[lev].maxturns) || forceturnsreq) {
this.levels[lev].maxturns = turnsreq; this.levels[lev].maxturns = turnsreq;
} }
// must be an integer
this.levels[lev].maxturns = Math.floor(this.levels[lev].maxturns);
}, },
initlevels : function ( ) { initlevels : function ( ) {
@ -1416,8 +1427,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
this.addlevelthings(1, "cat", 50, "food", 50); this.addlevelthings(1, "cat", 50, "food", 50);
this.addlevel(2, true); this.addlevel(2, true);
this.addlevelgoals(2, "cats", 10); this.addlevelgoals(2, "cats", 12);
this.addlevelgoals(2, "parades", 3);
this.addlevelthings(2, "cat", 45, "food", 55); this.addlevelthings(2, "cat", 45, "food", 55);
this.addlevel(3, true); this.addlevel(3, true);
@ -1669,9 +1679,15 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
} else if (game.state == "gameover") { } else if (game.state == "gameover") {
var text;
if (game.turnsleft <= 0) {
text = "Out of moves!";
} else {
text = "No valid moves!";
}
this.context.textAlign = "center"; this.context.textAlign = "center";
this.context.textBaseline = "top"; this.context.textBaseline = "top";
shadowtext(this.context, "No more moves!", 20, "red", SCREENW / 2, 5); shadowtext(this.context, text, 20, "red", SCREENW / 2, 5);
shadowtext(this.context, "Final Score: " + addcommas(score), 16, "white", SCREENW / 2, 35); shadowtext(this.context, "Final Score: " + addcommas(score), 16, "white", SCREENW / 2, 35);
} else if (game.state == "levelcomplete") { } else if (game.state == "levelcomplete") {
this.context.textAlign = "center"; this.context.textAlign = "center";
@ -2035,7 +2051,7 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
var imgsize = THINGSIZE / divamt; var imgsize = THINGSIZE / divamt;
var gridsize = GRIDSIZE / divamt; var gridsize = GRIDSIZE / divamt;
var gradient,x,y,x2,y2,curx,cury; var gradient,x,y,x2,y2,curx,cury;
var row1y,row2y,row3y; var row1y,row2y,row3y,row4y;
var i; var i;
var linex = []; var linex = [];
var liney = []; var liney = [];
@ -2408,7 +2424,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
ctx.textAlign = "left"; ctx.textAlign = "left";
ctx.textBaseline = "bottom"; ctx.textBaseline = "bottom";
shadowtext(ctx, "The game ends when there are no valid moves left.", HELPTEXTSIZE,helpcol, textxspace, cury); shadowtext(ctx, "The game ends when there are no valid moves left,", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
shadowtext(ctx, "or if the turn counter runs out.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
} else if (curlevel == 2) { } else if (curlevel == 2) {
@ -2456,15 +2474,15 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
liney[2] = y + imgsize/2; liney[2] = y + imgsize/2;
x += gridsize; x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize); ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
linex[5] = x + imgsize/2; linex[5] = x + imgsize/2;
liney[5] = y + imgsize/2; liney[5] = y + imgsize/2;
cury = y + HELPTEXTYSPACE; cury = y + HELPTEXTYSPACE;
for (i = 0; i < 4; i++) { for (i = 0; i < 3; i++) {
drawline(ctx, linex[i], liney[i], linex[i+1], liney[i+1], PATHLINECOLGOOD, LINEWIDTH); drawline(ctx, linex[i], liney[i], linex[i+1], liney[i+1], PATHLINECOLGOOD, LINEWIDTH);
} }
drawarrow(ctx, linex[4], liney[4], linex[5], liney[5], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE); drawarrow(ctx, linex[3], liney[3], linex[4], liney[4], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
// arrow to middle // arrow to middle
x = x + gridsize; x = x + gridsize;
@ -2489,6 +2507,135 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE; cury += HELPTEXTYSPACE;
cury = this.drawhelpsubtitle(ctx, "Score Multiplier", cury);
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
shadowtext(ctx, "Longer parades score more points.", HELPTEXTSIZE,helpcol, textxspace, cury);
cury += HELPTEXTYSPACE;
// top line of second parade - 5 cats
x = imgsize;
y = cury;
row1y = y;
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
x += gridsize;
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);
linex[1] = x + imgsize/2;
liney[1] = y + imgsize/2;
x += gridsize;
x = imgsize;
y += gridsize;
row2y = y;
// 2nd line of second parade - 3 cats
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[3] = x + imgsize/2;
liney[3] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[2] = x + imgsize/2;
liney[2] = y + imgsize/2;
x = imgsize;
y += gridsize;
row3y = y;
// 3rd line of second parade - 3 cats
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[4] = x + imgsize/2;
liney[4] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[5] = x + imgsize/2;
liney[5] = y + imgsize/2;
x += gridsize;
x = imgsize;
y += gridsize;
row4y = y;
// 4th line of second parade - 3 cats
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[7] = x + imgsize/2;
liney[7] = y + imgsize/2;
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
x += gridsize;
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
linex[6] = x + imgsize/2;
liney[6] = y + imgsize/2;
cury = y + HELPTEXTYSPACE;
// path lines
for (i = 0; i < 6; i++) {
drawline(ctx, linex[i], liney[i], linex[i+1], liney[i+1], PATHLINECOLGOOD, LINEWIDTH);
}
drawarrow(ctx, linex[6], liney[6], linex[7], liney[7], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
// arrow to middle
x = x + gridsize;
y = row1y + (imgsize);
x2 = midpoint2 - 10;
y2 = y;
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
// explain multipliers
ctx.textAlign = "left";
ctx.textBaseline = "top";
x = midpoint2;
y = y - HELPTEXTYSPACE/2;
shadowtext(ctx, "Cats 1-5 = x1", HELPTEXTSIZE,pointscol, x, y);
y += HELPTEXTYSPACE;
x = midpoint2;
y = row3y + HELPTEXTYSPACE/2;
shadowtext(ctx, "Cats 6-8 = x2", HELPTEXTSIZE,pointscol, x, y);
x = midpoint2;
y = row4y + HELPTEXTYSPACE/2;
shadowtext(ctx, "Cats 9-11 = x3", HELPTEXTSIZE,pointscol, x, y);
x = midpoint2;
y += HELPTEXTYSPACE;
y += HELPTEXTYSPACE;
shadowtext(ctx, "...etc", HELPTEXTSIZE,pointscol, x, y);
cury = y + HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
cury += HELPTEXTYSPACE;
} else if (curlevel == 3) { } else if (curlevel == 3) {
var llamatitle = llamatext[0].toUpperCase() + llamatext.substring(1); var llamatitle = llamatext[0].toUpperCase() + llamatext.substring(1);
cury = this.drawhelpsubtitle(ctx, llamatitle + "s", cury); cury = this.drawhelpsubtitle(ctx, llamatitle + "s", cury);
@ -3213,6 +3360,26 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
}, },
moveturnsleftbar : function() {
var turnspct;
// turnspct = how high the bar should be
// game.turnsbarpct = how high the bar _is_
turnspct = (game.turnsleft / game.levels[curlevel].maxturns);
// move it towards what it should be.
if (game.turnsbarpct > turnspct) {
game.turnsbarpct -= TURNSBARSPEEDDOWN;
if (game.turnsbarpct < turnspct) game.turnsbarpct = turnspct;
game.dirty = true;
} else if (game.turnsbarpct < turnspct) {
game.turnsbarpct += TURNSBARSPEEDUP;
if (game.turnsbarpct > turnspct) game.turnsbarpct = turnspct;
game.dirty = true;
}
},
drawsides : function() { drawsides : function() {
var x,y,w,h,y2,h2; var x,y,w,h,y2,h2;
var turnscol = "#00dddd"; var turnscol = "#00dddd";
@ -3223,7 +3390,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
w = BOARDX-1; w = BOARDX-1;
h = GRIDH * GRIDSIZE; h = GRIDH * GRIDSIZE;
h2 = (game.turnsleft / game.levels[curlevel].maxturns) * (h-2); h2 = game.turnsbarpct * (h-2);
//y2 = y + (h - game.turnsbarh);
y2 = y + (h - h2); y2 = y + (h - h2);
// black background // black background
@ -3234,15 +3403,21 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// turns left bar // turns left bar
if (game.turnsleft > 0) { if (game.turnsleft > 0) {
ctx.fillStyle = "blue"; var gradient;
ctx.beginPath(); ctx.beginPath();
ctx.rect(x+1,y2,w-1,h2);
gradient = ctx.createLinearGradient(0, 0, 0, h2);
gradient.addColorStop(0, "#0000ff");
gradient.addColorStop(1, "#000055");
ctx.fillStyle = gradient;
ctx.fillRect(x+1,y2,w-1,h2);
ctx.stroke(); ctx.stroke();
// turns left text // turns left text
ctx.textAlign = "center"; ctx.textAlign = "center";
ctx.textBaseline = "top"; ctx.textBaseline = "top";
shadowtext(ctx, game.turnsleft, TURNSLEFTTEXTSIZE, turnscol, x + (w/2), y2 + 2); shadowtext(ctx, Math.floor(game.turnsleft), TURNSLEFTTEXTSIZE, turnscol, x + (w/2), y2 + 2);
} }
// border // border
@ -3563,6 +3738,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
// reset turns left // reset turns left
game.turnsleft = game.levels[curlevel].maxturns; game.turnsleft = game.levels[curlevel].maxturns;
// start turns left bar at bottom so it ticks up.
game.turnsbarpct = 0;
wipe.start("", "in", 50); wipe.start("", "in", 50);
} else if (newstate == "levselect") { } else if (newstate == "levselect") {
@ -3730,13 +3907,13 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
game.progress("turns", 1); game.progress("turns", 1);
break; break;
case "parade": case "parade":
multiplier = 1; globmulti = 0;
if (curpath.length >= 2) { // should always be true if (curpath.length >= 2) { // should always be true
var i; var i;
// everything in the path exits via a parade // everything in the path exits via a parade
pathdoor = pathcontainstype("door"); pathdoor = pathcontainstype("door");
if (pathdoor) multiplier++; if (pathdoor) globmulti++;
for (i = 0; i < curpath.length; i++) { for (i = 0; i < curpath.length; i++) {
// ... except doors // ... except doors
@ -3744,9 +3921,9 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
game.progress("doors", 1); game.progress("doors", 1);
console.log("path has doors!"); console.log("path has doors!");
// add animation // add animation
things.push(new thing(curpath[i].gridx, curpath[i].gridy, "text", "x" + multiplier)); things.push(new thing(curpath[i].gridx, curpath[i].gridy, "text", "x" + (globmulti+1)));
} else { } else {
curpath[i].givepoints(); curpath[i].givepoints(i);
curpath[i].startparade(); curpath[i].startparade();
} }
} }
@ -3760,8 +3937,8 @@ console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
curpath.splice(0, 1); curpath.splice(0, 1);
} }
} }
multiplier = 1; globmulti = 0;
game.progress("parades", 1); //game.progress("parades", 1);
game.progress("turns", 1); game.progress("turns", 1);
break; break;
} }
@ -3943,7 +4120,7 @@ function coord(x,y) {
this.y = y; this.y = y;
} }
function thing(gridx, gridy, type, text) { function thing(gridx, gridy, type, text, col) {
this.opacity = 1.0; this.opacity = 1.0;
this.isnew = true; this.isnew = true;
@ -3970,26 +4147,32 @@ function thing(gridx, gridy, type, text) {
} }
this.type = type; this.type = type;
switch (this.type) {
case "cat": if (col == undefined) {
this.color = "#b5dea8"; switch (this.type) {
break; case "cat":
case "food": this.color = "#b5dea8";
this.color = "#d8db03"; break;
break; case "food":
case "llama": this.color = "#d8db03";
this.color = "#cccccc"; break;
break; case "llama":
case "text": this.color = "#cccccc";
if (this.name.indexOf("x") == 0) { break;
this.color = "#00dddd"; case "text":
} else { // default, might ver overridden
this.color = "#00cc00"; if (this.name.indexOf("x") == 0) {
} this.color = "#00dddd";
break; } else {
default: // should never happen this.color = "#00cc00";
this.color = getrandomcolour(); }
break; break;
default: // should never happen
this.color = getrandomcolour();
break;
}
} else {
this.color = col;
} }
if (this.type == "text") { if (this.type == "text") {
@ -4125,12 +4308,18 @@ function thing(gridx, gridy, type, text) {
return false; return false;
} }
this.givepoints = function() { this.givepoints = function(pathpos) {
var points = 0; var points = 0;
var prestars,poststars; var prestars,poststars;
var thismulti = 1;
var colidx = 0;
prestars = game.calcstars(curlevel, score); prestars = game.calcstars(curlevel, score);
if (pathpos == undefined) {
pathpos = 0;
}
if (this.type == "food") { if (this.type == "food") {
points = FOODPOINTS; points = FOODPOINTS;
game.progress("food", 1); game.progress("food", 1);
@ -4149,21 +4338,31 @@ function thing(gridx, gridy, type, text) {
game.progress("goats", 1); game.progress("goats", 1);
} }
points *= multiplier; // multiplier for path position
thismulti = Math.floor((pathpos+1) / 3); // ie. 1-5=x1 6-8=x2 9-11=x3 etc
if (thismulti < 1) thismulti = 1;
// global multiplier (doors etc)
thismulti += globmulti;
points *= thismulti;
if (points > 0) { if (points > 0) {
//console.log("scoring " + points + " points for " + this.name + "(globmulti is " + thismulti + ")" );
score += points; score += points;
game.progress("points", points); //game.progress("points", points);
// add animation // add animation
things.push(new thing(this.gridx, this.gridy, "text", "+" + points)); colidx = thismulti;
if (colidx > (scorecols.length-1)) colidx = scorecols.length-1;
things.push(new thing(this.gridx, this.gridy, "text", "+" + points, scorecols[colidx]));
poststars = game.calcstars(curlevel, score); poststars = game.calcstars(curlevel, score);
if (poststars != prestars) { if (poststars != prestars) {
// regenerate star colors at top, if required // regenerate star colors at top, if required
game.generatestargoalbanner(); game.generatestargoalbanner();
} }
} }
} }
@ -4689,6 +4888,10 @@ function mainloop() {
things[i].move(); things[i].move();
} }
// move "turns left" bar towards its correct location.
game.moveturnsleftbar();
gridalpha = wipe.getval(1.0, "up", "down", 1.0); gridalpha = wipe.getval(1.0, "up", "down", 1.0);
ctx.globalAlpha = gridalpha; ctx.globalAlpha = gridalpha;
if (game.dirty || wipe.isactive()) { if (game.dirty || wipe.isactive()) {
@ -4747,14 +4950,20 @@ function mainloop() {
pathdoor.startshrink(); pathdoor.startshrink();
pathdoor = null; pathdoor = null;
} else if (levelfinished()) { } else if (levelfinished()) {
// important: check for this BEFORE gameover.
// otherwise levels with turn limits won't work.
// record score // record score
if (score > playerdata.levscore[curlevel]) { if (score > playerdata.levscore[curlevel]) {
playerdata.setlevscore(curlevel, score); playerdata.setlevscore(curlevel, score);
} }
game.setstate("levelcomplete"); game.setstate("levelcomplete");
} else if (!anyvalidmoves()) { } else if (!anyvalidmoves()) {
game.setstate("gameover"); game.setstate("gameover");
} else if (game.turnsleft <= 0) {
game.setstate("gameover");
} }
// mark things as not new // mark things as not new
for (i = 0; i < things.length; i += 1) { for (i = 0; i < things.length; i += 1) {

22
todo
View File

@ -10,25 +10,17 @@ https://www.smashingmagazine.com/2012/10/design-your-own-mobile-game/
--- check here for ios --- check here for ios
multiplier for path length *multiplier for path length
3 = nothing *turn limit
6 = x2 from now on *help for path length multiplier
9 = x3 from now on
...etc
doors double entire length help for turn limit
... then adjust point goal calculation code. PLAYTEST:
... adjust point goal calculation code now that we have multiplier.
... adjust # of turns per level
turn limit.
... then get rid of 'form x parades' goal, just have 'clear x cats'
*ticks down on L of board.
gameover if you run out
che k amoint calchlation
... then get rid of 'survive x turns'
replace with "get as many points as you can"
finish lev without min star points = game over
...then add more levels ...then add more levels