4597 lines
114 KiB
JavaScript
4597 lines
114 KiB
JavaScript
<!-- vim: set syntax=javascript : -->
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
<head>
|
|
|
|
<!-- need utf8 for unicode chars -->
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
|
|
|
<!-- Viewport isn't scalable -->
|
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1, user-scalable=0, minimal-au" />
|
|
<!-- <meta name="viewport" content="width=device-width, minimal-ui" /> -->
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
|
|
<!-- for apps on home screen -->
|
|
|
|
<!-- for ios 7 style, multi-resolution icon of 152x152 -->
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-barstyle" content="black-translucent">
|
|
<link rel="apple-touch-icon" href="images/icon-152.png">
|
|
<!-- for Chrome on Android, multi-resolution icon of 196x196 -->
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<link rel="shortcut icon" sizes="196x196" href="images/icon-196.png">
|
|
|
|
<style>
|
|
canvas {
|
|
border:1px solid #d3d3d3;
|
|
background-color: #000000;
|
|
}
|
|
@font-face {
|
|
font-family: "BlueStone";
|
|
src: url("BlueStone.ttf");
|
|
}
|
|
</style>
|
|
</head>
|
|
<body onload="startGame()">
|
|
<script>
|
|
|
|
var FONT = "BlueStone";
|
|
|
|
// game vars
|
|
var things = [];
|
|
var score = 0;
|
|
var multiplier = 1;
|
|
var overdesc = "";
|
|
var curpath = [];
|
|
var pathdir = -1;
|
|
var pathdoor = null;
|
|
var pathvalid = false;
|
|
var curlevel = 1;
|
|
var lastmx = -1, lastmy = -1;
|
|
|
|
|
|
var mbdown = false;
|
|
|
|
|
|
var FLASHSPEED = 0.05;
|
|
|
|
|
|
|
|
// for background
|
|
var catalpha = 1.0;
|
|
|
|
var ctx = null;
|
|
|
|
// goal types
|
|
var GOALVERB = {
|
|
'food': 'Eat',
|
|
'turns': 'Survive',
|
|
'points': 'Earn',
|
|
'parades': 'Form',
|
|
'llamas': 'Clear',
|
|
'cats': 'Clear',
|
|
'goats': 'Clear',
|
|
'doors': 'Enter',
|
|
'sun cycles': 'Wait out',
|
|
};
|
|
|
|
var wipe = {
|
|
to: "",
|
|
dir: "",
|
|
count: 0,
|
|
active: false,
|
|
|
|
isactive : function() {
|
|
if (this.active) {
|
|
return this.dir;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
// howin and howoutout should be 'up' or 'down'
|
|
getval : function(fullamt, howin, howout, def) {
|
|
var num,how;
|
|
if (this.active) {
|
|
if (this.dir == "in") {
|
|
how = howin;
|
|
} else if (this.dir == "out") {
|
|
how = howout;
|
|
}
|
|
} else {
|
|
return def;
|
|
}
|
|
|
|
num = (this.count / this.max) * fullamt;
|
|
if (how == "down") {
|
|
num = fullamt - num;
|
|
}
|
|
return num;
|
|
},
|
|
|
|
start : function(nextstate, dir, howlong) {
|
|
this.to = nextstate;
|
|
this.count = 0;
|
|
this.max = howlong;
|
|
this.dir = dir;
|
|
this.active = true;
|
|
},
|
|
|
|
tick : function() {
|
|
this.count++;
|
|
if (this.count >= this.max) {
|
|
var nextstate = this.to;
|
|
this.active = false;
|
|
this.to = "";
|
|
this.count = 0;
|
|
if (nextstate != "") {
|
|
game.setstate(nextstate);
|
|
}
|
|
}
|
|
},
|
|
};
|
|
|
|
//var FULLSTAR = "\u2605";
|
|
//var EMPTYSTAR = "\u2606";
|
|
|
|
var STARWID_LEVSEL = 16;
|
|
var STARWID_LEVSEL_LOCKED = 16;
|
|
var STARWID_LEVSEL_TOP = 24;
|
|
var STARWID_ENDLEV = 32;
|
|
|
|
var DEF_GRIDSIZE = 80;
|
|
var DEF_THINGSIZE = 64;
|
|
var DEF_GRIDW = 5;
|
|
var DEF_GRIDH = 5;
|
|
var GRIDSIZE = null;
|
|
var THINGSIZE = null;
|
|
var GRIDW = null;
|
|
var GRIDH = null;
|
|
|
|
var MAXDIRS = 4;
|
|
var DIRXMOD = [ 0, 1, 0, -1 ];
|
|
var DIRYMOD = [ -1, 0, 1, 0 ];
|
|
|
|
var MAXWINIMAGES = 8;
|
|
var WINIMGZOOMSPEED = 0.1;
|
|
|
|
var SCREENW = 480;
|
|
var SCREENH = 640;
|
|
|
|
var GRAVITY = 0.5;
|
|
|
|
|
|
var TEXTSIZE = 16; // in points
|
|
var TEXTSIZEMULTIPLIER = 28; // in points
|
|
var TEXTSPEED = 0.5;
|
|
var TEXTFADESPEED = 0.05;
|
|
var TEXTTIME = 35;
|
|
var TEXTSIZEGOALGET = 38; // in points
|
|
|
|
var LEVELTEXTSIZE = 12;
|
|
var SCORETEXTSIZE = 14;
|
|
var STARPOINTTEXTSIZE = 10;
|
|
|
|
var TITLESIZELEVSELECT = 18; // in points
|
|
var TEXTSIZELEVSELECT = 20; // in points
|
|
var TEXTSIZETOTSTARS = 16; // in points
|
|
var TEXTSIZELEVSCORE = 8; // in points
|
|
var TEXTSIZELEVSTARS = 12; // in points
|
|
|
|
var HELPLINEWIDTH=4;
|
|
var HELPARROWSIZE=15;
|
|
var HELPTITLESIZE = 18;
|
|
var HELPSUBTITLESIZE = 14;
|
|
//var HELPTEXTSIZE = 12;
|
|
var HELPTEXTSIZE = 9;
|
|
|
|
var GOALTEXTSIZE = 16;
|
|
|
|
var HELPTEXTYSPACE = HELPTEXTSIZE * 1.8;
|
|
|
|
var TITLETEXTSIZE = 36;
|
|
var TITLECREDITTEXTSIZE = 16;
|
|
var TITLESTARTTEXTSIZE = 26;
|
|
|
|
var BACKTOTITLESIZE = 20; // game over button
|
|
var TAPBUTTONSIZE = 26; // game over button
|
|
var TAPBUTTONSIZEC = 20; // levcomplete button
|
|
var TAPBUTTONSIZESTAR = 26; // levcomplete button
|
|
|
|
var PARADESPEED=12;
|
|
|
|
var EXPLODETICKS=20;
|
|
var EXPLODEGAIN= (DEF_THINGSIZE*2) / EXPLODETICKS;
|
|
var EXPLODEFADESPEED = 1.0 / EXPLODETICKS;
|
|
|
|
var SHRINKTICKS=20;
|
|
var SHRINKLOSE= (DEF_THINGSIZE / SHRINKTICKS);
|
|
|
|
var LINEWIDTH=2;
|
|
var CROSSWIDTH=2;
|
|
|
|
var BOTTOMBORDERWIDTH=5;
|
|
|
|
var LEVSELGRIDW = 5;
|
|
var LEVSELGRIDH = 6;
|
|
|
|
var PATHARROWSIZE = 10;
|
|
var PATHLINECOLGOOD = "#00ee00";
|
|
var PATHLINECOLBAD = "#ee0000";
|
|
|
|
|
|
var PARADELENGTH = 3;
|
|
|
|
var LEVSEL_X = Math.floor((SCREENW - (DEF_GRIDW * DEF_GRIDSIZE)) / 2);
|
|
var LEVSEL_Y = 64;
|
|
|
|
var DEF_BOARDX = Math.floor((SCREENW - (DEF_GRIDW * DEF_GRIDSIZE)) /2 );
|
|
var BOARDX = DEF_BOARDX;
|
|
var BOARDY = 64;
|
|
|
|
// 'tap to continue' button
|
|
var tapx,tapy,tapw,taph;
|
|
|
|
// back to title screen buton
|
|
var levsel_contx = BOARDX;
|
|
var levsel_conty = BOARDY + (DEF_GRIDSIZE*DEF_GRIDH) + DEF_GRIDSIZE + DEF_GRIDSIZE/4;
|
|
var levsel_contw = SCREENW - (BOARDX*2);
|
|
var levsel_conth = (DEF_GRIDSIZE/2);
|
|
|
|
var FOODPOINTS = 10;
|
|
var LLAMAPOINTS = 100;
|
|
var GOATPOINTS = 50;
|
|
var CATPOINTS = 20;
|
|
var SLEEPYCATPOINTS = 40;
|
|
|
|
var overdesc = "";
|
|
|
|
var llamatext = "llama";
|
|
|
|
var image = new Array();
|
|
var winimg = null;
|
|
|
|
function loadimage(name, filename) {
|
|
image[name] = new Image();
|
|
image[name].src = filename;
|
|
}
|
|
|
|
function getgridthing(gridx, gridy) {
|
|
var i;
|
|
if (things == undefined) return null;
|
|
|
|
// only include non-animating things
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((things[i].gridx == gridx) && (things[i].gridy == gridy)) {
|
|
if (!things[i].isanimating()) {
|
|
return things[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getthingxy(x, y) {
|
|
var i,gridx,gridy;
|
|
var thing;
|
|
// use thing coords
|
|
/*
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((x >= things[i].x) && (x <= things[i].x + THINGSIZE-1) &&
|
|
(y >= things[i].y) && (y <= things[i].y + THINGSIZE-1)) {
|
|
return things[i];
|
|
}
|
|
}
|
|
*/
|
|
// use grid coords
|
|
gridx = Math.floor(x / GRIDSIZE);
|
|
gridy = Math.floor(y / GRIDSIZE);
|
|
|
|
return getgridthing(gridx, gridy);
|
|
}
|
|
|
|
function clearpath() {
|
|
curpath = [];
|
|
pathdir = -1;
|
|
pathvalid = false;
|
|
}
|
|
|
|
function pathcomplete() {
|
|
// get path type
|
|
switch(getpathtype()) {
|
|
case "chomp":
|
|
if ((curpath.length >= 2) &&
|
|
(curpath[0].type == "cat") &&
|
|
!curpath[0].issleepy()) {
|
|
var i;
|
|
var ok = true;
|
|
// everything else is food?
|
|
for (i = 1; i < curpath.length; i++) {
|
|
if (curpath[i].type != "food") {
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
if (ok) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
case "parade":
|
|
// long enough?
|
|
if (curpath.length >= PARADELENGTH) {
|
|
var lcount = 0,gcount = 0;
|
|
var i;
|
|
// includes <= 1 llama?
|
|
for (i = 1; i < curpath.length; i++) {
|
|
if (curpath[i].type == "llama") {
|
|
lcount++;
|
|
} else if (curpath[i].type == "goat") {
|
|
gcount++;
|
|
}
|
|
}
|
|
if ((lcount <= 1) || (gcount)) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function backspacepath() {
|
|
// remove last thing in path
|
|
curpath.splice(curpath.length-1, 1);
|
|
|
|
validatepath();
|
|
|
|
dumppath("Reduced path to: ",curpath);
|
|
}
|
|
|
|
function addtopath(what) {
|
|
console.log("addpath() " + what.name);
|
|
|
|
//dumppath("addpath pre: ", curpath);
|
|
|
|
curpath.push(what);
|
|
|
|
validatepath();
|
|
|
|
/*
|
|
if (curpath.length == 1) {
|
|
console.log("Starting path with " + what.name);
|
|
} else {
|
|
dumppath("Cur path is: ",curpath);
|
|
}
|
|
*/
|
|
}
|
|
|
|
function validatepath() {
|
|
if (pathcomplete()) {
|
|
pathvalid = true;
|
|
} else {
|
|
pathvalid = false;
|
|
}
|
|
|
|
if (curpath.length == 2) {
|
|
pathdir = getdir(curpath[0], curpath[1]);
|
|
}
|
|
}
|
|
|
|
function pathcontains(what) {
|
|
var i;
|
|
if (curpath == undefined) return false;
|
|
|
|
for (i = 0; i < curpath.length; i += 1) {
|
|
if (curpath[i] == what) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// return sfirst thing of matching type
|
|
function pathcontainstype(type) {
|
|
var i;
|
|
if (curpath == undefined) return false;
|
|
|
|
for (i = 0; i < curpath.length; i += 1) {
|
|
if (curpath[i].type == type) {
|
|
return curpath[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function isvalidpath(mypath) {
|
|
var valid = true;
|
|
var firstcat = false;
|
|
var fcount = 0;
|
|
var lcount = 0;
|
|
var gcount = 0;
|
|
var count = 0;
|
|
var i;
|
|
|
|
for (i = 0; i < mypath.length - 1; i++) {
|
|
var thisone,nextone;
|
|
thisone = mypath[i];
|
|
/*
|
|
if (i == mypath.length - 1) { // last one
|
|
nextone = null;
|
|
} else {
|
|
nextone = mypath[i+1];
|
|
}
|
|
*/
|
|
nextone = mypath[i+1];
|
|
|
|
if (thisone.type == "food") {
|
|
fcount++;
|
|
}
|
|
if (thisone.type == "llama") {
|
|
lcount++;
|
|
}
|
|
if (thisone.type == "goat") {
|
|
gcount++;
|
|
}
|
|
count++;
|
|
|
|
if ((thisone.type == "cat") && (nextone.type == "cat")) {
|
|
// no parades on level 1
|
|
if (curlevel == 1) {
|
|
return false;
|
|
}
|
|
// ...but otherwise lines of cats are ok
|
|
} else if ((thisone.type == "goat") && (nextone.type == "cat" || nextone.type == "llama" || nextone.type == "goat")) {
|
|
// goat can go to llama or cat
|
|
// ok
|
|
} else if ((nextone.type == "door") && (count >= PARADELENGTH) && (fcount == 0) && (count >= 3) &&
|
|
(thisone.type == "goat" || thisone.type == "cat" || thisone.type == "llama")) {
|
|
// completed parades can extend into doors
|
|
} else if ((thisone.type == "cat") && nextone.type == "llama") {
|
|
// no parades on level 1
|
|
if (curlevel == 1) {
|
|
return false;
|
|
}
|
|
// cat -> llama is only okay if:
|
|
// 1. there is no food in the path
|
|
if (fcount >= 1) {
|
|
return false;
|
|
}
|
|
// and either:
|
|
// 2a. there are no other llamas in the path
|
|
if (lcount >= 1) {
|
|
// or
|
|
// 2b. there is a goat in the path
|
|
if (!gcount) {
|
|
return false;
|
|
}
|
|
}
|
|
} else if ((thisone.type == "cat") && nextone.type == "goat") {
|
|
// cat -> goat is okay
|
|
} else if ((thisone.type == "llama") && (nextone.type == "cat" || nextone.type == "goat")) {
|
|
// no parades on level 1
|
|
if (curlevel == 1) {
|
|
return false;
|
|
}
|
|
// ...but otherwise llama -> goat/cat is okay
|
|
|
|
} else if ((thisone.type == "llama") && (nextone.type == "llama")) {
|
|
// llama -> llama okay if we have a goat in the path
|
|
if (!gcount) {
|
|
return false;
|
|
}
|
|
} else if ((i == 0) && (thisone.type == "cat") && (nextone.type == "food")) {
|
|
// first cat -> food is ok
|
|
firstcat = true;
|
|
} else if ((i != 0) && firstcat && (thisone.type == "food")) {
|
|
// not the first one, first one was a cat, this one is food
|
|
} else {
|
|
// not ok
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
// would adding 'overthing' to our existing path result in a valid path?
|
|
function canextendpath(overthing) {
|
|
var pathtype;
|
|
|
|
if (!overthing) return false;
|
|
|
|
pathtype = getpathtype();
|
|
|
|
if ( isadjacent(overthing, curpath[curpath.length-1]) && // adjacent to last thing in path?
|
|
!pathcontains(overthing) && // path doesn't already contain this?
|
|
(pathtype == "parade" || isinpathdir(overthing)) // path in a straight line
|
|
) {
|
|
// create a fake new path containing this.
|
|
var fakepath = curpath.slice();
|
|
|
|
fakepath.push(overthing);
|
|
if (isvalidpath(fakepath)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function isadjacent(thing1, thing2) {
|
|
// is thing1 adjacent to thing2?
|
|
var newgridx,newgridy;
|
|
var i;
|
|
|
|
if (thing1 == thing2) return false;
|
|
|
|
for (i = 0; i < MAXDIRS; i++) {
|
|
newgridx = thing1.gridx + DIRXMOD[i];
|
|
newgridy = thing1.gridy + DIRYMOD[i];
|
|
if ((thing2.gridx == newgridx) && (thing2.gridy == newgridy)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function isinpathdir(what) {
|
|
var thisdir;
|
|
if (curpath.length <= 1) {
|
|
return true;
|
|
}
|
|
|
|
// get dir from last cell to what
|
|
thisdir = getdir(curpath[curpath.length - 1], what);
|
|
if ((thisdir != -1) && (thisdir == pathdir)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getdir(thing1, thing2) {
|
|
var i;
|
|
for (i = 0; i < MAXDIRS; i++) {
|
|
var newgx = thing1.gridx + DIRXMOD[i];
|
|
var newgy = thing1.gridy + DIRYMOD[i];
|
|
|
|
if ((thing2.gridx == newgx) && (thing2.gridy == newgy)) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function startGame() {
|
|
|
|
loadimage('cat', 'images/cat.png');
|
|
loadimage('catfull', 'images/catfull.png');
|
|
loadimage('catscared', 'images/catscared.png');
|
|
loadimage('llama', 'images/alpaca.png');
|
|
loadimage('cheese', 'images/cheese.png');
|
|
loadimage('title', 'images/title.png');
|
|
|
|
loadimage('goat', 'images/goat.png');
|
|
loadimage('door', 'images/door.png');
|
|
loadimage('sunlight', 'images/sunlight.png');
|
|
|
|
loadimage('lock', 'images/lock.png');
|
|
|
|
loadimage('catwalkl', 'images/catwalkl.png');
|
|
loadimage('catwalkr', 'images/catwalkr.png');
|
|
|
|
loadimage('starfull', 'images/starfull.png');
|
|
loadimage('starempty', 'images/starempty.png');
|
|
|
|
|
|
game.init();
|
|
game.initlevels();
|
|
|
|
playerdata.load();
|
|
|
|
//window.addEventListener('load', game.init, false);
|
|
window.addEventListener('resize', game.resize, false);
|
|
|
|
mainloop();
|
|
}
|
|
|
|
// valid types:
|
|
// none
|
|
// chomp
|
|
// parade
|
|
function getpathtype() {
|
|
if (curpath.length <= 1) return "none"
|
|
|
|
if (curpath[0].type == "cat") {
|
|
if (curpath[1].type == "food") {
|
|
return "chomp";
|
|
} else if ((curpath[1].type == "cat") || (curpath[1].type == "llama") || (curpath[1].type == "goat")) {
|
|
return "parade";
|
|
}
|
|
}
|
|
return "none";
|
|
}
|
|
|
|
function dumppath(prefix,arr) {
|
|
var str;
|
|
var i;
|
|
str = "";
|
|
for (i = 0; i < arr.length; i++) {
|
|
str = str + " " + arr[i].name;
|
|
}
|
|
console.log(prefix + str);
|
|
}
|
|
|
|
function thingsfalling() {
|
|
for (i = 0; i < things.length; i += 1) {
|
|
/*
|
|
switch (things[i].state) {
|
|
case "parade": // ok
|
|
case "chomp": // ok
|
|
case "stop": //ok
|
|
break;
|
|
default: // anything else
|
|
return true;
|
|
}
|
|
*/
|
|
if (things[i].state == "fall") {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function thingsmoving() {
|
|
var i;
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((things[i].state == "parade") || (things[i].state == "shrink")) {
|
|
return "parade";
|
|
}
|
|
}
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].state == "explode") {
|
|
return "chomp";
|
|
}
|
|
}
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].state != "stop") {
|
|
return "other";
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function canstartpath(what) {
|
|
if (what.type != "cat") {
|
|
// only cats can start paths
|
|
console.log("not a cat");
|
|
return false;
|
|
}
|
|
|
|
if (isadjacenttotype(what, "llama")) {
|
|
// cats adjacent to llamas are frozen
|
|
console.log("next to a llama");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function clearthings() {
|
|
while (things.length > 0) {
|
|
things.pop();
|
|
}
|
|
things = [];
|
|
}
|
|
|
|
|
|
function getmousexy(event) {
|
|
var e,scale;
|
|
var x,y;
|
|
var adjustx, adjusty;
|
|
var xoff=0,yoff=0;
|
|
var element = game.canvas;
|
|
|
|
scale = game.curw / SCREENW;
|
|
|
|
//var rect = game.canvas.getBoundingClientRect();
|
|
|
|
|
|
if (element.offsetParent !== undefined) {
|
|
do {
|
|
xoff += element.offsetLeft;
|
|
yoff += element.offsetTop;
|
|
} while ((element = element.offsetParent));
|
|
}
|
|
|
|
// Add padding and border style widths to offset
|
|
// Also add the <html> offsets in case there's a position:fixed bar
|
|
|
|
var _stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(game.canvas, null)['paddingLeft'], 10) || 0;
|
|
var _stylePaddingTop = parseInt(document.defaultView.getComputedStyle(game.canvas, null)['paddingTop'], 10) || 0;
|
|
var _styleBorderLeft = parseInt(document.defaultView.getComputedStyle(game.canvas, null)['borderLeftWidth'], 10) || 0;
|
|
var _styleBorderTop = parseInt(document.defaultView.getComputedStyle(game.canvas, null)['borderTopWidth'], 10) || 0;
|
|
var html = document.body.parentNode;
|
|
var _htmlTop = html.offsetTop;
|
|
var _htmlLeft = html.offsetLeft;
|
|
|
|
|
|
xoff += _stylePaddingLeft + _styleBorderLeft + _htmlLeft;
|
|
yoff += _stylePaddingTop + _styleBorderTop + _htmlTop;
|
|
|
|
|
|
|
|
if (event.type == "touchup") {
|
|
//x = (event.changedTouches[0].pageX - xoff) / scale;
|
|
//y = (event.changedTouches[0].pageY - yoff) / scale;
|
|
//adjustx = (event.changedTouches[0].pageX - xoff - BOARDX) / scale;
|
|
//adjusty = (event.changedTouches[0].pageY - yoff -BOARDY) / scale;
|
|
x = (event.touches[0].clientX - xoff) / scale;
|
|
y = (event.touches[0].clientY - yoff) / scale;
|
|
//adjustx = (event.changedTouches[0].clientX - xoff - BOARDX) / scale;
|
|
//adjusty = (event.changedTouches[0].clientY - yoff -BOARDY) / scale;
|
|
} else if (event.touches != undefined) {
|
|
x = (event.touches[0].clientX - xoff) / scale;
|
|
y = (event.touches[0].clientY - yoff) / scale;
|
|
//adjustx = (event.touches[0].clientX - xoff - BOARDX) / scale;
|
|
//adjusty = (event.touches[0].clientY - yoff - BOARDY) / scale;
|
|
} else {
|
|
x = (event.pageX - xoff) / scale;
|
|
y = (event.pageY - yoff) / scale;
|
|
//adjustx = (event.pageX - xoff - BOARDX) / scale;
|
|
//adjusty = (event.pageY - yoff - BOARDY) / scale;
|
|
}
|
|
|
|
if (game.state == "levselect") {
|
|
adjustx = x - LEVSEL_X;
|
|
adjusty = y - LEVSEL_Y;
|
|
} else {
|
|
adjustx = x - BOARDX;
|
|
adjusty = y - BOARDY;
|
|
}
|
|
|
|
return [ adjustx, adjusty, x, y ];
|
|
}
|
|
|
|
function isadjacenttotype(what, wanttype, exceptionthing) {
|
|
var newgridx,newgridy;
|
|
var i;
|
|
|
|
for (i = 0; i < MAXDIRS; i++) {
|
|
newgridx = what.gridx + DIRXMOD[i];
|
|
newgridy = what.gridy + DIRYMOD[i];
|
|
|
|
if (isonscreen(newgridx,newgridy)) {
|
|
adjthing = getgridthing(newgridx, newgridy);
|
|
if ((adjthing != undefined) && (adjthing.type == wanttype) && (adjthing != exceptionthing)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function drawline(ctx,x1,y1,x2,y2,col,width) {
|
|
ctx.strokeStyle = col;
|
|
ctx.lineWidth = width;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x1, y1);
|
|
ctx.lineTo(x2, y2);
|
|
ctx.stroke();
|
|
}
|
|
|
|
function addcommas(num) {
|
|
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
}
|
|
|
|
function hashelp(lev) {
|
|
// past last level!
|
|
if (lev >= game.levels.length) return false;
|
|
|
|
return game.levels[lev].hashelp;
|
|
}
|
|
|
|
function drawtick(ctx, x1, y1, x2, y2, col,wid) {
|
|
var w,h;
|
|
w = x2 - x1;
|
|
h = y2 - y1;
|
|
|
|
var tickleftx = x1 + w/4;
|
|
var ticklefty = y1 + h/2;
|
|
var tickbasex = x1 + w/2;
|
|
var tickbasey = y1+h-h/8;
|
|
var tickrightx = x1 + w - w/5;
|
|
var tickrighty = y1 + h/8;
|
|
drawline(ctx, tickleftx,ticklefty, tickbasex, tickbasey, col, wid);
|
|
drawline(ctx, tickbasex, tickbasey, tickrightx, tickrighty, col, wid);
|
|
}
|
|
|
|
function drawcross(ctx, x, y, x2, y2, col, width) {
|
|
// cross out
|
|
ctx.fillStyle = col
|
|
ctx.lineWidth = width;
|
|
ctx.strokeStyle = col;
|
|
// NW -> SE
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
ctx.lineTo(x2, y2);
|
|
ctx.stroke();
|
|
|
|
// SW -> NE
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y2);
|
|
ctx.lineTo(x2, y);
|
|
ctx.stroke();
|
|
}
|
|
|
|
function drawarrow(ctx,x1,y1,x2,y2,col,width, arrowsize) {
|
|
drawline(ctx, x1, y1, x2, y2, col, width);
|
|
drawarrowhead(ctx, x1, y1, x2, y2, col, arrowsize);
|
|
}
|
|
|
|
function drawarrowhead(ctx, x1, y1, x2, y2, col, size) {
|
|
var startrads,endrads;
|
|
var size2;
|
|
size2 = size * 1.5;
|
|
|
|
startrads = Math.atan((y2 - y1) / (x2 - x1));
|
|
if (x2 >= x1) {
|
|
startrads += -90*Math.PI/180;
|
|
} else {
|
|
startrads += 90*Math.PI/180;
|
|
}
|
|
|
|
endrads = Math.atan((y2 - y1) / (x2 - x1));
|
|
if (x2 >= x1) {
|
|
endrads += 90 * Math.PI / 180;
|
|
} else {
|
|
endrads += -90 * Math.PI / 180;
|
|
}
|
|
|
|
ctx.strokeStyle = col;
|
|
ctx.fillStyle = col;
|
|
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.translate(x2,y2);
|
|
ctx.rotate(endrads);
|
|
ctx.moveTo(0,0);
|
|
ctx.lineTo(size,size2);
|
|
ctx.lineTo(-size,size2);
|
|
ctx.closePath();
|
|
ctx.restore();
|
|
ctx.fill();
|
|
}
|
|
|
|
function countthingsoftype(type) {
|
|
var i,count=0;
|
|
for (i = 0; i < things.length; i++) {
|
|
if (things[i].type == type) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
var playerdata = {
|
|
levscore: [],
|
|
|
|
saveall : function() {
|
|
if (game.cheat) return;
|
|
this.savetotstars();
|
|
for (i = 0; i < this.levscore.length; i++) {
|
|
savelevscore(i);
|
|
}
|
|
},
|
|
|
|
savetotstars : function() {
|
|
// save max level
|
|
if (game.cheat) return;
|
|
localStorage.setItem('totstars',this.totstars);
|
|
},
|
|
|
|
savelevscore : function(lev) {
|
|
if (game.cheat) return;
|
|
localStorage.setItem("levscore" + lev, this.levscore[lev]);
|
|
},
|
|
|
|
load : function() {
|
|
var num,i;
|
|
// local star count
|
|
num = localStorage.getItem('totstars');
|
|
if (num != undefined) {
|
|
this.totstars = num;
|
|
console.log("playerdata.load() - totstars is " + this.totstars);
|
|
}
|
|
|
|
// load level hiscores
|
|
for (i = 0; i < game.levels.length; i++) {
|
|
num = localStorage.getItem("levscore" + i);
|
|
if (num == undefined) {
|
|
this.levscore[i] = 0;
|
|
} else {
|
|
this.levscore[i] = num;
|
|
console.log("playerdata.load() - lev " + i + " score is " + num);
|
|
}
|
|
}
|
|
|
|
// calculate player stars based on scores
|
|
this.settotstars(game.countplayerstars());
|
|
|
|
},
|
|
|
|
getlevscore : function (lev) {
|
|
if (this.levscore[lev] == undefined) {
|
|
return null;
|
|
}
|
|
return this.levscore[lev];
|
|
},
|
|
|
|
clearall : function() {
|
|
localStorage.removeItem("maxlevel"); // old one
|
|
localStorage.removeItem("totstars");
|
|
for (i = 0; i < game.levels.length; i++) {
|
|
localStorage.removeItem("levscore" + i);
|
|
}
|
|
console.log("cleared local storage.");
|
|
},
|
|
|
|
settotstars : function(num) {
|
|
console.log("playerdata() - setting total stars to " + num);
|
|
this.totstars = num;
|
|
this.savetotstars();
|
|
},
|
|
|
|
setlevscore : function(lev, num) {
|
|
this.levscore[lev] = num;
|
|
this.savelevscore(lev);
|
|
},
|
|
};
|
|
|
|
|
|
var game = {
|
|
ratio: null,
|
|
curw: null,
|
|
curh: null,
|
|
levels: null,
|
|
state: "title",
|
|
cheat: 0,
|
|
winimgsize: 0,
|
|
frameNo: 0,
|
|
|
|
screenflash: 0,
|
|
|
|
canvas: null,
|
|
|
|
addfirework : function() {
|
|
this.screenflash = 1.0;
|
|
},
|
|
|
|
init : function() {
|
|
|
|
this.canvas = document.createElement("canvas");
|
|
|
|
this.ratio = SCREENW / SCREENH;
|
|
this.curw = SCREENW;
|
|
this.curh = SCREENH;
|
|
|
|
this.canvas.width = SCREENW;
|
|
this.canvas.height = SCREENH;
|
|
|
|
this.context = this.canvas.getContext("2d");
|
|
|
|
ctx = this.context;
|
|
|
|
// find ipad/android/iphone so we can hide the address bar
|
|
this.ua = navigator.userAgent.toLowerCase();
|
|
this.android = this.ua.indexOf('android') > -1 ? true : false;
|
|
this.ios = ( this.ua.indexOf('iphone') > -1 || this.ua.indexOf('ipad') > -1 ) ? true : false;
|
|
|
|
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
|
|
|
|
// try to go full screen?
|
|
var body = document.documentElement;
|
|
if (body.requestFullscreen) {
|
|
body.requestFullscreen();
|
|
} else if (body.webkitrequestFullscreen) {
|
|
body.webkitrequestFullscreen();
|
|
} else if (body.mozrequestFullscreen) {
|
|
body.mozrequestFullscreen();
|
|
} else if (body.msrequestFullscreen) {
|
|
body.msrequestFullscreen();
|
|
}
|
|
|
|
this.resize();
|
|
|
|
//if (game.ios) {
|
|
// this.interval = setInterval(mainloop, 20);
|
|
//} else {
|
|
window.requestAnimFrame = (function(){
|
|
return window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
window.oRequestAnimationFrame ||
|
|
window.msRequestAnimationFrame ||
|
|
function( callback ){
|
|
window.setTimeout(mainloop, 1000 / 60);
|
|
};
|
|
})();
|
|
//}
|
|
|
|
this.canvas.addEventListener('mousedown', this.handlemousedown, false);
|
|
this.canvas.addEventListener('mouseup', this.handlemouseup, false);
|
|
this.canvas.addEventListener('mouseout', this.handlemouseup, false);
|
|
this.canvas.addEventListener('mousemove', this.handlemousemove, false);
|
|
|
|
this.canvas.addEventListener('touchstart', this.handlemousedown, false);
|
|
this.canvas.addEventListener('touchend', this.handlemouseup, false);
|
|
this.canvas.addEventListener('touchcancel', this.handlemouseup, false);
|
|
this.canvas.addEventListener('touchleave', this.handlemouseup, false);
|
|
this.canvas.addEventListener('touchmove', this.handlemousemove, false);
|
|
|
|
window.addEventListener('keypress', this.handlekeypress, false);
|
|
|
|
this.setstate("title");
|
|
},
|
|
|
|
isbanned : function(lev, what) {
|
|
var i;
|
|
|
|
// no list of allowed things means everything is allowed.
|
|
if (this.levels[lev].allowedthings == undefined) {
|
|
return false;
|
|
}
|
|
|
|
for (i = 0 ; i < this.levels[lev].allowedthings.length; i++) {
|
|
if (this.levels[lev].allowedthings.indexOf(what) != -1) {
|
|
// ok
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
turneffects : function() {
|
|
var i;
|
|
for (i = 0; i < things.length; i += 1) {
|
|
// suns can move again
|
|
if (things[i].type == "sunlight" && things[i].counter == 1) {
|
|
things[i].counter = 0;
|
|
}
|
|
}
|
|
},
|
|
|
|
resize : function() {
|
|
game.curh = window.innerHeight;
|
|
game.curw = game.curh * game.ratio;
|
|
|
|
// hide address bar on phones
|
|
if (game.android || game.ios) {
|
|
document.body.style.height = (window.innerHeight + 50) + 'px';
|
|
}
|
|
|
|
// scale canvas
|
|
////this.canvas.style.width = this.curw + 'px';
|
|
//this.canvas.style.height = this.curh + 'px';
|
|
|
|
// this.canvas.style.width = this.curw + 'px';
|
|
// this.canvas.style.height = this.curh + 'px';
|
|
console.log("game.canvas = " + game.canvas);
|
|
game.canvas.style.width = game.curw + 'px';
|
|
game.canvas.style.height = game.curh + 'px';
|
|
|
|
window.setTimeout(function() {
|
|
window.scrollTo(0, 1);
|
|
}, 1);
|
|
},
|
|
|
|
|
|
initgamevars : function() {
|
|
score = 0;
|
|
multiplier = 1;
|
|
this.frameNo = 0;
|
|
},
|
|
|
|
initlevelvars : function() {
|
|
// kill any existing objects
|
|
clearthings();
|
|
|
|
overdesc = "";
|
|
clearpath();
|
|
|
|
// set grid size
|
|
if (game.levels[curlevel].gridsize == undefined) {
|
|
GRIDSIZE = DEF_GRIDSIZE;
|
|
THINGSIZE = DEF_THINGSIZE;
|
|
GRIDW = DEF_GRIDW;
|
|
GRIDH = DEF_GRIDH;
|
|
BOARDX = DEF_BOARDX;
|
|
} else {
|
|
GRIDSIZE = game.levels[curlevel].gridsize;
|
|
THINGSIZE = game.levels[curlevel].thingsize;
|
|
GRIDW = game.levels[curlevel].gridw;
|
|
GRIDH = game.levels[curlevel].gridh;
|
|
BOARDX = game.levels[curlevel].boardx;
|
|
}
|
|
},
|
|
|
|
addlevel : function (lev, hashelp) {
|
|
var mylevel;
|
|
mylevel = new Object();
|
|
mylevel.hashelp = hashelp;
|
|
mylevel.goals = new Array();
|
|
mylevel.thinglist = new Array();
|
|
mylevel.forcelist = new Array();
|
|
mylevel.allowedthings = new Array();
|
|
|
|
if (lev == 1) {
|
|
mylevel.gridsize = DEF_GRIDSIZE;
|
|
mylevel.thingsize = DEF_THINGSIZE;
|
|
mylevel.gridw = DEF_GRIDW;
|
|
mylevel.gridh = DEF_GRIDH;
|
|
mylevel.boardx = (SCREENW - (DEF_GRIDW * DEF_GRIDSIZE))/2;
|
|
} 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;
|
|
}
|
|
|
|
this.levels[lev] = mylevel;
|
|
|
|
playerdata.levscore[lev] = 0;
|
|
},
|
|
|
|
addlevelgridwid: function (lev, newwid) {
|
|
var ratio;
|
|
|
|
ratio = newwid / DEF_GRIDW;
|
|
|
|
console.log("lev " + lev + " newwid " + newwid + " ratio " + ratio);
|
|
|
|
this.levels[lev].gridsize = DEF_GRIDSIZE / ratio;
|
|
this.levels[lev].thingsize = DEF_THINGSIZE / ratio;
|
|
this.levels[lev].gridw = DEF_GRIDW * ratio;
|
|
this.levels[lev].gridh = DEF_GRIDH * ratio;
|
|
this.levels[lev].boardx = Math.floor((SCREENW - (this.levels[lev].gridw * this.levels[lev].gridsize)) / 2);
|
|
},
|
|
|
|
// thingtype pct
|
|
addlevelthings: function (lev) {
|
|
var i,idx;
|
|
for (i = 1 ; 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];
|
|
}
|
|
},
|
|
|
|
// thingtype howmany
|
|
addlevelforcethings: function (lev) {
|
|
var i,idx;
|
|
for (i = 1 ; 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];
|
|
}
|
|
},
|
|
|
|
clearlevelprogress : function (lev) {
|
|
var i,idx;
|
|
for (i = 0 ; i < this.levels[lev].goals.length; i++) {
|
|
this.levels[lev].goals[i].progress = 0;
|
|
}
|
|
},
|
|
|
|
// thing1, thing2, etc
|
|
addlevelallowedthings : function (lev) {
|
|
var i;
|
|
for (i = 1 ; 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) {
|
|
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];
|
|
this.levels[lev].goals[idx].progress = 0;
|
|
}
|
|
},
|
|
|
|
// earn progress towards goals
|
|
progress : function(type, amt) {
|
|
var i;
|
|
|
|
// past last level!
|
|
if (curlevel >= game.levels.length) return false;
|
|
|
|
//console.log("progress()");
|
|
for (i = 0 ; i < this.levels[curlevel].goals.length; i++ ) {
|
|
//console.log("this goal type is " + this.levels[curlevel].goals[i].type);
|
|
if (this.levels[curlevel].goals[i].type == type) {
|
|
this.levels[curlevel].goals[i].progress += amt;
|
|
if (this.levels[curlevel].goals[i].progress >= this.levels[curlevel].goals[i].count) {
|
|
|
|
this.levels[curlevel].goals[i].progress = this.levels[curlevel].goals[i].count;
|
|
|
|
// add goal animation - fireworks ?
|
|
//things.push(new thing(2,2, "text", "Goal!"));
|
|
this.addfirework();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
|
|
calcstars : function (lev, points) {
|
|
var i;
|
|
for (i = 2; i >= 0; i--) {
|
|
if (points >= this.levels[lev].starpoints[i]) {
|
|
return (i+1);
|
|
}
|
|
}
|
|
return 0;
|
|
},
|
|
|
|
/*
|
|
calcstartext : function (nstars) {
|
|
var i;
|
|
var met = "", notmet = "";
|
|
for (i = 0; i < nstars; i++) {
|
|
met = met + FULLSTAR;
|
|
}
|
|
for (; i < 3; i++) {
|
|
notmet = notmet + EMPTYSTAR;
|
|
}
|
|
return [ met, notmet ] ;
|
|
},
|
|
*/
|
|
|
|
setstarpoints : function( lev, p1, p2, p3 ) {
|
|
this.levels[lev].starpoints = new Array();
|
|
this.levels[lev].starpoints[0] = p1;
|
|
this.levels[lev].starpoints[1] = p2;
|
|
this.levels[lev].starpoints[2] = p3;
|
|
},
|
|
|
|
calcstarpoints : function( lev ) {
|
|
var i,num;
|
|
var min = 0,pointsgoal = false;
|
|
// calculate minimum points required to win
|
|
// first pass
|
|
for (i = 0; i < this.levels[lev].goals.length; i++) {
|
|
switch (this.levels[lev].goals[i].type) {
|
|
case "food":
|
|
min += FOODPOINTS * this.levels[lev].goals[i].count;
|
|
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;
|
|
break;
|
|
case "cats": // use smaller amount of catpoints
|
|
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count;
|
|
break;
|
|
case "goats":
|
|
min += GOATPOINTS * this.levels[lev].goals[i].count;
|
|
break;
|
|
case "turns":
|
|
// assume you'll get a parade on most turns.
|
|
num = (Math.min(CATPOINTS, SLEEPYCATPOINTS) * this.levels[lev].goals[i].count);
|
|
if (!game.isbanned(curlevel, "door")) {
|
|
num *= 1.5;
|
|
}
|
|
|
|
min += num;
|
|
break;
|
|
case "doors":
|
|
// double the value of a minimum-score parade
|
|
min += Math.min(CATPOINTS, SLEEPYCATPOINTS) * 3 * 2 * this.levels[lev].goals[i].count;
|
|
break;
|
|
case "sun cycles":
|
|
min += SLEEPYCATPOINTS*5 * this.levels[lev].goals[i].count;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
|
|
// second pass - overrides
|
|
/*
|
|
for (i = 0; i < this.levels[lev].goals.length; i++) {
|
|
switch (this.levels[lev].goals[i].type) {
|
|
case "points":
|
|
pointsgoal = this.levels[lev].goals[i].count;
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// adjust for level size
|
|
if (this.levels[lev].gridsize != DEF_GRIDSIZE) {
|
|
var ratio;
|
|
ratio = (this.levels[lev].gridw * this.levels[lev].gridh) /
|
|
(DEF_GRIDW * DEF_GRIDH) * 2;
|
|
|
|
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));
|
|
},
|
|
|
|
initlevels : function ( ) {
|
|
var mylevel,i,n;
|
|
|
|
console.log("doing level init");
|
|
this.levels = [];
|
|
this.addlevel(1, true);
|
|
this.addlevelgoals(1, "food", 5);
|
|
this.setstarpoints(1, 50, 60, 80);
|
|
this.addlevelthings(1, "cat", 50, "food", 50);
|
|
|
|
this.addlevel(2, true);
|
|
this.addlevelgoals(2, "cats", 10);
|
|
this.addlevelgoals(2, "parades", 3);
|
|
this.addlevelthings(2, "cat", 45, "food", 55);
|
|
|
|
this.addlevel(3, true);
|
|
this.addlevelallowedthings(3, "cat", "food", "llama");
|
|
this.addlevelgoals(3, "llamas", 3);
|
|
|
|
this.addlevel(4, true);
|
|
this.addlevelgoals(4, "llamas", 5);
|
|
this.addlevelgoals(4, "food", 5);
|
|
this.addlevelallowedthings(4, "cat", "food", "llama");
|
|
|
|
this.addlevel(5, false);
|
|
this.addlevelgridwid(5, 6);
|
|
this.addlevelgoals(5, "turns", 10);
|
|
//this.addlevelgoals(5, "points", 600);
|
|
this.addlevelallowedthings(5, "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.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.addlevel(8, false);
|
|
this.addlevelallowedthings(8,"goat", "cat", "food", "llama");
|
|
this.addlevelgoals(8, "turns", 20);
|
|
this.addlevelgoals(8, "llamas", 3);
|
|
|
|
// 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.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);
|
|
|
|
// 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);
|
|
|
|
|
|
for (i = 1; i < this.levels.length; i++) {
|
|
var extrastars;
|
|
// calc star point cutoffs
|
|
if (this.levels[i].starpoints == undefined) {
|
|
this.calcstarpoints(i);
|
|
}
|
|
|
|
// calc stars to unlock
|
|
extrastars = Math.floor(i / 5);
|
|
this.levels[i].starsrequired = (i-1) + extrastars;
|
|
}
|
|
|
|
|
|
/*
|
|
for (i = 1; i < this.levels.length; i++) {
|
|
console.log("Level " + (i) + " goals:");
|
|
for (n = 0; n < this.levels[i].goals.length; n++) {
|
|
console.log(GOALVERB[this.levels[i].goals[n].type] + " " +
|
|
this.levels[i].goals[n].count + " " +
|
|
this.levels[i].goals[n].type);
|
|
}
|
|
}
|
|
*/
|
|
},
|
|
|
|
/*
|
|
startlevel : function() {
|
|
this.initlevelvars();
|
|
this.populategrid();
|
|
|
|
this.setstate("running");
|
|
this.dirty = true;
|
|
},
|
|
*/
|
|
|
|
populategrid : function() {
|
|
var i;
|
|
while (!anyvalidmoves()) {
|
|
var x,y;
|
|
|
|
console.log("populating grid...");
|
|
clearthings();
|
|
|
|
// populate initial things
|
|
for (y = 0; y < GRIDH; y++) {
|
|
for (x = 0; x < GRIDW; x++) {
|
|
// start off above the grid
|
|
things.push(new thing(x, y, "random"));
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// now move everything up so they'll fall down into the initial
|
|
// positions.
|
|
for (i = 0; i < things.length; i++) {
|
|
things[i].gridy -= GRIDH;
|
|
things[i].updatexy();
|
|
}
|
|
},
|
|
|
|
drawflash : function() {
|
|
if (!this.screenflash) return;
|
|
game.dirty = true;
|
|
|
|
ctx.globalAlpha = this.screenflash;
|
|
|
|
this.screenflash -= FLASHSPEED;
|
|
if (this.screenflash < 0) this.screenflash = 0;
|
|
|
|
ctx.fillStyle = "#ffffff";
|
|
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
ctx.globalAlpha = 1.0;
|
|
},
|
|
|
|
clear : function() {
|
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
},
|
|
|
|
drawtop : function() {
|
|
var texttodraw = overdesc;
|
|
var col = "#aaaaaa";
|
|
var i,n;
|
|
|
|
//ctx = this.context;
|
|
|
|
// clear
|
|
ctx.clearRect(0, 0, this.canvas.width-1, BOARDY-1);
|
|
|
|
if (game.state == "running") {
|
|
var y1 = 10;
|
|
var y2 = 26;
|
|
var y3 = 45;
|
|
var x,y = 10;
|
|
|
|
|
|
// show level
|
|
/*
|
|
ctx.font = "16pt Futura";
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "top";
|
|
ctx.fillStyle = "#00aaee";
|
|
ctx.fillText("Level " + curlevel, SCREENW/2, y1);
|
|
*/
|
|
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, "Level " + curlevel, LEVELTEXTSIZE, "#00aaee", SCREENW/2, y1);
|
|
|
|
// show star targets
|
|
var starsize = 10;
|
|
var starindent = 16;
|
|
var startextcol = "#eeee00";
|
|
var startextcoldark = "#999900";
|
|
x = SCREENW/4;
|
|
for (i = 0; i < 3; i++) {
|
|
var n,starx,stars = "";
|
|
for (n = 0; n < (i+1); n++) {
|
|
/*
|
|
if (n == 0) {
|
|
starx = (SCREENW/4)
|
|
} else if
|
|
drawcross(ctx, starx, y, starx + starsize, y + starsize, startextcol, 2);
|
|
starx += starsize*1.5;
|
|
*/
|
|
stars = stars + "\u2605"
|
|
|
|
}
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, stars + " = " + addcommas(game.levels[curlevel].starpoints[i]), STARPOINTTEXTSIZE,
|
|
(score >= game.levels[curlevel].starpoints[i]) ? startextcol : startextcoldark,
|
|
x, y2);
|
|
x += (SCREENW / 4);
|
|
}
|
|
|
|
// show score
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, "Score: " + addcommas(score), SCORETEXTSIZE, "white", 16, y3);
|
|
/*
|
|
ctx.font = "16pt Futura";
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
ctx.fillStyle = "white";
|
|
ctx.fillText("Score: " + addcommas(score), 16, y2);
|
|
*/
|
|
|
|
switch (thingsmoving()) {
|
|
case "parade":
|
|
col = "#00ff00";
|
|
texttodraw = "CAT PARADE!"
|
|
break;
|
|
case "chomp":
|
|
col = "#00cc00";
|
|
texttodraw = "Chomp!"
|
|
break;
|
|
default:
|
|
// show current object in path
|
|
if ((curpath != undefined) && (curpath.length >= 1)) {
|
|
var lastone = curpath[curpath.length - 1];
|
|
texttodraw = lastone.getdesc();
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
if (texttodraw != "") {
|
|
/*
|
|
ctx.font = "16pt Futura";
|
|
ctx.textAlign = "right";
|
|
ctx.textBaseline = "top";
|
|
ctx.fillStyle = col;
|
|
ctx.fillText(texttodraw, SCREENW-16, y2);
|
|
*/
|
|
|
|
ctx.textAlign = "right";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, texttodraw, SCORETEXTSIZE, col, SCREENW-16, y3);
|
|
}
|
|
|
|
|
|
} else if (game.state == "gameover") {
|
|
this.context.textAlign = "center";
|
|
this.context.textBaseline = "top";
|
|
shadowtext(this.context, "No more moves!", 20, "red", SCREENW / 2, 5);
|
|
shadowtext(this.context, "Final Score: " + addcommas(score), 16, "white", SCREENW / 2, 35);
|
|
} else if (game.state == "levelcomplete") {
|
|
this.context.textAlign = "center";
|
|
this.context.textBaseline = "top";
|
|
shadowtext(this.context, "LEVEL COMPLETE!", 20, "#00ee00", SCREENW / 2, 5);
|
|
shadowtext(this.context, "Score: " + addcommas(score), 16, "white", SCREENW / 2, 35);
|
|
|
|
}
|
|
},
|
|
|
|
drawbottom : function() {
|
|
var bx = 0,by = BOARDY + GRIDH*GRIDSIZE + 25;
|
|
var bw = SCREENW - BOTTOMBORDERWIDTH, bh = SCREENH - by - BOTTOMBORDERWIDTH;
|
|
|
|
var x,y;
|
|
var margin = 10;
|
|
var indent = 50;
|
|
var boxindent = 20;
|
|
//ctx = this.context;
|
|
|
|
if ((game.state == "running") || (game.state == "levelcomplete") || (game.state == "gameover")) {
|
|
var texth = GOALTEXTSIZE+10;
|
|
var gradient;
|
|
var borderwidth = 5;
|
|
var goaltitlecol = "#00aaee";
|
|
|
|
// background
|
|
gradient = this.context.createLinearGradient(0, 0, bw, bh);
|
|
gradient.addColorStop(0, "#0000ff");
|
|
gradient.addColorStop(1, "#000055");
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(bx, by, bw, bh);
|
|
|
|
//outline
|
|
ctx.strokeStyle = "cyan";
|
|
ctx.lineWidth = BOTTOMBORDERWIDTH;
|
|
ctx.beginPath();
|
|
ctx.rect(bx+(borderwidth/2), by+(borderwidth/2), bw-(borderwidth/2), bh-(borderwidth/2));
|
|
ctx.stroke();
|
|
|
|
// draw goals
|
|
x = bx + margin;
|
|
y = by + margin;
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, "Goals:", GOALTEXTSIZE,goaltitlecol, x , y); y += texth;
|
|
|
|
if (curlevel < this.levels.length) {
|
|
for (n = 0; n < this.levels[curlevel].goals.length; n++) {
|
|
var goalcol = "#aaee00";
|
|
var goalmet = false;
|
|
|
|
// for checkbox
|
|
var boxsize = texth-8;
|
|
var boxx = x+boxindent;
|
|
var boxy = y + texth/2 - boxsize/2;
|
|
|
|
if (this.levels[curlevel].goals[n].progress >= this.levels[curlevel].goals[n].count) {
|
|
goalmet = true;
|
|
}
|
|
|
|
if (goalmet) {
|
|
goalcol = "#00ddff";
|
|
} else {
|
|
goalcol = "#aaee00";
|
|
}
|
|
|
|
// goal name
|
|
var goaltext = GOALVERB[this.levels[curlevel].goals[n].type] + " " +
|
|
this.levels[curlevel].goals[n].count + " " +
|
|
this.levels[curlevel].goals[n].type;
|
|
|
|
var progtext = "[" + this.levels[curlevel].goals[n].progress + " / " +
|
|
this.levels[curlevel].goals[n].count + "]";
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, goaltext, GOALTEXTSIZE,goalcol, x+indent, y);
|
|
|
|
ctx.textAlign = "right";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, progtext, GOALTEXTSIZE,goalcol, SCREENW-indent, y);
|
|
|
|
// completed?
|
|
if (goalmet) {
|
|
var crossouth = 4;
|
|
|
|
ctx.beginPath();
|
|
ctx.fillStyle = goalcol;
|
|
ctx.fillRect(x+indent,boxy+boxsize/2-crossouth/2,SCREENW - indent*2 - x, crossouth);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.strokeStyle = "black";
|
|
ctx.lineWidth = 1;
|
|
ctx.rect(x+indent,boxy+boxsize/2-crossouth/2,SCREENW - indent*2 - x, crossouth);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// checkbox
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 3;
|
|
ctx.strokeStyle = "black";
|
|
ctx.rect(boxx,boxy,boxsize,boxsize); // shadow1
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeStyle = goalcol;
|
|
ctx.rect(boxx,boxy,boxsize,boxsize); // shadow1
|
|
ctx.stroke();
|
|
|
|
// ticked ?
|
|
if (goalmet) {
|
|
drawtick(ctx, boxx, boxy, boxx + boxsize-1, boxy + boxsize-1, goalcol, 2);
|
|
}
|
|
|
|
y += texth;
|
|
}
|
|
|
|
y += texth;
|
|
} else {
|
|
// past last level
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, "(none)", GOALTEXTSIZE,goaltitlecol, x+indent, y);
|
|
}
|
|
}
|
|
},
|
|
|
|
zoomwinimg : function() {
|
|
var orig;
|
|
orig = this.winimgsize;
|
|
this.winimgsize += WINIMGZOOMSPEED;
|
|
if (this.winimgsize > 1) this.winimgsize = 1;
|
|
|
|
if (this.winimgsize != orig) {
|
|
// recalc image position
|
|
tapx = (SCREENW/2) - ((tapw * this.winimgsize)/2);
|
|
tapy = BOARDY + ((GRIDH*GRIDSIZE)/2) - ((taph*this.winimgsize)/2);
|
|
game.dirty = true;
|
|
}
|
|
},
|
|
|
|
drawcontinuebutton : function() {
|
|
var borderwidth = 5;
|
|
//var /ctx = this.context;
|
|
var col,y;
|
|
|
|
|
|
if (game.state == "gameover") {
|
|
//fill
|
|
ctx.beginPath();
|
|
ctx.fillStyle = "black";
|
|
ctx.fillRect(tapx+(borderwidth/2), tapy+(borderwidth/2), tapw-(borderwidth), taph-(borderwidth/2));
|
|
ctx.stroke();
|
|
} else {
|
|
var zoomw,zoomh;
|
|
// draw winning cat image
|
|
//console.log("drawing win img. tapx:" + tapx + " tapy:" + tapy + " tapw:" + tapw + " taph:" + taph);
|
|
|
|
zoomw = tapw * game.winimgsize;
|
|
zoomh = taph * game.winimgsize;
|
|
|
|
this.context.drawImage(winimg, tapx, tapy, zoomw, zoomh);
|
|
}
|
|
|
|
//outline
|
|
if (game.state == "gameover") {
|
|
col = "#dd0000";
|
|
ctx.beginPath();
|
|
ctx.strokeStyle = col;
|
|
ctx.lineWidth = 5;
|
|
ctx.rect(tapx+(borderwidth/2), tapy+(borderwidth/2), tapw-(borderwidth), taph-(borderwidth/2));
|
|
ctx.stroke();
|
|
} else if (game.winimgsize >= 1) {
|
|
col = "#00dd00";
|
|
ctx.beginPath();
|
|
ctx.strokeStyle = col;
|
|
ctx.lineWidth = 5;
|
|
ctx.rect(tapx+(borderwidth/2), tapy+(borderwidth/2), tapw-(borderwidth), taph-(borderwidth/2));
|
|
ctx.stroke();
|
|
}
|
|
|
|
ctx.textAlign = "center";
|
|
|
|
if (game.state == "gameover") {
|
|
y = tapy + taph/2;
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, "Tap here to continue", TAPBUTTONSIZE, col, SCREENW / 2, y);
|
|
} else if (game.winimgsize >= 1) {
|
|
var nstars;
|
|
|
|
ctx.textBaseline = "bottom";
|
|
|
|
y = tapy + taph - 5 - TAPBUTTONSIZE*1.5;
|
|
shadowtext(ctx, "Tap to continue", TAPBUTTONSIZEC, col, SCREENW / 2, y);
|
|
|
|
y += TAPBUTTONSIZEC;
|
|
|
|
nstars = game.calcstars(curlevel, score);
|
|
game.drawstars(ctx, SCREENW / 2, y, TAPBUTTONSIZESTAR, nstars, STARWID_ENDLEV);
|
|
console.log("earned " + nstars + " stars");
|
|
}
|
|
|
|
|
|
},
|
|
|
|
drawstars : function(ctx, x, y, size, stars, starwid) {
|
|
var i;
|
|
var starcol = "#dddd00";
|
|
var starspace = starwid / 10;
|
|
var sx;
|
|
|
|
sx = x - (starwid+starspace);
|
|
for (i = 1;i <= 3; i++) {
|
|
var thiscol,imgname;
|
|
if (stars >= i) {
|
|
imgname = "starfull";
|
|
} else {
|
|
imgname = "starempty";
|
|
}
|
|
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
this.context.drawImage(image[imgname], sx - (starwid/2), y - (starwid/2), starwid, starwid);
|
|
|
|
sx += starwid + starspace;
|
|
|
|
}
|
|
},
|
|
|
|
drawbg : function() {
|
|
var gradient,x,y,off;
|
|
var catscale,catsize,catspeed;
|
|
var wantalpha,alphaspeed;
|
|
// background
|
|
/*
|
|
gradient = this.context.createLinearGradient(0, 0, 0, SCREENH);
|
|
gradient.addColorStop(0, "black");
|
|
gradient.addColorStop(1, "blue");
|
|
|
|
this.context.fillStyle = gradient;
|
|
*/
|
|
this.context.fillStyle = "#005051";
|
|
this.context.fillRect(0, 0, SCREENW, SCREENH);
|
|
|
|
// moving cats
|
|
catscale = 1;
|
|
catspeed = 0.5;
|
|
alphaspeed = 0.02;
|
|
|
|
catsize = DEF_GRIDSIZE * catscale;
|
|
if (game.state == "help" ){
|
|
wantalpha = 0.2;
|
|
} else if (game.state == "levselect") {
|
|
wantalpha = 0.6;
|
|
} else {
|
|
wantalpha = 1.0;
|
|
}
|
|
|
|
if (catalpha > wantalpha) {
|
|
catalpha -= alphaspeed;
|
|
if (catalpha < wantalpha) catalpha = wantalpha;
|
|
} else if (catalpha < wantalpha) {
|
|
catalpha += alphaspeed;
|
|
if (catalpha > wantalpha) catalpha = wantalpha;
|
|
}
|
|
|
|
ctx.globalAlpha = catalpha;
|
|
off = game.frameNo % (catsize / catspeed);
|
|
for (y = -catsize*2; y < SCREENH; y += catsize*2) {
|
|
for (x = -catsize*2; x < SCREENW+catsize*2; x += catsize) {
|
|
//ctx.fillStyle = "red";
|
|
//ctx.fillRect(x +(catsize/4)+off, y +(catsize/4)+off, catsize/2, catsize/2);
|
|
this.context.drawImage(image['catwalkr'], x +(catsize/4)+off*catspeed, y +(catsize/4),
|
|
image['catwalkr'].width*catscale,
|
|
image['catwalkr'].height*catscale);
|
|
|
|
this.context.drawImage(image['catwalkl'], x +(catsize/4)-off*catspeed, y +(catsize/4)+catsize,
|
|
image['catwalkl'].width*catscale,
|
|
image['catwalkl'].height*catscale);
|
|
}
|
|
}
|
|
ctx.globalAlpha = 1.0;
|
|
},
|
|
|
|
drawtitle : function() {
|
|
var ratio,w,h;
|
|
var img = image['title'];
|
|
var catyoff = 0;
|
|
var titlexoff = 0;
|
|
var titley = 10;
|
|
var creditsy = 64;
|
|
var textgrad;
|
|
|
|
// background
|
|
this.drawbg();
|
|
|
|
// big cat
|
|
ratio = SCREENW / img.width;
|
|
w = img.width * ratio;
|
|
h = img.height * ratio;
|
|
|
|
catyoff = wipe.getval(h, "down", "up", 0);
|
|
this.context.drawImage(img, SCREENW/16, SCREENH - h + catyoff, w, h);
|
|
|
|
// text
|
|
this.context.textAlign = "center";
|
|
this.context.textBaseline = "top";
|
|
|
|
titlexoff = wipe.getval(SCREENW, "down", "up", 0);
|
|
|
|
|
|
shadowtext(this.context, "Cat Parade", TITLETEXTSIZE,"red", SCREENW / 2 - titlexoff, titley, "#ff0000", "#ffff00", "white");
|
|
shadowtext(this.context, "rpearce, 2016", TITLECREDITTEXTSIZE, "#00aaee", SCREENW / 2 - titlexoff, creditsy);
|
|
|
|
this.context.textBaseline = "bottom";
|
|
shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2 + titlexoff, SCREENH - 64);
|
|
},
|
|
|
|
levelexists : function (lev) {
|
|
if (lev > 0 && lev < game.levels.length) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
countplayerstars : function () {
|
|
var i;
|
|
var total = 0;
|
|
|
|
for (i = 1 ; i < game.levels.length; i++ ) {
|
|
total += game.calcstars(i, playerdata.getlevscore(i));
|
|
}
|
|
return total;
|
|
},
|
|
|
|
levellocked : function (lev) {
|
|
if (playerdata.totstars < game.levels[lev].starsrequired) return true;
|
|
|
|
return false;
|
|
},
|
|
|
|
// returns new y val
|
|
drawhelpsubtitle : function(ctx, text, y) {
|
|
var subtitlecol = "#cc00cc";
|
|
var xindent = 10;
|
|
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, text, HELPSUBTITLESIZE,subtitlecol, SCREENW / 2, y);
|
|
return (y + HELPTEXTYSPACE*1.5);
|
|
},
|
|
|
|
// return TRUE if there is no help for this level
|
|
drawhelp : function() {
|
|
var divamt = 2;
|
|
var imgsize = THINGSIZE / divamt;
|
|
var gridsize = GRIDSIZE / divamt;
|
|
var gradient,x,y,x2,y2,curx,cury;
|
|
var row1y,row2y,row3y;
|
|
var i;
|
|
var linex = [];
|
|
var liney = [];
|
|
|
|
var textxspace = 10;
|
|
|
|
var midpoint1 = SCREENW/8 * 5;
|
|
var midpoint2 = SCREENW/8 * 4;
|
|
var titlecol = "#00ccff";
|
|
var helpcol = "#00cc00";
|
|
var pointscoldark = "#888800";
|
|
var pointscol = "#dddd00";
|
|
|
|
//ctx = this.context;
|
|
|
|
// background
|
|
/*
|
|
gradient = this.context.createLinearGradient(0, 0, 0, SCREENH);
|
|
gradient.addColorStop(0, "black");
|
|
gradient.addColorStop(1, "blue");
|
|
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(0, 0, SCREENW, SCREENH);
|
|
*/
|
|
|
|
this.drawbg();
|
|
|
|
// top text
|
|
cury = HELPTEXTYSPACE*2;
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "bottom";
|
|
|
|
shadowtext(ctx, "Level " + curlevel + ": Instructions", HELPTITLESIZE,titlecol, SCREENW / 2, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
// original help text for reference. maybe use this
|
|
// for a 'continuous mode' later.
|
|
if (curlevel == -1) {
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Drag a cat to eat cheese.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
shadowtext(ctx, "Cats can eat any amount of cheese.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Cats can only eat cheese in a straight line.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
shadowtext(ctx, "Cats get tired after eating and cannot eat again.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
// help on eating
|
|
// row 1
|
|
x = imgsize;
|
|
y = cury;
|
|
row1y = y;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
x2 = x + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
ctx.strokeStyle = PATHLINECOLGOOD;
|
|
ctx.lineWidth = LINEWIDTH;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x + imgsize/2, y + imgsize/2);
|
|
ctx.lineTo(x2 + imgsize/2, y2 + imgsize/2);
|
|
ctx.stroke();
|
|
|
|
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
|
|
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
cury = y2 + gridsize;
|
|
|
|
// row 2
|
|
x = imgsize;
|
|
y = cury;
|
|
row2y = y;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
x2 = x + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
x2 = x2 + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
x2 = x2 + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
|
|
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
cury = y2 + gridsize;
|
|
|
|
// arrow to middle
|
|
x = x2 + gridsize;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = x + gridsize*1.5;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// middle
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "top";
|
|
|
|
x = midpoint1;
|
|
y = row1y+10;
|
|
shadowtext(ctx, "+" + FOODPOINTS + " points", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
y = row2y-10;
|
|
shadowtext(ctx, "per cheese", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
|
|
// arrow to right
|
|
x = midpoint1 + gridsize + 10;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = SCREENW - imgsize*2;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// right
|
|
x = SCREENW - imgsize*2;
|
|
y = row1y;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
y = row2y;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
// LLAMA HELP
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Cats are scared of " + llamatext + "s and can't move when near them.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// PARADE HELP
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Drag a path through multiple cats to start a parade.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, " - Parades can turn corners.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, " - Parades can include one " + llamatext + " only.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of parade
|
|
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['catscared'], x, y, imgsize, imgsize);
|
|
linex[3] = x + imgsize/2;
|
|
liney[3] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[4] = x + imgsize/2;
|
|
liney[4] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['catfull'], 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[5] = x + imgsize/2;
|
|
liney[5] = y + imgsize/2;
|
|
cury = y + HELPTEXTYSPACE;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
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);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// explain points for parades
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
x = midpoint2;
|
|
y = row1y;
|
|
shadowtext(ctx, "+" + CATPOINTS + " points per cat", HELPTEXTSIZE,pointscol, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + SLEEPYCATPOINTS + " points per sleepy cat", HELPTEXTSIZE,pointscol, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + LLAMAPOINTS + " points per " + llamatext, HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
cury = y + HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// GAME OVER HELP
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "You fail the level if there are no valid moves left.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
ctx.textAlign = "center";
|
|
this.context.textBaseline = "bottom";
|
|
shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2, SCREENH - HELPTEXTYSPACE*2);
|
|
} else if (curlevel == 1) {
|
|
cury = this.drawhelpsubtitle(ctx, "Chomping Food", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Drag a cat to eat cheese.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE*1.5;
|
|
|
|
shadowtext(ctx, "Cats can eat any amount of cheese, but cannot turn", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
shadowtext(ctx, "corners whilst doing so.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE*1.5;
|
|
|
|
shadowtext(ctx, "Cats get tired after eating and cannot eat again.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
// help on eating
|
|
// row 1
|
|
x = imgsize;
|
|
y = cury;
|
|
row1y = y;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
x2 = x + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
ctx.strokeStyle = PATHLINECOLGOOD;
|
|
ctx.lineWidth = LINEWIDTH;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x + imgsize/2, y + imgsize/2);
|
|
ctx.lineTo(x2 + imgsize/2, y2 + imgsize/2);
|
|
ctx.stroke();
|
|
|
|
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
|
|
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
cury = y2 + gridsize;
|
|
|
|
// row 2
|
|
x = imgsize;
|
|
y = cury;
|
|
row2y = y;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
x2 = x + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
x2 = x2 + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
x2 = x2 + gridsize;
|
|
y2 = y;
|
|
ctx.drawImage(image['cheese'], x2, y2, imgsize, imgsize);
|
|
|
|
drawarrow(ctx, x + (imgsize/2), y + (imgsize/2),
|
|
x2 + (imgsize/2), y2 + (imgsize/2), PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
cury = y2 + gridsize;
|
|
|
|
// arrow to middle
|
|
x = x2 + gridsize;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = x + gridsize*1.5;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// middle
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "top";
|
|
|
|
x = midpoint1;
|
|
y = row1y+10;
|
|
shadowtext(ctx, "+" + FOODPOINTS + " points", HELPTEXTSIZE,pointscol, x, y);
|
|
y = row2y-10;
|
|
shadowtext(ctx, "per cheese", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
|
|
// arrow to right
|
|
x = midpoint1 + gridsize + 10;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = SCREENW - imgsize*2;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// right
|
|
x = SCREENW - imgsize*2;
|
|
y = row1y;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
y = row2y;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// GOAL HELP
|
|
cury = this.drawhelpsubtitle(ctx, "Goals", cury);
|
|
ctx.textAlign = "left";
|
|
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);
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// GAME OVER HELP
|
|
cury = this.drawhelpsubtitle(ctx, "End of Game", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "The game ends when there are no valid moves left.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
} else if (curlevel == 2) {
|
|
|
|
// PARADE HELP
|
|
cury = this.drawhelpsubtitle(ctx, "Cat Parades", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Drag a path through multiple cats to start a parade.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Parades can change directions as many times as you like.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of parade
|
|
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);
|
|
linex[3] = x + imgsize/2;
|
|
liney[3] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[4] = x + imgsize/2;
|
|
liney[4] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
linex[2] = x + imgsize/2;
|
|
liney[2] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[5] = x + imgsize/2;
|
|
liney[5] = y + imgsize/2;
|
|
cury = y + HELPTEXTYSPACE;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
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);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// explain points for parades
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
x = midpoint2;
|
|
y = row1y + HELPTEXTYSPACE/2;
|
|
shadowtext(ctx, "+" + CATPOINTS + " points per cat", HELPTEXTSIZE,pointscol, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + SLEEPYCATPOINTS + " points per sleepy cat", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
cury = y + HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
} else if (curlevel == 3) {
|
|
var llamatitle = llamatext[0].toUpperCase() + llamatext.substring(1);
|
|
cury = this.drawhelpsubtitle(ctx, llamatitle + "s", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Cats are scared of " + llamatext + "s and can't move while nearby.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
cury = this.drawhelpsubtitle(ctx, "Cat + " + llamatitle + " Parades", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Each cat parade may include a single " + llamatext + " only.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of parade
|
|
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['catscared'], x, y, imgsize, imgsize);
|
|
linex[3] = x + imgsize/2;
|
|
liney[3] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[4] = x + imgsize/2;
|
|
liney[4] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['catfull'], 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[5] = x + imgsize/2;
|
|
liney[5] = y + imgsize/2;
|
|
cury = y + HELPTEXTYSPACE;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
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);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row1y + (imgsize);
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// explain points for parades
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
x = midpoint2;
|
|
y = row1y;
|
|
shadowtext(ctx, "+" + CATPOINTS + " points per cat", HELPTEXTSIZE,pointscoldark, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + SLEEPYCATPOINTS + " points per sleepy cat", HELPTEXTSIZE,pointscoldark, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + LLAMAPOINTS + " points per " + llamatext, HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
cury = y + HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
} else if (curlevel == 4) {
|
|
cury = this.drawhelpsubtitle(ctx, "Later Levels", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "As you complete levels, more features will be introduced.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "For example:", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, "Goats (level 6)", HELPTEXTSIZE, pointscol, THINGSIZE*1.5, cury + THINGSIZE/2 - HELPTEXTYSPACE/2);
|
|
ctx.drawImage(image['goat'], textxspace, cury, THINGSIZE, THINGSIZE);
|
|
cury += GRIDSIZE;
|
|
|
|
shadowtext(ctx, "Doors (level 9)", HELPTEXTSIZE,pointscol, THINGSIZE*1.5, cury + THINGSIZE/2 - HELPTEXTYSPACE/2);
|
|
ctx.drawImage(image['door'], textxspace, cury, THINGSIZE, THINGSIZE);
|
|
cury += GRIDSIZE;
|
|
|
|
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 == 6) {
|
|
cury = this.drawhelpsubtitle(ctx, "Goats", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Goats and cats can gang up on " + llamatext + "s.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Parades with a goat can contain any number of llamas.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of parade
|
|
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['catscared'], x, y, imgsize, imgsize);
|
|
linex[3] = x + imgsize/2;
|
|
liney[3] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[4] = x + imgsize/2;
|
|
liney[4] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
// middle line of parade
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['catscared'], 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[5] = x + imgsize/2;
|
|
liney[5] = y + imgsize/2;
|
|
|
|
// bottom line of parade
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row3y = y;
|
|
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
linex[8] = x + imgsize/2;
|
|
liney[8] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[7] = x + imgsize/2;
|
|
liney[7] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[6] = x + imgsize/2;
|
|
liney[6] = y + imgsize/2;
|
|
|
|
|
|
|
|
// lines
|
|
cury = y + HELPTEXTYSPACE;
|
|
|
|
|
|
// parade lines
|
|
for (i = 0; i < 7; i++) {
|
|
drawline(ctx, linex[i], liney[i], linex[i+1], liney[i+1], PATHLINECOLGOOD, LINEWIDTH);
|
|
}
|
|
drawarrow(ctx, linex[7], liney[7], linex[8], liney[8], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row2y + imgsize/2;
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// explain points for parades
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
x = midpoint2;
|
|
y = row1y + HELPTEXTYSPACE/2;
|
|
shadowtext(ctx, "+" + CATPOINTS + " points per cat", HELPTEXTSIZE,pointscoldark, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + SLEEPYCATPOINTS + " points per sleepy cat", HELPTEXTSIZE,pointscoldark, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + LLAMAPOINTS + " points per " + llamatext, HELPTEXTSIZE,pointscoldark, x, y);
|
|
y += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "+" + GOATPOINTS + " points per goat", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
y += HELPTEXTYSPACE;
|
|
y += HELPTEXTYSPACE;
|
|
cury = y;
|
|
|
|
shadowtext(ctx, "Goats can't start parades. Parades must start with a cat.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE * 1.5;
|
|
|
|
// bad example
|
|
x = imgsize;
|
|
y = cury;
|
|
row1y = y;
|
|
ctx.drawImage(image['goat'], 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*2;
|
|
|
|
y += gridsize;
|
|
cury = y;
|
|
|
|
drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], PATHLINECOLBAD, LINEWIDTH, PATHARROWSIZE);
|
|
drawcross(ctx, x+imgsize/8, row1y+imgsize/8, x + imgsize-imgsize/8, row1y + imgsize-imgsize/8, PATHLINECOLBAD, 3);
|
|
|
|
// good example
|
|
x = imgsize;
|
|
row2y = y;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[0] = x + imgsize/2;
|
|
liney[0] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize*2;
|
|
|
|
|
|
drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
drawtick(ctx, x, row2y, x + imgsize, row2y + imgsize, PATHLINECOLGOOD, 3);
|
|
|
|
y += gridsize;
|
|
cury = y;
|
|
} else if (curlevel == 9) {
|
|
cury = this.drawhelpsubtitle(ctx, "Doors", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Cats love escaping outside through doors.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Ending a parade on a door will score double points!", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of parade
|
|
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['catscared'], x, y, imgsize, imgsize);
|
|
linex[3] = x + imgsize/2;
|
|
liney[3] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['llama'], x, y, imgsize, imgsize);
|
|
linex[4] = x + imgsize/2;
|
|
liney[4] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
// middle line of parade
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['catscared'], x, y, imgsize, imgsize);
|
|
linex[2] = x + imgsize/2;
|
|
liney[2] = y + imgsize/2;
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['door'], x, y, imgsize, imgsize);
|
|
linex[5] = x + imgsize/2;
|
|
liney[5] = y + imgsize/2;
|
|
|
|
|
|
// parade lines
|
|
cury = y + HELPTEXTYSPACE;
|
|
for (i = 0; i < 5; i++) {
|
|
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);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row2y;
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// explain points for doors
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
x = midpoint2;
|
|
|
|
y = row2y - HELPTEXTYSPACE/2;
|
|
shadowtext(ctx, "x2 points", HELPTEXTSIZE,pointscol, x, y);
|
|
|
|
cury = y;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Doors don't fall down like other objects.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "They are only removed when a parade enters them.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
// top line of door fall example
|
|
x = imgsize;
|
|
y = cury;
|
|
row1y = y;
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['door'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
// middle line of parade
|
|
x = imgsize;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
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['cheese'], x, y, imgsize, imgsize);
|
|
|
|
// cat eating food line
|
|
drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], PATHLINECOLGOOD, LINEWIDTH, PATHARROWSIZE);
|
|
|
|
// arrow to middle
|
|
x = x + gridsize;
|
|
y = row2y;
|
|
|
|
x2 = midpoint2 - 10;
|
|
y2 = y;
|
|
|
|
drawarrow(ctx, x, y, x2, y2, "red", HELPLINEWIDTH, HELPARROWSIZE);
|
|
|
|
// top line of part 2 of door fall example
|
|
x = midpoint2;
|
|
y = cury;
|
|
row1y = y;
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['door'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
x += gridsize;
|
|
|
|
// middle line of parade
|
|
x = midpoint2;
|
|
y += gridsize;
|
|
row2y = y;
|
|
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
linex[0] = x + imgsize/2;
|
|
liney[0] = y + imgsize/2;
|
|
|
|
x += gridsize*2;
|
|
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
} else if (curlevel == 11) {
|
|
cury = this.drawhelpsubtitle(ctx, "Sunlight", cury);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "bottom";
|
|
shadowtext(ctx, "Cats love luxuriating in sunlight.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Any cats next to a sun will fall asleep.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['sunlight'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['catfull'], x, y, imgsize, imgsize);
|
|
|
|
cury += gridsize;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
shadowtext(ctx, "Each turn, suns swap places with the object below.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
shadowtext(ctx, "Cats will awaken once out of the sunlight.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['goat'], x, y, imgsize, imgsize);
|
|
linex[0] = x + imgsize/2;
|
|
liney[0] = y + imgsize/2;
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cat'], x, y, imgsize, imgsize);
|
|
|
|
cury += gridsize;
|
|
|
|
x = (SCREENW / 2) - gridsize/2 - gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['sunlight'], x, y, imgsize, imgsize);
|
|
linex[1] = x + imgsize/2;
|
|
liney[1] = y + imgsize/2;
|
|
|
|
x += gridsize;
|
|
y = cury;
|
|
ctx.drawImage(image['cheese'], x, y, imgsize, imgsize);
|
|
|
|
drawarrow(ctx, linex[0], liney[0], linex[1], liney[1], "#dd0000", LINEWIDTH, PATHARROWSIZE);
|
|
drawarrow(ctx, linex[1], liney[1], linex[0], liney[0], "#dd0000", LINEWIDTH, PATHARROWSIZE);
|
|
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
|
|
shadowtext(ctx, "After reaching the the bottom of the play area, suns will set.", HELPTEXTSIZE,helpcol, textxspace, cury);
|
|
cury += HELPTEXTYSPACE;
|
|
|
|
}
|
|
|
|
ctx.textAlign = "center";
|
|
this.context.textBaseline = "bottom";
|
|
shadowtext(this.context, "Tap to start", TITLESTARTTEXTSIZE, "#00dd00", SCREENW / 2, SCREENH - HELPTEXTYSPACE*2);
|
|
|
|
if (!hashelp(curlevel)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
drawlevselect : function() {
|
|
var titley = 5;
|
|
var pstarsy = 32;
|
|
var x,y,i;
|
|
var levnum = 1;
|
|
var levcol = "#555500";
|
|
//var gridcol = "#aaaa00";
|
|
var gridcol = "#000000";
|
|
var crosscol = "#bbbbbb";
|
|
var textcol = "#dddd00";
|
|
var titlecol = "#00aaee";
|
|
var scorecol = "#00dd00";
|
|
var starcol = "#dddd00";
|
|
var buttontextcol = "#bbbbbb";
|
|
|
|
var gridblack = "#111111";
|
|
|
|
var gridgrad,buttongrad;
|
|
|
|
var titleyoff = 0;
|
|
var buttonyoff = 0;
|
|
var gridalpha = 1.0;
|
|
|
|
var topstarsize =
|
|
|
|
//ctx = this.context;
|
|
|
|
// background
|
|
this.drawbg();
|
|
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "top";
|
|
|
|
titleyoff = wipe.getval(titley*5, "down", "up", 0);
|
|
shadowtext(ctx, "Level Selection", TITLESIZELEVSELECT,titlecol, SCREENW / 2, titley - titleyoff);
|
|
|
|
ctx.drawImage(image['starfull'], LEVSEL_X, pstarsy - titleyoff, STARWID_LEVSEL_TOP, STARWID_LEVSEL_TOP);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
shadowtext(ctx, playerdata.totstars, TEXTSIZETOTSTARS,starcol, LEVSEL_X + STARWID_LEVSEL_TOP*1.2, pstarsy - titleyoff);
|
|
|
|
gridalpha = wipe.getval(1.0, "up", "down", 1.0);
|
|
|
|
// grid
|
|
ctx.globalAlpha = gridalpha;
|
|
for (y = 0; y < LEVSELGRIDH*GRIDSIZE; y += GRIDSIZE) {
|
|
for (x = 0; x < LEVSELGRIDW*GRIDSIZE; x += GRIDSIZE) {
|
|
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)) {
|
|
gridgrad.addColorStop(0, "#00ee00");
|
|
} else {
|
|
gridgrad.addColorStop(0, "#eeeeee");
|
|
}
|
|
gridgrad.addColorStop(1, gridblack);
|
|
ctx.fillStyle = gridgrad;
|
|
ctx.fillRect(LEVSEL_X + x, LEVSEL_Y + y, GRIDSIZE-1, GRIDSIZE-1);
|
|
ctx.stroke();
|
|
|
|
if (this.levellocked(levnum)) {
|
|
// locked
|
|
ctx.drawImage(image['lock'],
|
|
LEVSEL_X + x + GRIDSIZE/2 - image['lock'].width/3,
|
|
LEVSEL_Y + y + GRIDSIZE/3 - image['lock'].height/3,
|
|
GRIDSIZE/2, GRIDSIZE/2);
|
|
|
|
// # stars to unlock
|
|
|
|
ctx.drawImage(image['starfull'],
|
|
LEVSEL_X + x + GRIDSIZE/2 - STARWID_LEVSEL_LOCKED*1.25,
|
|
LEVSEL_Y + y + GRIDSIZE - (GRIDSIZE/4) - (STARWID_LEVSEL_LOCKED/2),
|
|
STARWID_LEVSEL_LOCKED, STARWID_LEVSEL_LOCKED);
|
|
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "top";
|
|
|
|
shadowtext(ctx, this.levels[levnum].starsrequired,
|
|
TEXTSIZELEVSTARS, starcol,
|
|
LEVSEL_X + x + GRIDSIZE/2, LEVSEL_Y + y + GRIDSIZE - (GRIDSIZE/4) - (STARWID_LEVSEL_LOCKED/2));
|
|
|
|
|
|
} else {
|
|
var hiscore,starcount,stars = "";
|
|
var levy = LEVSEL_Y + y + GRIDSIZE/4;
|
|
var scorey = LEVSEL_Y + y + GRIDSIZE - 5;
|
|
|
|
var stary = levy + ((scorey - levy) / 2); // half way between
|
|
|
|
// show level num and hiscore
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, levnum, TEXTSIZELEVSELECT, textcol,
|
|
LEVSEL_X + x + GRIDSIZE/2,levy);
|
|
|
|
// get player hiscore
|
|
hiscore = playerdata.getlevscore(levnum);
|
|
|
|
// show stars
|
|
if (hiscore != undefined) {
|
|
starcount = game.calcstars(levnum, hiscore);
|
|
} else {
|
|
starcount = 0;
|
|
}
|
|
|
|
game.drawstars(ctx, LEVSEL_X + x + GRIDSIZE/2, stary, TEXTSIZELEVSTARS, starcount, STARWID_LEVSEL);
|
|
|
|
/*
|
|
stars = game.calcstartext(starcount);
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, stars, TEXTSIZELEVSTARS, starcol,
|
|
LEVSEL_X + x + GRIDSIZE/2,stary);
|
|
*/
|
|
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// level doesn't exist
|
|
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, "#eeeeee");
|
|
gridgrad.addColorStop(1, gridblack);
|
|
ctx.fillStyle = gridgrad;
|
|
ctx.fillRect(LEVSEL_X + x, LEVSEL_Y + y, GRIDSIZE-1, GRIDSIZE-1);
|
|
ctx.stroke();
|
|
|
|
// 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();
|
|
ctx.lineWidth = 3;
|
|
ctx.strokeStyle = gridcol;
|
|
ctx.rect(LEVSEL_X + x, LEVSEL_Y + y, GRIDSIZE-1, GRIDSIZE-1);
|
|
ctx.stroke();
|
|
|
|
levnum++;
|
|
}
|
|
}
|
|
ctx.globalAlpha = 1.0;
|
|
|
|
buttongrad = this.context.createLinearGradient(0, 0, levsel_contx + levsel_contw, 0);
|
|
buttongrad.addColorStop(0, "#999999");
|
|
buttongrad.addColorStop(1, "black");
|
|
|
|
if (wipe.isactive()) {
|
|
var fullamt = SCREENH - levsel_conty;
|
|
buttonyoff = fullamt - ((wipe.count / wipe.max) * fullamt);
|
|
}
|
|
|
|
buttonyoff = wipe.getval(SCREENH - levsel_conty, "down", "up", 0);
|
|
|
|
|
|
ctx.beginPath();
|
|
ctx.fillStyle = buttongrad;
|
|
ctx.fillRect(levsel_contx, levsel_conty + buttonyoff, levsel_contw, levsel_conth);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 3;
|
|
ctx.strokeStyle = gridcol;
|
|
ctx.rect(levsel_contx, levsel_conty + buttonyoff, levsel_contw, levsel_conth);
|
|
ctx.stroke();
|
|
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, "Back to title screen", BACKTOTITLESIZE, buttontextcol,
|
|
levsel_contx + levsel_contw/2, levsel_conty + levsel_conth/2 + buttonyoff);
|
|
|
|
},
|
|
|
|
drawgrid : function() {
|
|
/*
|
|
this.context.strokeStyle = "red";
|
|
this.context.lineWidth = 2;
|
|
this.context.beginPath();
|
|
// draw grid
|
|
for (y = 0; y < GRIDH*GRIDSIZE; y += GRIDSIZE) {
|
|
for (x = 0; x < GRIDW*GRIDSIZE; x += GRIDSIZE) {
|
|
this.context.rect(BOARDX + x, BOARDY + y, GRIDSIZE-1, GRIDSIZE-1);
|
|
}
|
|
}
|
|
|
|
this.context.stroke();
|
|
*/
|
|
},
|
|
|
|
drawpath : function() {
|
|
//var ctx = this.context;
|
|
var col;
|
|
var i;
|
|
|
|
if ((curpath == undefined) || (curpath.length < 1)) {
|
|
return;
|
|
}
|
|
|
|
if (pathvalid) {
|
|
col = PATHLINECOLGOOD;
|
|
} else {
|
|
col = PATHLINECOLBAD;
|
|
}
|
|
ctx.strokeStyle = col;
|
|
ctx.lineWidth = LINEWIDTH;
|
|
|
|
// draw line to show current path
|
|
ctx.beginPath();
|
|
ctx.moveTo(BOARDX + curpath[0].x + THINGSIZE/2, BOARDY + curpath[0].y + THINGSIZE/2);
|
|
for (i = 1; i < curpath.length; i++) {
|
|
ctx.lineTo(BOARDX + curpath[i].x + THINGSIZE/2, BOARDY + curpath[i].y + THINGSIZE/2);
|
|
}
|
|
ctx.stroke();
|
|
|
|
if (curpath.length >= 2) {
|
|
x1 = curpath[curpath.length-2].x + (THINGSIZE/2);
|
|
y1 = curpath[curpath.length-2].y + (THINGSIZE/2);
|
|
|
|
x2 = curpath[curpath.length-1].x + (THINGSIZE/2);
|
|
y2 = curpath[curpath.length-1].y + (THINGSIZE/2);
|
|
|
|
drawarrowhead(ctx, BOARDX + x1, BOARDY + y1, BOARDX + x2, BOARDY + y2, col, PATHARROWSIZE);
|
|
}
|
|
|
|
},
|
|
|
|
/*
|
|
handleclick : function(event) {
|
|
// make sure nothing is moving
|
|
if (thingsmoving()) return;
|
|
|
|
// did you click on an object?
|
|
var clickedthing = getthingxy(event.pageX,event.pageY);
|
|
if (clickedthing) {
|
|
clickedthing.kill();
|
|
}
|
|
},
|
|
*/
|
|
|
|
handlekeypress : function(event) {
|
|
var ch;
|
|
ch = String.fromCharCode(event.keyCode || event.charCode);
|
|
console.log("pressed " + ch);
|
|
if (ch == 'a') {
|
|
console.log("chear() - ending game");
|
|
game.setstate("gameover");
|
|
game.cheat = 1;
|
|
} else if (ch == 'c') {
|
|
playerdata.clearall();
|
|
} else if (ch == 't') {
|
|
game.addfirework();
|
|
} else if (ch == 'n') {
|
|
var i;
|
|
score += 10;
|
|
for (i = 0 ; i < game.levels[curlevel].goals.length; i++ ) {
|
|
game.levels[curlevel].goals[i].progress = game.levels[curlevel].goals[i].count;
|
|
}
|
|
game.cheat = 1;
|
|
console.log("cheat() - finishingl level");
|
|
} else if (ch == 'u') {
|
|
game.cheat = 1;
|
|
playerdata.settotstars(9999);
|
|
console.log("cheat() - set tot stars to " + playerdata.totstars);
|
|
}
|
|
},
|
|
|
|
|
|
handlemousedown : function(event) {
|
|
var coords,adjustx,adjusty,realx,realy;
|
|
event.preventDefault();
|
|
|
|
mbdown = true;
|
|
|
|
coords = getmousexy(event);
|
|
adjustx = coords[0];
|
|
adjusty = coords[1];
|
|
realx = coords[2];
|
|
realy = coords[3];
|
|
// remember coords for touch screens
|
|
if (event.type == "touchstart") {
|
|
lastmx = adjustx;
|
|
lastmy = adjusty;
|
|
}
|
|
|
|
if (wipe.isactive()) {
|
|
return;
|
|
}
|
|
|
|
if (game.state == "running") {
|
|
// ignore multi-touch
|
|
//if ((curpath != undefined) && curpath.length >= 1) return;
|
|
|
|
game.dirty = true; // need to redraw
|
|
|
|
// make sure nothing is moving
|
|
if (thingsfalling()) return;
|
|
|
|
// clear existing path
|
|
clearpath();
|
|
|
|
// did you click on an object?
|
|
var onthing = getthingxy(adjustx, adjusty);
|
|
if (onthing) {
|
|
if (canstartpath(onthing)) {
|
|
console.log("Initial click on " + onthing.name);
|
|
addtopath(onthing);
|
|
} else {
|
|
// just show description
|
|
overdesc = onthing.getdesc();
|
|
}
|
|
}
|
|
} else if (game.state == "gameover") {
|
|
if ((realx >= tapx) && (realx <= tapx + tapw) &&
|
|
(realy >= tapy) && (realy <= tapy + taph)) {
|
|
game.clearlevelprogress(curlevel);
|
|
|
|
wipe.start("levselect", "out", 20);
|
|
//game.setstate("levselect");
|
|
}
|
|
} else if (game.state == "title") {
|
|
wipe.start("levselect", "out", 15);
|
|
} else if (game.state == "levselect") {
|
|
// find where you clicked
|
|
if ((realx >= levsel_contx) && (realx <= levsel_contx + levsel_contw) &&
|
|
(realy >= levsel_conty) && (realy <= levsel_conty + levsel_conth)) {
|
|
/* TODO: this currently works on ios */
|
|
//game.setstate("title");
|
|
wipe.start("title", "out", 15);
|
|
} else {
|
|
/* TODO: this DOESN'T works on ios */
|
|
var gridx,gridy,levsel;
|
|
|
|
gridx = Math.floor(adjustx / GRIDSIZE);
|
|
gridy = Math.floor(adjusty / GRIDSIZE);
|
|
//gridx = Math.floor((realx - BOARDX) / GRIDSIZE);
|
|
//gridy = Math.floor((realy - BOARDY) / GRIDSIZE);
|
|
|
|
levsel = (gridy*LEVSELGRIDW) + gridx + 1;
|
|
|
|
if (game.levelexists(levsel) && !game.levellocked(levsel)) {
|
|
curlevel = levsel;
|
|
|
|
game.initgamevars();
|
|
game.helporstartlev();
|
|
}
|
|
}
|
|
} else if (game.state == "help") {
|
|
game.setstate("running");
|
|
} else if (game.state == "levelcomplete") {
|
|
if ((realx >= tapx) && (realx <= tapx + tapw) &&
|
|
(realy >= tapy) && (realy <= tapy + taph)) {
|
|
|
|
// clear goals in case we do this level again
|
|
game.clearlevelprogress(curlevel);
|
|
|
|
game.setstate("levselect");
|
|
}
|
|
}
|
|
},
|
|
|
|
helporstartlev : function() {
|
|
if (hashelp(curlevel)) {
|
|
wipe.start("help", "out", 15);
|
|
//game.setstate("help");
|
|
} else {
|
|
//game.startlevel();
|
|
wipe.start("running", "out", 15);
|
|
}
|
|
},
|
|
|
|
setstate : function(newstate) {
|
|
if (newstate != this.state) {
|
|
this.dirty = true;
|
|
}
|
|
if (newstate == "help") {
|
|
// decide which word to use
|
|
if (onein(2)) {
|
|
llamatext = "llama";
|
|
} else {
|
|
llamatext = "alpaca";
|
|
}
|
|
}
|
|
|
|
if (newstate == "gameover") {
|
|
tapx = 0, tapy = BOARDY + (GRIDH/2)*GRIDSIZE;
|
|
tapw = SCREENW, taph = GRIDSIZE;
|
|
} else if (newstate == "levelcomplete") {
|
|
var newsize;
|
|
//tapx = 0, tapy = BOARDY;
|
|
//tapw = SCREENW, taph = GRIDH*GRIDSIZE;
|
|
|
|
// calc size of continue button based on image size
|
|
newsize = getimgsize(winimg.width,winimg.height, SCREENW, GRIDH*GRIDSIZE);
|
|
tapw = newsize.width;
|
|
taph = newsize.height;
|
|
//tapx = (SCREENW / 2) - (tapw/2);
|
|
//tapy = BOARDY + ((GRIDH*GRIDSIZE)/2) - (taph/2);
|
|
tapx = 0;
|
|
tapy = BOARDY;
|
|
} else if (newstate == "running") {
|
|
|
|
this.initlevelvars();
|
|
this.populategrid();
|
|
|
|
// get a new cat picture for if we win
|
|
if (winimg != undefined) delete winimg;
|
|
winimg = new Image();
|
|
var n = rnd(MAXWINIMAGES);
|
|
winimg.src = "images/win" + n + ".png";
|
|
this.winimgsize = 0.1;
|
|
|
|
wipe.start("", "in", 50);
|
|
} else if (newstate == "levselect") {
|
|
// reset grid size
|
|
GRIDSIZE = DEF_GRIDSIZE;
|
|
THINGSIZE = DEF_THINGSIZE;
|
|
GRIDW = DEF_GRIDW;
|
|
GRIDH = DEF_GRIDH;
|
|
|
|
// count player stars
|
|
playerdata.settotstars(game.countplayerstars());
|
|
|
|
// start fade in
|
|
wipe.start("", "in", 15);
|
|
} else if (newstate == "title") {
|
|
// start fade in
|
|
wipe.start("", "in", 15);
|
|
}
|
|
|
|
this.state = newstate;
|
|
},
|
|
|
|
|
|
handlemousemove : function(event) {
|
|
var coords,adjustx,adjusty,realx,realy;
|
|
coords = getmousexy(event);
|
|
adjustx = coords[0];
|
|
adjusty = coords[1];
|
|
realx = coords[2];
|
|
realy = coords[3];
|
|
|
|
// remember coords for touch screens
|
|
if (event.type == "touchmove") {
|
|
lastmx = adjustx;
|
|
lastmy = adjusty;
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
if (!mbdown) return;
|
|
if (game.state != "running") return;
|
|
|
|
game.dirty = true; // need to redraw
|
|
|
|
// make sure nothing is moving
|
|
if (thingsmoving()) return;
|
|
|
|
// existing path?
|
|
if (curpath != undefined && curpath.length > 0) {
|
|
var overthing = getthingxy(adjustx, adjusty);
|
|
var lastinpath,secondlast;
|
|
|
|
if (curpath == undefined) {
|
|
lastinpath = null;
|
|
} else {
|
|
lastinpath = curpath[curpath.length-1];
|
|
if (curpath.length >= 2) {
|
|
secondlast = curpath[curpath.length-2];
|
|
} else {
|
|
secondlast = null;
|
|
}
|
|
}
|
|
|
|
if ((secondlast != undefined) && (overthing == secondlast)) {
|
|
backspacepath();
|
|
} else if (canextendpath(overthing)) {
|
|
// add it to the path
|
|
addtopath(overthing);
|
|
} else if (pathcontains(overthing) && pathcomplete()) {
|
|
pathvalid = true;
|
|
} else {
|
|
pathvalid = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
handlemouseup : function(event) {
|
|
var ok = true;
|
|
var adjustx, adjusty,realx,realy;
|
|
var ptype;
|
|
var points = 0;
|
|
var overthing = null;
|
|
|
|
event.preventDefault();
|
|
|
|
mbdown = false;
|
|
|
|
if (game.state != "running") return;
|
|
|
|
game.dirty = true; // need to redraw
|
|
|
|
ptype = getpathtype();
|
|
|
|
// special case for touch screens, as the 'touchend' events don't have x/y
|
|
if ((event.type == "touchend") || (event.type == "touchleave") || (event.type == "touchcancel")) {
|
|
adjustx = lastmx;
|
|
adjusty = lastmy;
|
|
} else {
|
|
coords = getmousexy(event);
|
|
adjustx = coords[0];
|
|
adjusty = coords[1];
|
|
realx = coords[2];
|
|
realy = coords[3];
|
|
}
|
|
|
|
overthing = getthingxy(adjustx, adjusty);
|
|
|
|
overdesc = "";
|
|
|
|
if ((curpath == undefined) || (curpath.length == 0)) {
|
|
//console.log("mouseup() - no path");
|
|
ok = false;
|
|
} else if (thingsmoving()) {
|
|
//console.log("mouseup() - things are moving");
|
|
ok = false;
|
|
} else if (!isvalidpath(curpath)) {
|
|
//console.log("mouseup() - path isn't valid");
|
|
ok = false;
|
|
} else if (!pathcomplete(curpath)) {
|
|
//console.log("mouseup() - path ("+ ptype + ") isn't complete");
|
|
ok = false;
|
|
} else if ((overthing == undefined) || !pathcontains(overthing)) {
|
|
//console.log("mouseup() - not over something in path");
|
|
ok = false;
|
|
}
|
|
|
|
if (!ok) {
|
|
clearpath();
|
|
return;
|
|
}
|
|
|
|
// figure out path type
|
|
points = 0;
|
|
switch(ptype) {
|
|
case "chomp":
|
|
// killall except first and last
|
|
if (curpath.length > 2) {
|
|
var i;
|
|
for (i = 1; i < curpath.length - 1; i++) {
|
|
curpath[i].givepoints();
|
|
curpath[i].addabove();
|
|
//curpath[i].kill();
|
|
curpath[i].startexplode();
|
|
}
|
|
}
|
|
|
|
curpath[curpath.length-1].givepoints();
|
|
|
|
// first one chomps last one
|
|
curpath[0].chomp(curpath[curpath.length - 1]);
|
|
|
|
game.progress("turns", 1);
|
|
break;
|
|
case "parade":
|
|
multiplier = 1;
|
|
if (curpath.length >= 2) { // should always be true
|
|
var i;
|
|
// everything in the path exits via a parade
|
|
|
|
pathdoor = pathcontainstype("door");
|
|
if (pathdoor) multiplier++;
|
|
|
|
for (i = 0; i < curpath.length; i++) {
|
|
// ... except doors
|
|
if (curpath[i].type == "door") {
|
|
game.progress("doors", 1);
|
|
console.log("path has doors!");
|
|
// add animation
|
|
things.push(new thing(curpath[i].gridx, curpath[i].gridy, "text", "x" + multiplier));
|
|
} else {
|
|
curpath[i].givepoints();
|
|
curpath[i].startparade();
|
|
}
|
|
}
|
|
clearpath();
|
|
} else {
|
|
// just kill everything in path
|
|
while (curpath != undefined && curpath.length > 0) {
|
|
curpath[0].givepoints();
|
|
curpath[0].addabove();
|
|
curpath[0].kill();
|
|
curpath.splice(0, 1);
|
|
}
|
|
}
|
|
multiplier = 1;
|
|
game.progress("parades", 1);
|
|
game.progress("turns", 1);
|
|
break;
|
|
}
|
|
|
|
clearpath();
|
|
|
|
// things that happen once per turn.
|
|
game.turneffects();
|
|
},
|
|
}
|
|
|
|
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) {
|
|
var roll;
|
|
roll = Math.floor(Math.random() * num);
|
|
return roll;
|
|
}
|
|
|
|
function onein(num) {
|
|
var roll;
|
|
roll = Math.floor(Math.random() * num);
|
|
if (roll == 0) return true;
|
|
return false;
|
|
}
|
|
|
|
function getrandomcolour() {
|
|
var letters = '0123456789ABCDEF';
|
|
var col = '#';
|
|
for (var i = 0; i < 6; i++ ) {
|
|
col += letters[Math.floor(Math.random() * 16)];
|
|
}
|
|
return col;
|
|
}
|
|
|
|
function getrandomname() {
|
|
var letters = '0123456789';
|
|
var name = "";
|
|
for (var i = 0; i < 3; i++ ) {
|
|
name += letters[Math.floor(Math.random() * 10)];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function isonscreen(x,y) {
|
|
if ((x < 0) || (y < 0) || (x >= GRIDW) || (y >= GRIDH)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function gettextw(ctx, text, size) {
|
|
ctx.font = size + "pt " + FONT;
|
|
return ctx.measureText(text).width + 2; // add space for shadow
|
|
}
|
|
|
|
// extra args are gradient
|
|
function shadowtext(ctx, text, size, col, x, y) {
|
|
var i,textcol,gradidx = 0;
|
|
|
|
if (arguments.length > 6) {
|
|
var y1,y2,adjsize,gradinc;
|
|
|
|
adjsize = size*2;
|
|
if (game.context.textBaseline == "top") {
|
|
y1 = y;
|
|
y2 = y + adjsize;
|
|
} else {
|
|
y1 = y - adjsize/2;
|
|
y2 = y + adjsize/2;
|
|
}
|
|
textcol = game.context.createLinearGradient(0, y1, 0, y2);
|
|
|
|
gradinc = 1.0 / (arguments.length - 6-1);
|
|
|
|
for (i = 6 ; i < arguments.length; i ++) {
|
|
textcol.addColorStop(gradidx, arguments[i]);
|
|
|
|
gradidx += gradinc;
|
|
}
|
|
|
|
} else {
|
|
textcol = col;
|
|
}
|
|
|
|
ctx.font = size + "pt " + FONT;
|
|
// shadows
|
|
ctx.fillStyle = "black";
|
|
ctx.fillText(text, x-1, y-1);
|
|
ctx.fillText(text, x+1, y);
|
|
ctx.fillText(text, x+1, y+1);
|
|
ctx.fillText(text, x-1, y+1);
|
|
// real text
|
|
ctx.fillStyle = textcol;
|
|
ctx.fillText(text, x, y);
|
|
}
|
|
|
|
function getrandomtype() {
|
|
var roll,tot,type = null,i;
|
|
var thinglist,maxroll = 0;
|
|
var speciallist = null;
|
|
|
|
if (curlevel >= game.levels.length) {
|
|
thinglist = null;
|
|
} else {
|
|
thinglist = game.levels[curlevel].thinglist;
|
|
}
|
|
|
|
// construct a list of permitted special things
|
|
var poss = [ "sunlight" ] ;
|
|
for (i in poss ) {
|
|
if (!game.isbanned(curlevel, poss[i])) {
|
|
if (speciallist == undefined) {
|
|
speciallist = [];
|
|
}
|
|
speciallist.push(poss[i]);
|
|
}
|
|
}
|
|
|
|
console.log("speciallist is " + speciallist);
|
|
|
|
if (thinglist == undefined || thinglist.length == 0) {
|
|
var f;
|
|
thinglist = new Array();
|
|
|
|
// default thinglist
|
|
// 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 (!game.isbanned(curlevel, 'goat')) thinglist.push({ type: 'goat', pct: 10 } );
|
|
if (!game.isbanned(curlevel, 'llama')) thinglist.push({ type: 'llama', pct: 20 } );
|
|
if (!game.isbanned(curlevel, 'food')) thinglist.push({ type: 'food', pct: 40 } );
|
|
if (!game.isbanned(curlevel, 'cat')) thinglist.push({ type: 'cat', pct: 45 } );
|
|
}
|
|
|
|
for (i = 0; i < thinglist.length; i++) {
|
|
maxroll += thinglist[i].pct;
|
|
//console.log(thinglist[i].type + ": " + thinglist[i].pct + " [" + maxroll + "]");
|
|
|
|
}
|
|
|
|
for (i = 0; i < thinglist.length; i++) {
|
|
console.log(thinglist[i].type + ": " + ((thinglist[i].pct / maxroll)*100) + "% [roll " + maxroll + "/" + maxroll + "]");
|
|
}
|
|
|
|
roll = rnd(maxroll);
|
|
tot = 0;
|
|
for (i = 0; i < thinglist.length; i++) {
|
|
tot += thinglist[i].pct;
|
|
if (roll <= tot) {
|
|
console.log("rolled " + roll + "/" + maxroll + " --> " + thinglist[i].type + " [<= " + tot + "]");
|
|
|
|
type = thinglist[i].type;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (type == null || type == undefined) {
|
|
console.log("couldn't find type! roll is " + roll);
|
|
type = 'cat';
|
|
} else if (type == "special") {
|
|
// pick from list of specials
|
|
type = speciallist[rnd(speciallist.length)];
|
|
}
|
|
return type;
|
|
}
|
|
|
|
function coord(x,y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
function thing(gridx, gridy, type, text) {
|
|
this.opacity = 1.0;
|
|
this.isnew = true;
|
|
|
|
if (type == "random") {
|
|
type = getrandomtype();
|
|
console.log("got random type "+ type);
|
|
}
|
|
// used for various things
|
|
if (type == "sunlight") {
|
|
this.counter = 1;
|
|
} else {
|
|
this.counter = 0;
|
|
}
|
|
|
|
if (type == undefined) {
|
|
console.log("type is now " + type);
|
|
debugger;
|
|
}
|
|
|
|
if (text == undefined) {
|
|
this.name = type + "-" + getrandomname();
|
|
} else {
|
|
this.name = text;
|
|
}
|
|
|
|
this.type = type;
|
|
switch (this.type) {
|
|
case "cat":
|
|
this.color = "#b5dea8";
|
|
break;
|
|
case "food":
|
|
this.color = "#d8db03";
|
|
break;
|
|
case "llama":
|
|
this.color = "#cccccc";
|
|
break;
|
|
case "text":
|
|
if (this.name.indexOf("x") == 0) {
|
|
this.color = "#00dddd";
|
|
} else {
|
|
this.color = "#00cc00";
|
|
}
|
|
break;
|
|
default: // should never happen
|
|
this.color = getrandomcolour();
|
|
break;
|
|
}
|
|
|
|
if (this.type == "text") {
|
|
if (this.name.indexOf("x") == 0) {
|
|
this.size = TEXTSIZEMULTIPLIER;
|
|
} else {
|
|
this.size = TEXTSIZE;
|
|
}
|
|
} else {
|
|
this.size = THINGSIZE;
|
|
}
|
|
this.lifetime = 0;
|
|
|
|
|
|
this.gridx = gridx;
|
|
if (gridy == "top") {
|
|
var i;
|
|
highest = 999;
|
|
// find highest
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((things[i].gridx == gridx) &&
|
|
(things[i].gridy <= highest)) {
|
|
highest = things[i].gridy-1;
|
|
}
|
|
}
|
|
gridy = highest;
|
|
//console.log("adding thing at gridy = " + gridy);
|
|
}
|
|
this.gridy = gridy;
|
|
this.yspeed = 0;
|
|
if (this.type == "text") {
|
|
this.state = "text";
|
|
} else {
|
|
this.state = "stop";
|
|
}
|
|
|
|
this.path = [];
|
|
this.pathspeed = PARADESPEED;
|
|
this.expcount = 0;
|
|
this.expmax = 0;
|
|
this.eaten = false;
|
|
|
|
if (this.type == "text" ) {
|
|
this.x = gridx * GRIDSIZE + (GRIDSIZE/2);
|
|
this.y = gridy * GRIDSIZE + (GRIDSIZE/2) - 10; // TODO: fix to 10!
|
|
} else {
|
|
this.x = gridx * GRIDSIZE + (GRIDSIZE/2) - (this.size/2);
|
|
this.y = gridy * GRIDSIZE + (GRIDSIZE/2) - (this.size/2);
|
|
}
|
|
|
|
|
|
this.issleepy = function() {
|
|
if (this.type == "cat") {
|
|
if (this.eaten == true) {
|
|
return true;
|
|
} else if (isadjacenttotype(this, "sunlight")) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.canfall = function() {
|
|
// doors can't fall after their initial drop
|
|
if (this.type == "door") {
|
|
if ((this.gridy >= 0) && (this.new == false)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
this.pushpath = function(x,y) {
|
|
this.path.push(new coord(x, y));
|
|
}
|
|
|
|
this.poppath = function() {
|
|
this.path.splice(0, 1);
|
|
}
|
|
|
|
// are there any valid moves starting with this thing?
|
|
this.hasvalidmoves = function() {
|
|
var i,newx,newy;
|
|
|
|
if (this.gridy < 0) {
|
|
return false;
|
|
}
|
|
|
|
if (this.isanimating()) {
|
|
return false;
|
|
}
|
|
if (this.type != "cat") {
|
|
return false;
|
|
}
|
|
if (isadjacenttotype(this, "llama")) {
|
|
return false;
|
|
}
|
|
|
|
// chomp
|
|
if (isadjacenttotype(this, "food") && !this.issleepy()) {
|
|
return true;
|
|
}
|
|
|
|
// parade - this is the hardest to check for.
|
|
// check for any adjacent cats or llamas or goats
|
|
// cat: if it also has an adjacent cat/llama/goat, we're good
|
|
// llama: if it also has an adjacent cat/goat, we're good
|
|
for (i = 0; i < MAXDIRS; i++) {
|
|
var adj;
|
|
newx = this.gridx + DIRXMOD[i];
|
|
newy = this.gridy + DIRYMOD[i];
|
|
if (isonscreen(newx, newy)) {
|
|
adj = getgridthing(newx, newy);
|
|
if (adj != undefined) {
|
|
if (adj.type == "cat") {
|
|
// adjacent cat
|
|
if (isadjacenttotype(adj, "llama", this) ||
|
|
isadjacenttotype(adj, "cat", this) ||
|
|
isadjacenttotype(adj, "goat", this)) {
|
|
return true;
|
|
}
|
|
} else if (adj.type == "llama") {
|
|
// adjacent llama
|
|
if (isadjacenttotype(adj, "cat", this) ||
|
|
isadjacenttotype(adj, "goat", this)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
this.givepoints = function() {
|
|
var points = 0;
|
|
if (this.type == "food") {
|
|
points = FOODPOINTS;
|
|
game.progress("food", 1);
|
|
} else if (this.type == "llama") {
|
|
points = LLAMAPOINTS;
|
|
game.progress("llamas", 1);
|
|
} else if (this.type == "cat") {
|
|
if (this.issleepy()) {
|
|
points = SLEEPYCATPOINTS;
|
|
} else {
|
|
points = CATPOINTS;
|
|
}
|
|
game.progress("cats", 1);
|
|
} else if (this.type == "goat") {
|
|
points = GOATPOINTS;
|
|
game.progress("goats", 1);
|
|
}
|
|
|
|
points *= multiplier;
|
|
|
|
if (points > 0) {
|
|
score += points;
|
|
game.progress("points", points);
|
|
|
|
// add animation
|
|
things.push(new thing(this.gridx, this.gridy, "text", "+" + points));
|
|
}
|
|
}
|
|
|
|
|
|
this.getdesc = function() {
|
|
var desc = "";
|
|
if (this.type == "cat") {
|
|
if (isadjacenttotype(this, "llama")) {
|
|
if (this.issleepy() == true) {
|
|
desc = "scared sleepy cat";
|
|
} else {
|
|
desc = "scared cat";
|
|
}
|
|
} else if (this.issleepy() == true) {
|
|
desc = "sleepy cat";
|
|
} else {
|
|
desc = "cat";
|
|
}
|
|
} else if (this.type == "llama") {
|
|
var num;
|
|
num = (Math.floor(game.frameNo / 50)) % 2;
|
|
if (num == 0) {
|
|
desc = "llama";
|
|
} else {
|
|
desc = "alpaca";
|
|
}
|
|
} else if (this.type == "food") {
|
|
desc = "cheese";
|
|
}
|
|
return desc;
|
|
}
|
|
|
|
this.draw = function() {
|
|
var yoff;
|
|
var inpath = false;
|
|
var howbig,myx,myy;
|
|
|
|
//ctx = game.context;
|
|
|
|
// check whether I'm in the drawn path
|
|
if (pathcontains(this)) {
|
|
inpath = true;
|
|
}
|
|
|
|
// set opacity
|
|
if (!wipe.isactive()) {
|
|
ctx.globalAlpha = this.opacity;
|
|
}
|
|
|
|
// draw myself
|
|
if (this.type == "text") {
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
shadowtext(ctx, this.name, this.size, this.color, BOARDX + this.x,BOARDY + this.y);
|
|
} else {
|
|
if (this.type == "cat") {
|
|
var myimage;
|
|
|
|
if (this.state == "parade") {
|
|
myimage = image['cat'];
|
|
} else if (isadjacenttotype(this, "llama")) {
|
|
myimage = image['catscared'];
|
|
} else if (this.issleepy() == true) {
|
|
myimage = image['catfull'];
|
|
} else {
|
|
myimage = image['cat'];
|
|
}
|
|
} else if (this.type == "llama") {
|
|
myimage = image['llama'];
|
|
} else if (this.type == "food") {
|
|
myimage = image['cheese'];
|
|
} else if (this.type == "goat") {
|
|
myimage = image['goat'];
|
|
} else if (this.type == "door") {
|
|
myimage = image['door'];
|
|
} else if (this.type == "sunlight") {
|
|
myimage = image['sunlight'];
|
|
} else {
|
|
console.log("ERROR - no image for type " + this.type);
|
|
console.log(this);
|
|
}
|
|
howbig = this.size;
|
|
myx = this.x;
|
|
myy = this.y;
|
|
if (inpath) {
|
|
var growpct = 50;
|
|
howbig = howbig * ((100+growpct) / 100);
|
|
myx -= (growpct/2/100) * this.size;
|
|
myy -= (growpct/2/100) * this.size;
|
|
}
|
|
|
|
/* hilight non-snapped things
|
|
var snapto = Math.floor((this.gridy * GRIDSIZE) + (GRIDSIZE/2) - (howbig/2));
|
|
if (myy != snapto) {
|
|
console.log("not aligned");
|
|
ctx.fillStyle = "green";
|
|
ctx.fillRect(BOARDX + myx, BOARDY + myy, howbig, howbig);
|
|
}
|
|
*/
|
|
|
|
ctx.drawImage(myimage, BOARDX + myx, BOARDY + myy, howbig, howbig);
|
|
}
|
|
|
|
/*
|
|
} else {
|
|
ctx.fillStyle = this.color;
|
|
ctx.fillRect(BOARDX + this.x, BOARDY + this.y, this.size, this.size);
|
|
}
|
|
*/
|
|
|
|
// frozen cat?
|
|
/*
|
|
if ((this.type == "cat") && !this.isanimating()) {
|
|
if (isadjacenttotype(this, "llama")) {
|
|
// cross out
|
|
ctx.fillStyle = "red";
|
|
ctx.lineWidth = CROSSWIDTH;
|
|
ctx.strokeStyle = "red";
|
|
// NW -> SE
|
|
ctx.beginPath();
|
|
ctx.moveTo(BOARDX + this.x, BOARDY + this.y);
|
|
ctx.lineTo(BOARDX + this.x + this.size - 1, BOARDY + this.y + this.size - 1);
|
|
ctx.stroke();
|
|
|
|
// SW -> NE
|
|
ctx.beginPath();
|
|
ctx.moveTo(BOARDX + this.x, BOARDY + this.y + this.size - 1);
|
|
ctx.lineTo(BOARDX + this.x + this.size - 1, BOARDY + this.y);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
*/
|
|
|
|
// draw text on me
|
|
/*
|
|
if (this.type == "cat") {
|
|
} else if (this.type == "llama") {
|
|
} else {
|
|
ctx.fillStyle = "black";
|
|
ctx.fillText(this.name, BOARDX + this.x + 10, BOARDY + this.y + (THINGSIZE/2));
|
|
ctx.fillText(this.eaten ? "FULL" : "", BOARDX + this.x + 10, BOARDY + this.y + (THINGSIZE/2) + 10);
|
|
}
|
|
*/
|
|
|
|
// back to full opacity
|
|
if (!wipe.isactive()) {
|
|
ctx.globalAlpha = 1.0;
|
|
}
|
|
|
|
/*
|
|
// path outline
|
|
if (inpath && this.state != "parade" && this.state != "explode") {
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 1;
|
|
ctx.fillStyle = "black";
|
|
// outline it
|
|
if (pathvalid) {
|
|
ctx.strokeStyle = "green";
|
|
} else {
|
|
ctx.strokeStyle = "red";
|
|
}
|
|
ctx.rect(BOARDX + this.x, BOARDY + this.y, this.size, this.size);
|
|
ctx.stroke();
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
this.issametype = function(otherthing) {
|
|
if (otherthing == undefined) return false;
|
|
if (otherthing.type == this.type) return true;
|
|
return false;
|
|
}
|
|
|
|
// return TRUE if we did something
|
|
this.snaptogrid = function() {
|
|
var moved = false;
|
|
var snaptox = Math.floor(this.gridx * GRIDSIZE + (GRIDSIZE/2) - (this.size/2));
|
|
var snaptoy = Math.floor(this.gridy * GRIDSIZE + (GRIDSIZE/2) - (this.size/2));
|
|
|
|
if (this.state != "fall" && this.state != "stop") {
|
|
return false;
|
|
}
|
|
|
|
//var snapto = (GRIDSIZE + (GRIDSIZE/2) - (THINGSIZE/2);
|
|
//if (this.y % (GRIDSIZE + (GRIDSIZE/2) - (THINGSIZE/2)) != 0) {
|
|
//if (this.y % snapto != 0) {
|
|
if (this.y != snaptoy) {
|
|
this.y = snaptoy;
|
|
var moved = true;
|
|
}
|
|
if (this.x != snaptox) {
|
|
this.x = snaptox;
|
|
var moved = true;
|
|
}
|
|
|
|
return moved;
|
|
}
|
|
|
|
this.getstoppedbelowthing = function() {
|
|
var bt;
|
|
bt = getgridthing(this.gridx, this.gridy + 1);
|
|
if (bt && bt.state != "fall") {
|
|
return bt;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
this.addabove = function() {
|
|
// add a new cat above us
|
|
things.push(new thing(this.gridx, "top", "random"));
|
|
}
|
|
|
|
this.kill = function() {
|
|
// kill ourselves
|
|
var idx = things.indexOf(this);
|
|
things.splice(idx, 1);
|
|
}
|
|
|
|
this.updatexy = function() {
|
|
this.x = this.gridx * GRIDSIZE + (GRIDSIZE/2) - (THINGSIZE/2);
|
|
this.y = this.gridy * GRIDSIZE + (GRIDSIZE/2) - (THINGSIZE/2);
|
|
}
|
|
|
|
this.setgridxy = function(x,y) {
|
|
this.gridx = x;
|
|
this.gridy = y;
|
|
this.updatexy();
|
|
}
|
|
|
|
this.chomp = function(food) {
|
|
var origgx,origgy;
|
|
// remember cat loc
|
|
origgx = this.gridx;
|
|
origgy = this.gridy;
|
|
|
|
// add new object above cat location
|
|
this.addabove();
|
|
|
|
// move cat to food location
|
|
this.setgridxy(food.gridx,food.gridy);
|
|
|
|
|
|
// move food to cat location (so new object will
|
|
// be added in the correct column.
|
|
//food.setgridxy(origgx, origgy);
|
|
|
|
// make food explode
|
|
//food.addabove();
|
|
//food.kill();
|
|
food.startexplode();
|
|
|
|
// mark that we've eaten something
|
|
this.eaten = true;
|
|
|
|
console.log("chomp");
|
|
}
|
|
|
|
this.isanimating = function() {
|
|
if (this.type == "text") return true;
|
|
if (this.state == "explode") return true;
|
|
if (this.state == "shrink") return true;
|
|
if (this.state == "parade") return true;
|
|
return false;
|
|
}
|
|
|
|
this.startexplode = function() {
|
|
this.expcount=1;
|
|
this.expmax=EXPLODETICKS;
|
|
this.state = "explode";
|
|
}
|
|
|
|
this.startshrink = function() {
|
|
this.expcount=1;
|
|
this.expmax=SHRINKTICKS;
|
|
this.state = "shrink";
|
|
}
|
|
|
|
this.startparade = function() {
|
|
var i,startidx=-1;
|
|
// find our position in the current path
|
|
for (i = 0; i < curpath.length; i++) {
|
|
if (curpath[i] == this) {
|
|
startidx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (startidx == -1) {
|
|
// not in path?!
|
|
return;
|
|
}
|
|
|
|
// populate our own movement path.
|
|
for (i = startidx; i < curpath.length; i++) {
|
|
var nextidx;
|
|
// add waypoint of next cell in selected path
|
|
nextidx = i+1;
|
|
if (nextidx >= curpath.length) {
|
|
var dir;
|
|
if (pathdoor != undefined) {
|
|
// we're at a door. vanish.
|
|
this.pushpath(-1, -1);
|
|
} else {
|
|
// we're at the end. move off the screen in the direction of the path.
|
|
|
|
// find dir from previous to us...
|
|
// don't worry about checking for being the first element cause
|
|
// parades can't be 1 in length;
|
|
dir = getdir(curpath[i-1],curpath[i]);
|
|
this.pushpath(curpath[i].x + (DIRXMOD[dir]*GRIDSIZE*GRIDW),
|
|
curpath[i].y + (DIRYMOD[dir]*GRIDSIZE*GRIDH));
|
|
}
|
|
} else {
|
|
this.pushpath(curpath[nextidx].x, curpath[nextidx].y);
|
|
}
|
|
}
|
|
//console.log("Starting parade: " + this.name + " path len is [" + this.path.length + "]");
|
|
|
|
this.addabove(); // add cat above
|
|
this.state = "parade"; // go to parade mode
|
|
|
|
}
|
|
|
|
this.calcgridxy = function() {
|
|
this.gridx = Math.floor(this.x / GRIDSIZE);
|
|
this.gridy = Math.floor(this.y / GRIDSIZE);
|
|
}
|
|
|
|
this.move = function() {
|
|
// not at bottom and nothing fixed below us?
|
|
var dofall = false;
|
|
var belowthing = null,atbottom = false;
|
|
|
|
if (this.state == "explode") {
|
|
game.dirty = true; // need to redraw
|
|
this.expcount++;
|
|
if (this.expcount >= this.expmax) {
|
|
this.kill();
|
|
} else {
|
|
// get bigger
|
|
this.size += EXPLODEGAIN;
|
|
this.opacity -= EXPLODEFADESPEED;
|
|
|
|
if (this.opacity < 0) this.opacity = 0;
|
|
|
|
// adjust x/y
|
|
this.x = (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2);
|
|
this.y = (this.gridy * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2);
|
|
|
|
}
|
|
} else if (this.type == "text") {
|
|
game.dirty = true; // need to redraw
|
|
// slowly move up
|
|
this.y -= TEXTSPEED;
|
|
this.lifetime++;
|
|
if (this.lifetime >= TEXTTIME) {
|
|
this.opacity -= TEXTFADESPEED;
|
|
if (this.opacity <= 0) {
|
|
this.kill();
|
|
}
|
|
}
|
|
} else if (this.state == "shrink") {
|
|
game.dirty = true; // need to redraw
|
|
this.expcount++;
|
|
if (this.expcount >= this.expmax) {
|
|
this.kill();
|
|
} else {
|
|
// get smaller
|
|
this.size -= SHRINKLOSE;
|
|
|
|
if (this.size < 1) this.size == 1;
|
|
|
|
// adjust x/y
|
|
this.x = (this.gridx * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2);
|
|
this.y = (this.gridy * GRIDSIZE) + (GRIDSIZE/2) - (this.size/2);
|
|
}
|
|
} 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;
|
|
|
|
game.dirty = true; // need to redraw
|
|
|
|
// special case: door.
|
|
if ((nextx == -1) && (nexty == -1)) {
|
|
this.path = [];
|
|
this.startshrink();
|
|
} else {
|
|
if (this.x < nextx) {
|
|
this.x += this.pathspeed;
|
|
if (this.x > nextx) xdone = true;
|
|
} else if (this.x > nextx) {
|
|
this.x -= this.pathspeed;
|
|
if (this.x < nextx) xdone = true;
|
|
} else {
|
|
xdone = true;
|
|
}
|
|
|
|
if (this.y < nexty) {
|
|
this.y += this.pathspeed;
|
|
if (this.y > nexty) ydone = true;
|
|
} else if (this.y > nexty) {
|
|
this.y -= this.pathspeed;
|
|
if (this.y < nexty) ydone = true;
|
|
} else {
|
|
ydone = true;
|
|
}
|
|
|
|
this.calcgridxy();
|
|
|
|
// at destination?
|
|
if (xdone && ydone) {
|
|
this.poppath();
|
|
// path finished?
|
|
if (this.path == undefined || this.path.length == 0) {
|
|
if (this.state == "catparade" ){
|
|
this.kill();
|
|
} else {
|
|
this.state = "stop";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// regular gravity
|
|
if ((this.gridy >= GRIDH-1)) {
|
|
atbottom = true;
|
|
}
|
|
if (!atbottom && !this.getstoppedbelowthing() && this.canfall()) {
|
|
game.dirty = true; // need to redraw
|
|
// accelerate
|
|
this.yspeed += GRAVITY;
|
|
|
|
// move
|
|
this.y += this.yspeed;
|
|
|
|
this.state = "fall";
|
|
|
|
// don't go below bottom of screen
|
|
if (this.y > GRIDSIZE * GRIDH) {
|
|
//this.y = GRIDSIZE * GRIDH;
|
|
atbottom = true;
|
|
this.state = "stop";
|
|
}
|
|
|
|
// calc new gridx / gridy
|
|
this.calcgridxy();
|
|
|
|
if ((this.gridy >= GRIDH-1)) {
|
|
atbottom = true;
|
|
this.state = "stop";
|
|
}
|
|
|
|
}
|
|
|
|
// hit something?
|
|
if (atbottom || this.getstoppedbelowthing()) {
|
|
// something below us.
|
|
|
|
// stop
|
|
this.yspeed = 0;
|
|
|
|
// snap to grid
|
|
if (this.snaptogrid()) {
|
|
game.dirty = true; // need to redraw
|
|
}
|
|
|
|
this.state = "stop";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function mainloop() {
|
|
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
|
|
var i;
|
|
|
|
|
|
requestAnimFrame(mainloop);
|
|
|
|
game.frameNo += 1;
|
|
if (wipe.isactive()) {
|
|
wipe.tick();
|
|
}
|
|
|
|
if (game.state == "title") {
|
|
game.clear();
|
|
game.drawtitle();
|
|
///game.setstate("levselect");
|
|
} else if (game.state == "help") {
|
|
game.clear();
|
|
game.drawhelp();
|
|
} else if (game.state == "levselect") {
|
|
game.clear();
|
|
game.drawlevselect();
|
|
} else if ((game.state == "running") || (game.state == "gameover") || (game.state == "levelcomplete")) {
|
|
var gridalpha = 1.0;
|
|
// move objects
|
|
for (i = 0; i < things.length; i += 1) {
|
|
things[i].move();
|
|
}
|
|
|
|
gridalpha = wipe.getval(1.0, "up", "down", 1.0);
|
|
ctx.globalAlpha = gridalpha;
|
|
if (game.dirty || wipe.isactive()) {
|
|
// clear
|
|
game.clear();
|
|
// draw grid
|
|
game.drawgrid();
|
|
// draw non-animating objects
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (!things[i].isanimating()) {
|
|
things[i].draw();
|
|
}
|
|
}
|
|
// draw animating objects
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].isanimating()) {
|
|
things[i].draw();
|
|
}
|
|
}
|
|
// draw top of canvas (score etc)
|
|
game.drawtop();
|
|
|
|
// draw bottom of canvas (goals)
|
|
game.drawbottom();
|
|
|
|
if ((game.state == "levelcomplete") || (game.state == "gameover")) {
|
|
// draw buttons
|
|
game.drawcontinuebutton();
|
|
}
|
|
|
|
|
|
// draw dragged arrow
|
|
game.drawpath();
|
|
|
|
// flash
|
|
game.drawflash();
|
|
}
|
|
ctx.globalAlpha = 1.0;
|
|
game.dirty = false;
|
|
|
|
if (game.state == "levelcomplete") {
|
|
// make image bigger
|
|
game.zoomwinimg();
|
|
}
|
|
|
|
// check for game over and level over
|
|
if (game.state == "running") {
|
|
if (!thingsmoving()) {
|
|
var i;
|
|
if (pathdoor != undefined) {
|
|
// still a path door needing to be closed/destroyed?
|
|
pathdoor.givepoints();
|
|
pathdoor.addabove();
|
|
pathdoor.startshrink();
|
|
pathdoor = null;
|
|
} else if (levelfinished()) {
|
|
// record score
|
|
if (score > playerdata.levscore[curlevel]) {
|
|
playerdata.setlevscore(curlevel, score);
|
|
}
|
|
|
|
game.setstate("levelcomplete");
|
|
} else if (!anyvalidmoves()) {
|
|
game.setstate("gameover");
|
|
}
|
|
// mark things as not new
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].gridy >= 0) 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 &&
|
|
things[i].state != "swapping" && things[i].counter == 0) {
|
|
if ((things[i].gridy >= GRIDH-1)) {
|
|
// at bottom - disappear
|
|
things[i].addabove();
|
|
things[i].startexplode();
|
|
game.progress("sun cycles", 1);
|
|
} else {
|
|
var thingbelow;
|
|
// move down
|
|
things[i].pushpath(things[i].x, things[i].y + GRIDSIZE);
|
|
things[i].state = "swapping";
|
|
things[i].counter = 1;
|
|
|
|
thingbelow = getgridthing(things[i].gridx, things[i].gridy+1);
|
|
if (thingbelow != undefined && thingbelow.state != "swapping" &&
|
|
thingbelow.type != "sunlight") {
|
|
thingbelow.pushpath(things[i].x, things[i].y);
|
|
thingbelow.state = "swapping";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function levelfinished() {
|
|
var i;
|
|
// past last level!
|
|
if (curlevel >= game.levels.length) return false;
|
|
|
|
for (i = 0 ; i < game.levels[curlevel].goals.length; i++ ) {
|
|
if (game.levels[curlevel].goals[i].progress < game.levels[curlevel].goals[i].count) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function anyvalidmoves() {
|
|
var gotmoves = false;
|
|
var i;
|
|
|
|
if (things == undefined || things.length == 0) return false;
|
|
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].hasvalidmoves()) {
|
|
gotmoves = true;
|
|
break;
|
|
}
|
|
}
|
|
return gotmoves;
|
|
}
|
|
|
|
//<button onmousedown="accelerate(-0.2)" onmouseup="accelerate(0.05)">ACCELERATE</button>
|
|
</script>
|
|
<br>
|
|
</body>
|
|
</html>
|
|
|
|
|