diff --git a/README.md b/README.md index 4204bd2e..3c597aca 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,5 @@ ComunicWeb would not exists without the following technologies developped by the - JSZip (https://github.com/Stuk/jszip.git) (MIT License) - JSZip Utils (https://github.com/Stuk/jszip-utils.git) (MIT License) - SCEditor (BBC WYIWYG editor) (https://github.com/samclarke/SCEditor) (MIT License) -- JavaScript BBCode Parser (https://github.com/Frug/js-bbcode-parser) (MIT License) \ No newline at end of file +- JavaScript BBCode Parser (https://github.com/Frug/js-bbcode-parser) (MIT License) +- Pacman (https://github.com/daleharvey/pacman) (WTFPL License) \ No newline at end of file diff --git a/assets/3rdparty/pacman/BD_Cartoon_Shout-webfont.ttf b/assets/3rdparty/pacman/BD_Cartoon_Shout-webfont.ttf new file mode 100644 index 00000000..c7e60dad Binary files /dev/null and b/assets/3rdparty/pacman/BD_Cartoon_Shout-webfont.ttf differ diff --git a/assets/3rdparty/pacman/LICENSE b/assets/3rdparty/pacman/LICENSE new file mode 100644 index 00000000..07b7a818 --- /dev/null +++ b/assets/3rdparty/pacman/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. \ No newline at end of file diff --git a/assets/3rdparty/pacman/audio/die.mp3 b/assets/3rdparty/pacman/audio/die.mp3 new file mode 100644 index 00000000..57e32c9a Binary files /dev/null and b/assets/3rdparty/pacman/audio/die.mp3 differ diff --git a/assets/3rdparty/pacman/audio/die.ogg b/assets/3rdparty/pacman/audio/die.ogg new file mode 100644 index 00000000..3ffd9599 Binary files /dev/null and b/assets/3rdparty/pacman/audio/die.ogg differ diff --git a/assets/3rdparty/pacman/audio/eatghost.mp3 b/assets/3rdparty/pacman/audio/eatghost.mp3 new file mode 100644 index 00000000..0bccf3b1 Binary files /dev/null and b/assets/3rdparty/pacman/audio/eatghost.mp3 differ diff --git a/assets/3rdparty/pacman/audio/eatghost.ogg b/assets/3rdparty/pacman/audio/eatghost.ogg new file mode 100644 index 00000000..59a60e24 Binary files /dev/null and b/assets/3rdparty/pacman/audio/eatghost.ogg differ diff --git a/assets/3rdparty/pacman/audio/eating.mp3 b/assets/3rdparty/pacman/audio/eating.mp3 new file mode 100644 index 00000000..7630181e Binary files /dev/null and b/assets/3rdparty/pacman/audio/eating.mp3 differ diff --git a/assets/3rdparty/pacman/audio/eating.ogg b/assets/3rdparty/pacman/audio/eating.ogg new file mode 100644 index 00000000..66f6091b Binary files /dev/null and b/assets/3rdparty/pacman/audio/eating.ogg differ diff --git a/assets/3rdparty/pacman/audio/eating.short.mp3 b/assets/3rdparty/pacman/audio/eating.short.mp3 new file mode 100644 index 00000000..240607b8 Binary files /dev/null and b/assets/3rdparty/pacman/audio/eating.short.mp3 differ diff --git a/assets/3rdparty/pacman/audio/eating.short.ogg b/assets/3rdparty/pacman/audio/eating.short.ogg new file mode 100644 index 00000000..32693835 Binary files /dev/null and b/assets/3rdparty/pacman/audio/eating.short.ogg differ diff --git a/assets/3rdparty/pacman/audio/eatpill.mp3 b/assets/3rdparty/pacman/audio/eatpill.mp3 new file mode 100644 index 00000000..8cc8b01d Binary files /dev/null and b/assets/3rdparty/pacman/audio/eatpill.mp3 differ diff --git a/assets/3rdparty/pacman/audio/eatpill.ogg b/assets/3rdparty/pacman/audio/eatpill.ogg new file mode 100644 index 00000000..b65c4cf4 Binary files /dev/null and b/assets/3rdparty/pacman/audio/eatpill.ogg differ diff --git a/assets/3rdparty/pacman/audio/extra lives.mp3 b/assets/3rdparty/pacman/audio/extra lives.mp3 new file mode 100644 index 00000000..6272b242 Binary files /dev/null and b/assets/3rdparty/pacman/audio/extra lives.mp3 differ diff --git a/assets/3rdparty/pacman/audio/extra lives.ogg b/assets/3rdparty/pacman/audio/extra lives.ogg new file mode 100644 index 00000000..b78056da Binary files /dev/null and b/assets/3rdparty/pacman/audio/extra lives.ogg differ diff --git a/assets/3rdparty/pacman/audio/intermission.mp3 b/assets/3rdparty/pacman/audio/intermission.mp3 new file mode 100644 index 00000000..146fe85d Binary files /dev/null and b/assets/3rdparty/pacman/audio/intermission.mp3 differ diff --git a/assets/3rdparty/pacman/audio/intermission.ogg b/assets/3rdparty/pacman/audio/intermission.ogg new file mode 100644 index 00000000..857cd5d1 Binary files /dev/null and b/assets/3rdparty/pacman/audio/intermission.ogg differ diff --git a/assets/3rdparty/pacman/audio/opening_song.mp3 b/assets/3rdparty/pacman/audio/opening_song.mp3 new file mode 100644 index 00000000..f295eb32 Binary files /dev/null and b/assets/3rdparty/pacman/audio/opening_song.mp3 differ diff --git a/assets/3rdparty/pacman/audio/opening_song.ogg b/assets/3rdparty/pacman/audio/opening_song.ogg new file mode 100644 index 00000000..ac62f8ae Binary files /dev/null and b/assets/3rdparty/pacman/audio/opening_song.ogg differ diff --git a/assets/3rdparty/pacman/audio/siren.mp3 b/assets/3rdparty/pacman/audio/siren.mp3 new file mode 100644 index 00000000..061fcc7f Binary files /dev/null and b/assets/3rdparty/pacman/audio/siren.mp3 differ diff --git a/assets/3rdparty/pacman/audio/siren.ogg b/assets/3rdparty/pacman/audio/siren.ogg new file mode 100644 index 00000000..0fe60aad Binary files /dev/null and b/assets/3rdparty/pacman/audio/siren.ogg differ diff --git a/assets/3rdparty/pacman/audio/vcs_90.mp3 b/assets/3rdparty/pacman/audio/vcs_90.mp3 new file mode 100644 index 00000000..226a6240 Binary files /dev/null and b/assets/3rdparty/pacman/audio/vcs_90.mp3 differ diff --git a/assets/3rdparty/pacman/audio/vcs_90.ogg b/assets/3rdparty/pacman/audio/vcs_90.ogg new file mode 100644 index 00000000..86389c3f Binary files /dev/null and b/assets/3rdparty/pacman/audio/vcs_90.ogg differ diff --git a/assets/3rdparty/pacman/index.html b/assets/3rdparty/pacman/index.html new file mode 100644 index 00000000..3e80d225 --- /dev/null +++ b/assets/3rdparty/pacman/index.html @@ -0,0 +1,59 @@ + + + + + HTML5 Pacman + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/assets/3rdparty/pacman/modernizr-1.5.min.js b/assets/3rdparty/pacman/modernizr-1.5.min.js new file mode 100644 index 00000000..a1de3f7e --- /dev/null +++ b/assets/3rdparty/pacman/modernizr-1.5.min.js @@ -0,0 +1,28 @@ +/*! + * Modernizr JavaScript library 1.5 + * http://www.modernizr.com/ + * + * Copyright (c) 2009-2010 Faruk Ates - http://farukat.es/ + * Dual-licensed under the BSD and MIT licenses. + * http://www.modernizr.com/license/ + * + * Featuring major contributions by + * Paul Irish - http://paulirish.com + */ + window.Modernizr=function(i,e,I){function C(a,b){for(var c in a)if(m[a[c]]!==I&&(!b||b(a[c],D)))return true}function r(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1);return!!C([a,"Webkit"+c,"Moz"+c,"O"+c,"ms"+c,"Khtml"+c],b)}function P(){j[E]=function(a){for(var b=0,c=a.length;b7)};d.historymanagement=function(){return!!(i.history&&history.pushState)};d.draganddrop=function(){return u("drag")&&u("dragstart")&&u("dragenter")&&u("dragover")&&u("dragleave")&&u("dragend")&&u("drop")};d.websockets=function(){return"WebSocket"in i};d.rgba=function(){m.cssText="background-color:rgba(150,255,150,.5)";return(""+m.backgroundColor).indexOf("rgba")!==-1};d.hsla=function(){m.cssText="background-color:hsla(120,40%,100%,.5)";return(""+ + m.backgroundColor).indexOf("rgba")!==-1};d.multiplebgs=function(){m.cssText="background:url(//:),url(//:),red url(//:)";return/(url\s*\(.*?){3}/.test(m.background)};d.backgroundsize=function(){return r("backgroundSize")};d.borderimage=function(){return r("borderImage")};d.borderradius=function(){return r("borderRadius","",function(a){return(""+a).indexOf("orderRadius")!==-1})};d.boxshadow=function(){return r("boxShadow")};d.opacity=function(){var a=y.join("opacity:.5;")+"";m.cssText=a;return(""+m.opacity).indexOf("0.5")!== + -1};d.cssanimations=function(){return r("animationName")};d.csscolumns=function(){return r("columnCount")};d.cssgradients=function(){var a=("background-image:"+y.join("gradient(linear,left top,right bottom,from(#9f9),to(white));background-image:")+y.join("linear-gradient(left top,#9f9, white);background-image:")).slice(0,-17);m.cssText=a;return(""+m.backgroundImage).indexOf("gradient")!==-1};d.cssreflections=function(){return r("boxReflect")};d.csstransforms=function(){return!!C(["transformProperty", + "WebkitTransform","MozTransform","OTransform","msTransform"])};d.csstransforms3d=function(){var a=!!C(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);if(a){var b=document.createElement("style"),c=e.createElement("div");b.textContent="@media ("+y.join("transform-3d),(")+"modernizr){#modernizr{height:3px}}";e.getElementsByTagName("head")[0].appendChild(b);c.id="modernizr";s.appendChild(c);a=c.offsetHeight===3;b.parentNode.removeChild(b);c.parentNode.removeChild(c)}return a}; + d.csstransitions=function(){return r("transitionProperty")};d.fontface=function(){var a;if(/*@cc_on@if(@_jscript_version>=5)!@end@*/0)a=true;else{var b=e.createElement("style"),c=e.createElement("span"),h,t=false,g=e.body,o,w;b.textContent="@font-face{font-family:testfont;src:url('data:font/ttf;base64,AAEAAAAMAIAAAwBAT1MvMliohmwAAADMAAAAVmNtYXCp5qrBAAABJAAAANhjdnQgACICiAAAAfwAAAAEZ2FzcP//AAMAAAIAAAAACGdseWYv5OZoAAACCAAAANxoZWFk69bnvwAAAuQAAAA2aGhlYQUJAt8AAAMcAAAAJGhtdHgGDgC4AAADQAAAABRsb2NhAIQAwgAAA1QAAAAMbWF4cABVANgAAANgAAAAIG5hbWUgXduAAAADgAAABPVwb3N03NkzmgAACHgAAAA4AAECBAEsAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAACAAMDAAAAAAAAgAACbwAAAAoAAAAAAAAAAFBmRWQAAAAgqS8DM/8zAFwDMwDNAAAABQAAAAAAAAAAAAMAAAADAAAAHAABAAAAAABGAAMAAQAAAK4ABAAqAAAABgAEAAEAAgAuqQD//wAAAC6pAP///9ZXAwAAAAAAAAACAAAABgBoAAAAAAAvAAEAAAAAAAAAAAAAAAAAAAABAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEACoAAAAGAAQAAQACAC6pAP//AAAALqkA////1lcDAAAAAAAAAAIAAAAiAogAAAAB//8AAgACACIAAAEyAqoAAwAHAC6xAQAvPLIHBADtMrEGBdw8sgMCAO0yALEDAC88sgUEAO0ysgcGAfw8sgECAO0yMxEhESczESMiARDuzMwCqv1WIgJmAAACAFUAAAIRAc0ADwAfAAATFRQWOwEyNj0BNCYrASIGARQGKwEiJj0BNDY7ATIWFX8aIvAiGhoi8CIaAZIoN/43KCg3/jcoAWD0JB4eJPQkHh7++EY2NkbVRjY2RgAAAAABAEH/+QCdAEEACQAANjQ2MzIWFAYjIkEeEA8fHw8QDxwWFhwWAAAAAQAAAAIAAIuYbWpfDzz1AAsEAAAAAADFn9IuAAAAAMWf0i797/8zA4gDMwAAAAgAAgAAAAAAAAABAAADM/8zAFwDx/3v/98DiAABAAAAAAAAAAAAAAAAAAAABQF2ACIAAAAAAVUAAAJmAFUA3QBBAAAAKgAqACoAWgBuAAEAAAAFAFAABwBUAAQAAgAAAAEAAQAAAEAALgADAAMAAAAQAMYAAQAAAAAAAACLAAAAAQAAAAAAAQAhAIsAAQAAAAAAAgAFAKwAAQAAAAAAAwBDALEAAQAAAAAABAAnAPQAAQAAAAAABQAKARsAAQAAAAAABgAmASUAAQAAAAAADgAaAUsAAwABBAkAAAEWAWUAAwABBAkAAQBCAnsAAwABBAkAAgAKAr0AAwABBAkAAwCGAscAAwABBAkABABOA00AAwABBAkABQAUA5sAAwABBAkABgBMA68AAwABBAkADgA0A/tDb3B5cmlnaHQgMjAwOSBieSBEYW5pZWwgSm9obnNvbi4gIFJlbGVhc2VkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgT3BlbiBGb250IExpY2Vuc2UuIEtheWFoIExpIGdseXBocyBhcmUgcmVsZWFzZWQgdW5kZXIgdGhlIEdQTCB2ZXJzaW9uIDMuYmFlYzJhOTJiZmZlNTAzMiAtIHN1YnNldCBvZiBKdXJhTGlnaHRiYWVjMmE5MmJmZmU1MDMyIC0gc3Vic2V0IG9mIEZvbnRGb3JnZSAyLjAgOiBKdXJhIExpZ2h0IDogMjMtMS0yMDA5YmFlYzJhOTJiZmZlNTAzMiAtIHN1YnNldCBvZiBKdXJhIExpZ2h0VmVyc2lvbiAyIGJhZWMyYTkyYmZmZTUwMzIgLSBzdWJzZXQgb2YgSnVyYUxpZ2h0aHR0cDovL3NjcmlwdHMuc2lsLm9yZy9PRkwAQwBvAHAAeQByAGkAZwBoAHQAIAAyADAAMAA5ACAAYgB5ACAARABhAG4AaQBlAGwAIABKAG8AaABuAHMAbwBuAC4AIAAgAFIAZQBsAGUAYQBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAdABlAHIAbQBzACAAbwBmACAAdABoAGUAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUALgAgAEsAYQB5AGEAaAAgAEwAaQAgAGcAbAB5AHAAaABzACAAYQByAGUAIAByAGUAbABlAGEAcwBlAGQAIAB1AG4AZABlAHIAIAB0AGgAZQAgAEcAUABMACAAdgBlAHIAcwBpAG8AbgAgADMALgBiAGEAZQBjADIAYQA5ADIAYgBmAGYAZQA1ADAAMwAyACAALQAgAHMAdQBiAHMAZQB0ACAAbwBmACAASgB1AHIAYQBMAGkAZwBoAHQAYgBhAGUAYwAyAGEAOQAyAGIAZgBmAGUANQAwADMAMgAgAC0AIABzAHUAYgBzAGUAdAAgAG8AZgAgAEYAbwBuAHQARgBvAHIAZwBlACAAMgAuADAAIAA6ACAASgB1AHIAYQAgAEwAaQBnAGgAdAAgADoAIAAyADMALQAxAC0AMgAwADAAOQBiAGEAZQBjADIAYQA5ADIAYgBmAGYAZQA1ADAAMwAyACAALQAgAHMAdQBiAHMAZQB0ACAAbwBmACAASgB1AHIAYQAgAEwAaQBnAGgAdABWAGUAcgBzAGkAbwBuACAAMgAgAGIAYQBlAGMAMgBhADkAMgBiAGYAZgBlADUAMAAzADIAIAAtACAAcwB1AGIAcwBlAHQAIABvAGYAIABKAHUAcgBhAEwAaQBnAGgAdABoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAAAAAgAAAAAAAP+BADMAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAQACAQIAEQt6ZXJva2F5YWhsaQ==')}"; + e.getElementsByTagName("head")[0].appendChild(b);c.setAttribute("style","font:99px _,arial,helvetica;position:absolute;visibility:hidden");if(!g){g=s.appendChild(e.createElement("fontface"));t=true}c.innerHTML="........";c.id="fonttest";g.appendChild(c);h=c.offsetWidth*c.offsetHeight;c.style.font="99px testfont,_,arial,helvetica";a=h!==c.offsetWidth*c.offsetHeight;var v=function(){if(g.parentNode){a=j.fontface=h!==c.offsetWidth*c.offsetHeight;s.className=s.className.replace(/(no-)?fontface\b/,"")+ + (a?" ":" no-")+"fontface"}};setTimeout(v,75);setTimeout(v,150);addEventListener("load",function(){v();(w=true)&&o&&o(a);setTimeout(function(){t||(g=c);g.parentNode.removeChild(g);b.parentNode.removeChild(b)},50)},false)}j._fontfaceready=function(p){w||a?p(a):(o=p)};return a||h!==c.offsetWidth};d.video=function(){var a=e.createElement("video"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('video/ogg; codecs="theora"');b.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"');b.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return b}; + d.audio=function(){var a=e.createElement("audio"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('audio/ogg; codecs="vorbis"');b.mp3=a.canPlayType("audio/mpeg;");b.wav=a.canPlayType('audio/wav; codecs="1"');b.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}return b};d.localStorage=function(){return"localStorage"in i&&i.localStorage!==null};d.sessionStorage=function(){try{return"sessionStorage"in i&&i.sessionStorage!==null}catch(a){return false}};d.webworkers=function(){return!!i.Worker}; + d.applicationCache=function(){var a=i.applicationCache;return!!(a&&typeof a.status!="undefined"&&typeof a.update=="function"&&typeof a.swapCache=="function")};d.svg=function(){return!!e.createElementNS&&!!e.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect};d.smil=function(){return!!e.createElementNS&&/SVG/.test(M.call(e.createElementNS("http://www.w3.org/2000/svg","animate")))};d.svgclippaths=function(){return!!e.createElementNS&&/SVG/.test(M.call(e.createElementNS("http://www.w3.org/2000/svg", + "clipPath")))};for(var z in d)if(O(d,z))N.push(((j[z.toLowerCase()]=d[z]())?"":"no-")+z.toLowerCase());j[E]||P();j.addTest=function(a,b){a=a.toLowerCase();if(!j[a]){b=!!b();s.className+=" "+(b?"":"no-")+a;j[a]=b;return j}};m.cssText="";D=n=null;(function(){var a=e.createElement("div");a.innerHTML="";return a.childNodes.length!==1})()&&function(a,b){function c(f,k){if(o[f])o[f].styleSheet.cssText+=k;else{var l=t[G],q=b[A]("style");q.media=f;l.insertBefore(q,l[G]);o[f]=q;c(f,k)}}function h(f, + k){for(var l=new RegExp("\\b("+w+")\\b(?!.*[;}])","gi"),q=function(B){return".iepp_"+B},x=-1;++x\\s*$","i");g.innerHTML=f.outerHTML.replace(/\r|\n/g," ").replace(l,f.currentStyle.display=="block"?"":"");l=g.childNodes[0];l.className+=" iepp_"+q;l=p[p.length]=[f,l];f.parentNode.replaceChild(l[1],l[0])}h(b.styleSheets,"all")});a.attachEvent("onafterprint", + function(){for(var f=-1,k;++f 10) { + return x1 + (10 - rem); + } else if(rem > 0 && result < 0) { + return x1 - rem; + } + return x1 + x2; + }; + + function isVunerable() { + return eatable !== null; + }; + + function isDangerous() { + return eaten === null; + }; + + function isHidden() { + return eatable === null && eaten !== null; + }; + + function getRandomDirection() { + var moves = (direction === LEFT || direction === RIGHT) + ? [UP, DOWN] : [LEFT, RIGHT]; + return moves[Math.floor(Math.random() * 2)]; + }; + + function reset() { + eaten = null; + eatable = null; + position = {"x": 90, "y": 80}; + direction = getRandomDirection(); + due = getRandomDirection(); + }; + + function onWholeSquare(x) { + return x % 10 === 0; + }; + + function oppositeDirection(dir) { + return dir === LEFT && RIGHT || + dir === RIGHT && LEFT || + dir === UP && DOWN || UP; + }; + + function makeEatable() { + direction = oppositeDirection(direction); + eatable = game.getTick(); + }; + + function eat() { + eatable = null; + eaten = game.getTick(); + }; + + function pointToCoord(x) { + return Math.round(x / 10); + }; + + function nextSquare(x, dir) { + var rem = x % 10; + if (rem === 0) { + return x; + } else if (dir === RIGHT || dir === DOWN) { + return x + (10 - rem); + } else { + return x - rem; + } + }; + + function onGridSquare(pos) { + return onWholeSquare(pos.y) && onWholeSquare(pos.x); + }; + + function secondsAgo(tick) { + return (game.getTick() - tick) / Pacman.FPS; + }; + + function getColour() { + if (eatable) { + if (secondsAgo(eatable) > 5) { + return game.getTick() % 20 > 10 ? "#FFFFFF" : "#0000BB"; + } else { + return "#0000BB"; + } + } else if(eaten) { + return "#222"; + } + return colour; + }; + + function draw(ctx) { + + var s = map.blockSize, + top = (position.y/10) * s, + left = (position.x/10) * s; + + if (eatable && secondsAgo(eatable) > 8) { + eatable = null; + } + + if (eaten && secondsAgo(eaten) > 3) { + eaten = null; + } + + var tl = left + s; + var base = top + s - 3; + var inc = s / 10; + + var high = game.getTick() % 10 > 5 ? 3 : -3; + var low = game.getTick() % 10 > 5 ? -3 : 3; + + ctx.fillStyle = getColour(); + ctx.beginPath(); + + ctx.moveTo(left, base); + + ctx.quadraticCurveTo(left, top, left + (s/2), top); + ctx.quadraticCurveTo(left + s, top, left+s, base); + + // Wavy things at the bottom + ctx.quadraticCurveTo(tl-(inc*1), base+high, tl - (inc * 2), base); + ctx.quadraticCurveTo(tl-(inc*3), base+low, tl - (inc * 4), base); + ctx.quadraticCurveTo(tl-(inc*5), base+high, tl - (inc * 6), base); + ctx.quadraticCurveTo(tl-(inc*7), base+low, tl - (inc * 8), base); + ctx.quadraticCurveTo(tl-(inc*9), base+high, tl - (inc * 10), base); + + ctx.closePath(); + ctx.fill(); + + ctx.beginPath(); + ctx.fillStyle = "#FFF"; + ctx.arc(left + 6,top + 6, s / 6, 0, 300, false); + ctx.arc((left + s) - 6,top + 6, s / 6, 0, 300, false); + ctx.closePath(); + ctx.fill(); + + var f = s / 12; + var off = {}; + off[RIGHT] = [f, 0]; + off[LEFT] = [-f, 0]; + off[UP] = [0, -f]; + off[DOWN] = [0, f]; + + ctx.beginPath(); + ctx.fillStyle = "#000"; + ctx.arc(left+6+off[direction][0], top+6+off[direction][1], + s / 15, 0, 300, false); + ctx.arc((left+s)-6+off[direction][0], top+6+off[direction][1], + s / 15, 0, 300, false); + ctx.closePath(); + ctx.fill(); + + }; + + function pane(pos) { + + if (pos.y === 100 && pos.x >= 190 && direction === RIGHT) { + return {"y": 100, "x": -10}; + } + + if (pos.y === 100 && pos.x <= -10 && direction === LEFT) { + return position = {"y": 100, "x": 190}; + } + + return false; + }; + + function move(ctx) { + + var oldPos = position, + onGrid = onGridSquare(position), + npos = null; + + if (due !== direction) { + + npos = getNewCoord(due, position); + + if (onGrid && + map.isFloorSpace({ + "y":pointToCoord(nextSquare(npos.y, due)), + "x":pointToCoord(nextSquare(npos.x, due))})) { + direction = due; + } else { + npos = null; + } + } + + if (npos === null) { + npos = getNewCoord(direction, position); + } + + if (onGrid && + map.isWallSpace({ + "y" : pointToCoord(nextSquare(npos.y, direction)), + "x" : pointToCoord(nextSquare(npos.x, direction)) + })) { + + due = getRandomDirection(); + return move(ctx); + } + + position = npos; + + var tmp = pane(position); + if (tmp) { + position = tmp; + } + + due = getRandomDirection(); + + return { + "new" : position, + "old" : oldPos + }; + }; + + return { + "eat" : eat, + "isVunerable" : isVunerable, + "isDangerous" : isDangerous, + "makeEatable" : makeEatable, + "reset" : reset, + "move" : move, + "draw" : draw + }; +}; + +Pacman.User = function (game, map) { + + var position = null, + direction = null, + eaten = null, + due = null, + lives = null, + score = 5, + keyMap = {}; + + keyMap[KEY.ARROW_LEFT] = LEFT; + keyMap[KEY.ARROW_UP] = UP; + keyMap[KEY.ARROW_RIGHT] = RIGHT; + keyMap[KEY.ARROW_DOWN] = DOWN; + + function addScore(nScore) { + score += nScore; + if (score >= 10000 && score - nScore < 10000) { + lives += 1; + } + }; + + function theScore() { + return score; + }; + + function loseLife() { + lives -= 1; + }; + + function getLives() { + return lives; + }; + + function initUser() { + score = 0; + lives = 3; + newLevel(); + } + + function newLevel() { + resetPosition(); + eaten = 0; + }; + + function resetPosition() { + position = {"x": 90, "y": 120}; + direction = LEFT; + due = LEFT; + }; + + function reset() { + initUser(); + resetPosition(); + }; + + function keyDown(e) { + if (typeof keyMap[e.keyCode] !== "undefined") { + due = keyMap[e.keyCode]; + e.preventDefault(); + e.stopPropagation(); + return false; + } + return true; + }; + + function getNewCoord(dir, current) { + return { + "x": current.x + (dir === LEFT && -2 || dir === RIGHT && 2 || 0), + "y": current.y + (dir === DOWN && 2 || dir === UP && -2 || 0) + }; + }; + + function onWholeSquare(x) { + return x % 10 === 0; + }; + + function pointToCoord(x) { + return Math.round(x/10); + }; + + function nextSquare(x, dir) { + var rem = x % 10; + if (rem === 0) { + return x; + } else if (dir === RIGHT || dir === DOWN) { + return x + (10 - rem); + } else { + return x - rem; + } + }; + + function next(pos, dir) { + return { + "y" : pointToCoord(nextSquare(pos.y, dir)), + "x" : pointToCoord(nextSquare(pos.x, dir)), + }; + }; + + function onGridSquare(pos) { + return onWholeSquare(pos.y) && onWholeSquare(pos.x); + }; + + function isOnSamePlane(due, dir) { + return ((due === LEFT || due === RIGHT) && + (dir === LEFT || dir === RIGHT)) || + ((due === UP || due === DOWN) && + (dir === UP || dir === DOWN)); + }; + + function move(ctx) { + + var npos = null, + nextWhole = null, + oldPosition = position, + block = null; + + if (due !== direction) { + npos = getNewCoord(due, position); + + if (isOnSamePlane(due, direction) || + (onGridSquare(position) && + map.isFloorSpace(next(npos, due)))) { + direction = due; + } else { + npos = null; + } + } + + if (npos === null) { + npos = getNewCoord(direction, position); + } + + if (onGridSquare(position) && map.isWallSpace(next(npos, direction))) { + direction = NONE; + } + + if (direction === NONE) { + return {"new" : position, "old" : position}; + } + + if (npos.y === 100 && npos.x >= 190 && direction === RIGHT) { + npos = {"y": 100, "x": -10}; + } + + if (npos.y === 100 && npos.x <= -12 && direction === LEFT) { + npos = {"y": 100, "x": 190}; + } + + position = npos; + nextWhole = next(position, direction); + + block = map.block(nextWhole); + + if ((isMidSquare(position.y) || isMidSquare(position.x)) && + block === Pacman.BISCUIT || block === Pacman.PILL) { + + map.setBlock(nextWhole, Pacman.EMPTY); + addScore((block === Pacman.BISCUIT) ? 10 : 50); + eaten += 1; + + if (eaten === 182) { + game.completedLevel(); + } + + if (block === Pacman.PILL) { + game.eatenPill(); + } + } + + return { + "new" : position, + "old" : oldPosition + }; + }; + + function isMidSquare(x) { + var rem = x % 10; + return rem > 3 || rem < 7; + }; + + function calcAngle(dir, pos) { + if (dir == RIGHT && (pos.x % 10 < 5)) { + return {"start":0.25, "end":1.75, "direction": false}; + } else if (dir === DOWN && (pos.y % 10 < 5)) { + return {"start":0.75, "end":2.25, "direction": false}; + } else if (dir === UP && (pos.y % 10 < 5)) { + return {"start":1.25, "end":1.75, "direction": true}; + } else if (dir === LEFT && (pos.x % 10 < 5)) { + return {"start":0.75, "end":1.25, "direction": true}; + } + return {"start":0, "end":2, "direction": false}; + }; + + function drawDead(ctx, amount) { + + var size = map.blockSize, + half = size / 2; + + if (amount >= 1) { + return; + } + + ctx.fillStyle = "#FFFF00"; + ctx.beginPath(); + ctx.moveTo(((position.x/10) * size) + half, + ((position.y/10) * size) + half); + + ctx.arc(((position.x/10) * size) + half, + ((position.y/10) * size) + half, + half, 0, Math.PI * 2 * amount, true); + + ctx.fill(); + }; + + function draw(ctx) { + + var s = map.blockSize, + angle = calcAngle(direction, position); + + ctx.fillStyle = "#FFFF00"; + + ctx.beginPath(); + + ctx.moveTo(((position.x/10) * s) + s / 2, + ((position.y/10) * s) + s / 2); + + ctx.arc(((position.x/10) * s) + s / 2, + ((position.y/10) * s) + s / 2, + s / 2, Math.PI * angle.start, + Math.PI * angle.end, angle.direction); + + ctx.fill(); + }; + + initUser(); + + return { + "draw" : draw, + "drawDead" : drawDead, + "loseLife" : loseLife, + "getLives" : getLives, + "score" : score, + "addScore" : addScore, + "theScore" : theScore, + "keyDown" : keyDown, + "move" : move, + "newLevel" : newLevel, + "reset" : reset, + "resetPosition" : resetPosition + }; +}; + +Pacman.Map = function (size) { + + var height = null, + width = null, + blockSize = size, + pillSize = 0, + map = null; + + function withinBounds(y, x) { + return y >= 0 && y < height && x >= 0 && x < width; + } + + function isWall(pos) { + return withinBounds(pos.y, pos.x) && map[pos.y][pos.x] === Pacman.WALL; + } + + function isFloorSpace(pos) { + if (!withinBounds(pos.y, pos.x)) { + return false; + } + var peice = map[pos.y][pos.x]; + return peice === Pacman.EMPTY || + peice === Pacman.BISCUIT || + peice === Pacman.PILL; + } + + function drawWall(ctx) { + + var i, j, p, line; + + ctx.strokeStyle = "#0000FF"; + ctx.lineWidth = 5; + ctx.lineCap = "round"; + + for (i = 0; i < Pacman.WALLS.length; i += 1) { + line = Pacman.WALLS[i]; + ctx.beginPath(); + + for (j = 0; j < line.length; j += 1) { + + p = line[j]; + + if (p.move) { + ctx.moveTo(p.move[0] * blockSize, p.move[1] * blockSize); + } else if (p.line) { + ctx.lineTo(p.line[0] * blockSize, p.line[1] * blockSize); + } else if (p.curve) { + ctx.quadraticCurveTo(p.curve[0] * blockSize, + p.curve[1] * blockSize, + p.curve[2] * blockSize, + p.curve[3] * blockSize); + } + } + ctx.stroke(); + } + } + + function reset() { + map = cloneObj(Pacman.MAP); + height = map.length; + width = map[0].length; + }; + + function block(pos) { + return map[pos.y][pos.x]; + }; + + function setBlock(pos, type) { + map[pos.y][pos.x] = type; + }; + + function drawPills(ctx) { + + if (++pillSize > 30) { + pillSize = 0; + } + + for (i = 0; i < height; i += 1) { + for (j = 0; j < width; j += 1) { + if (map[i][j] === Pacman.PILL) { + ctx.beginPath(); + + ctx.fillStyle = "#000"; + ctx.fillRect((j * blockSize), (i * blockSize), + blockSize, blockSize); + + ctx.fillStyle = "#FFF"; + ctx.arc((j * blockSize) + blockSize / 2, + (i * blockSize) + blockSize / 2, + Math.abs(5 - (pillSize/3)), + 0, + Math.PI * 2, false); + ctx.fill(); + ctx.closePath(); + } + } + } + }; + + function draw(ctx) { + + var i, j, size = blockSize; + + ctx.fillStyle = "#000"; + ctx.fillRect(0, 0, width * size, height * size); + + drawWall(ctx); + + for (i = 0; i < height; i += 1) { + for (j = 0; j < width; j += 1) { + drawBlock(i, j, ctx); + } + } + }; + + function drawBlock(y, x, ctx) { + + var layout = map[y][x]; + + if (layout === Pacman.PILL) { + return; + } + + ctx.beginPath(); + + if (layout === Pacman.EMPTY || layout === Pacman.BLOCK || + layout === Pacman.BISCUIT) { + + ctx.fillStyle = "#000"; + ctx.fillRect((x * blockSize), (y * blockSize), + blockSize, blockSize); + + if (layout === Pacman.BISCUIT) { + ctx.fillStyle = "#FFF"; + ctx.fillRect((x * blockSize) + (blockSize / 2.5), + (y * blockSize) + (blockSize / 2.5), + blockSize / 6, blockSize / 6); + } + } + ctx.closePath(); + }; + + reset(); + + return { + "draw" : draw, + "drawBlock" : drawBlock, + "drawPills" : drawPills, + "block" : block, + "setBlock" : setBlock, + "reset" : reset, + "isWallSpace" : isWall, + "isFloorSpace" : isFloorSpace, + "height" : height, + "width" : width, + "blockSize" : blockSize + }; +}; + +Pacman.Audio = function(game) { + + var files = [], + endEvents = [], + progressEvents = [], + playing = []; + + function load(name, path, cb) { + + var f = files[name] = document.createElement("audio"); + + progressEvents[name] = function(event) { progress(event, name, cb); }; + + f.addEventListener("canplaythrough", progressEvents[name], true); + f.setAttribute("preload", "true"); + f.setAttribute("autobuffer", "true"); + f.setAttribute("src", path); + f.pause(); + }; + + function progress(event, name, callback) { + if (event.loaded === event.total && typeof callback === "function") { + callback(); + files[name].removeEventListener("canplaythrough", + progressEvents[name], true); + } + }; + + function disableSound() { + for (var i = 0; i < playing.length; i++) { + files[playing[i]].pause(); + files[playing[i]].currentTime = 0; + } + playing = []; + }; + + function ended(name) { + + var i, tmp = [], found = false; + + files[name].removeEventListener("ended", endEvents[name], true); + + for (i = 0; i < playing.length; i++) { + if (!found && playing[i]) { + found = true; + } else { + tmp.push(playing[i]); + } + } + playing = tmp; + }; + + function play(name) { + if (!game.soundDisabled()) { + endEvents[name] = function() { ended(name); }; + playing.push(name); + files[name].addEventListener("ended", endEvents[name], true); + files[name].play(); + } + }; + + function pause() { + for (var i = 0; i < playing.length; i++) { + files[playing[i]].pause(); + } + }; + + function resume() { + for (var i = 0; i < playing.length; i++) { + files[playing[i]].play(); + } + }; + + return { + "disableSound" : disableSound, + "load" : load, + "play" : play, + "pause" : pause, + "resume" : resume + }; +}; + +var PACMAN = (function () { + + var state = WAITING, + audio = null, + ghosts = [], + ghostSpecs = ["#00FFDE", "#FF0000", "#FFB8DE", "#FFB847"], + eatenCount = 0, + level = 0, + tick = 0, + ghostPos, userPos, + stateChanged = true, + timerStart = null, + lastTime = 0, + ctx = null, + timer = null, + map = null, + user = null, + stored = null; + + function getTick() { + return tick; + }; + + function drawScore(text, position) { + ctx.fillStyle = "#FFFFFF"; + ctx.font = "12px BDCartoonShoutRegular"; + ctx.fillText(text, + (position["new"]["x"] / 10) * map.blockSize, + ((position["new"]["y"] + 5) / 10) * map.blockSize); + } + + function dialog(text) { + ctx.fillStyle = "#FFFF00"; + ctx.font = "14px BDCartoonShoutRegular"; + var width = ctx.measureText(text).width, + x = ((map.width * map.blockSize) - width) / 2; + ctx.fillText(text, x, (map.height * 10) + 8); + } + + function soundDisabled() { + return localStorage["soundDisabled"] === "true"; + }; + + function startLevel() { + user.resetPosition(); + for (var i = 0; i < ghosts.length; i += 1) { + ghosts[i].reset(); + } + audio.play("start"); + timerStart = tick; + setState(COUNTDOWN); + } + + function startNewGame() { + setState(WAITING); + level = 1; + user.reset(); + map.reset(); + map.draw(ctx); + startLevel(); + } + + function keyDown(e) { + if (e.keyCode === KEY.N) { + startNewGame(); + } else if (e.keyCode === KEY.S) { + audio.disableSound(); + localStorage["soundDisabled"] = !soundDisabled(); + } else if (e.keyCode === KEY.P && state === PAUSE) { + audio.resume(); + map.draw(ctx); + setState(stored); + } else if (e.keyCode === KEY.P) { + stored = state; + setState(PAUSE); + audio.pause(); + map.draw(ctx); + dialog("Paused"); + } else if (state !== PAUSE) { + return user.keyDown(e); + } + return true; + } + + function loseLife() { + setState(WAITING); + user.loseLife(); + if (user.getLives() > 0) { + startLevel(); + } + } + + function setState(nState) { + state = nState; + stateChanged = true; + }; + + function collided(user, ghost) { + return (Math.sqrt(Math.pow(ghost.x - user.x, 2) + + Math.pow(ghost.y - user.y, 2))) < 10; + }; + + function drawFooter() { + + var topLeft = (map.height * map.blockSize), + textBase = topLeft + 17; + + ctx.fillStyle = "#000000"; + ctx.fillRect(0, topLeft, (map.width * map.blockSize), 30); + + ctx.fillStyle = "#FFFF00"; + + for (var i = 0, len = user.getLives(); i < len; i++) { + ctx.fillStyle = "#FFFF00"; + ctx.beginPath(); + ctx.moveTo(150 + (25 * i) + map.blockSize / 2, + (topLeft+1) + map.blockSize / 2); + + ctx.arc(150 + (25 * i) + map.blockSize / 2, + (topLeft+1) + map.blockSize / 2, + map.blockSize / 2, Math.PI * 0.25, Math.PI * 1.75, false); + ctx.fill(); + } + + ctx.fillStyle = !soundDisabled() ? "#00FF00" : "#FF0000"; + ctx.font = "bold 16px sans-serif"; + //ctx.fillText("♪", 10, textBase); + ctx.fillText("s", 10, textBase); + + ctx.fillStyle = "#FFFF00"; + ctx.font = "14px BDCartoonShoutRegular"; + ctx.fillText("Score: " + user.theScore(), 30, textBase); + ctx.fillText("Level: " + level, 260, textBase); + } + + function redrawBlock(pos) { + map.drawBlock(Math.floor(pos.y/10), Math.floor(pos.x/10), ctx); + map.drawBlock(Math.ceil(pos.y/10), Math.ceil(pos.x/10), ctx); + } + + function mainDraw() { + + var diff, u, i, len, nScore; + + ghostPos = []; + + for (i = 0, len = ghosts.length; i < len; i += 1) { + ghostPos.push(ghosts[i].move(ctx)); + } + u = user.move(ctx); + + for (i = 0, len = ghosts.length; i < len; i += 1) { + redrawBlock(ghostPos[i].old); + } + redrawBlock(u.old); + + for (i = 0, len = ghosts.length; i < len; i += 1) { + ghosts[i].draw(ctx); + } + user.draw(ctx); + + userPos = u["new"]; + + for (i = 0, len = ghosts.length; i < len; i += 1) { + if (collided(userPos, ghostPos[i]["new"])) { + if (ghosts[i].isVunerable()) { + audio.play("eatghost"); + ghosts[i].eat(); + eatenCount += 1; + nScore = eatenCount * 50; + drawScore(nScore, ghostPos[i]); + user.addScore(nScore); + setState(EATEN_PAUSE); + timerStart = tick; + } else if (ghosts[i].isDangerous()) { + audio.play("die"); + setState(DYING); + timerStart = tick; + } + } + } + }; + + function mainLoop() { + + var diff; + + if (state !== PAUSE) { + ++tick; + } + + map.drawPills(ctx); + + if (state === PLAYING) { + mainDraw(); + } else if (state === WAITING && stateChanged) { + stateChanged = false; + map.draw(ctx); + dialog("Press N to start a New game"); + } else if (state === EATEN_PAUSE && + (tick - timerStart) > (Pacman.FPS / 3)) { + map.draw(ctx); + setState(PLAYING); + } else if (state === DYING) { + if (tick - timerStart > (Pacman.FPS * 2)) { + loseLife(); + } else { + redrawBlock(userPos); + for (i = 0, len = ghosts.length; i < len; i += 1) { + redrawBlock(ghostPos[i].old); + ghostPos.push(ghosts[i].draw(ctx)); + } + user.drawDead(ctx, (tick - timerStart) / (Pacman.FPS * 2)); + } + } else if (state === COUNTDOWN) { + + diff = 5 + Math.floor((timerStart - tick) / Pacman.FPS); + + if (diff === 0) { + map.draw(ctx); + setState(PLAYING); + } else { + if (diff !== lastTime) { + lastTime = diff; + map.draw(ctx); + dialog("Starting in: " + diff); + } + } + } + + drawFooter(); + } + + function eatenPill() { + audio.play("eatpill"); + timerStart = tick; + eatenCount = 0; + for (i = 0; i < ghosts.length; i += 1) { + ghosts[i].makeEatable(ctx); + } + }; + + function completedLevel() { + setState(WAITING); + level += 1; + map.reset(); + user.newLevel(); + startLevel(); + }; + + function keyPress(e) { + if (state !== WAITING && state !== PAUSE) { + e.preventDefault(); + e.stopPropagation(); + } + }; + + function init(wrapper, root) { + + var i, len, ghost, + blockSize = wrapper.offsetWidth / 19, + canvas = document.createElement("canvas"); + + canvas.setAttribute("width", (blockSize * 19) + "px"); + canvas.setAttribute("height", (blockSize * 22) + 30 + "px"); + + wrapper.appendChild(canvas); + + ctx = canvas.getContext('2d'); + + audio = new Pacman.Audio({"soundDisabled":soundDisabled}); + map = new Pacman.Map(blockSize); + user = new Pacman.User({ + "completedLevel" : completedLevel, + "eatenPill" : eatenPill + }, map); + + for (i = 0, len = ghostSpecs.length; i < len; i += 1) { + ghost = new Pacman.Ghost({"getTick":getTick}, map, ghostSpecs[i]); + ghosts.push(ghost); + } + + map.draw(ctx); + dialog("Loading ..."); + + var extension = Modernizr.audio.ogg ? 'ogg' : 'mp3'; + + var audio_files = [ + ["start", root + "audio/opening_song." + extension], + ["die", root + "audio/die." + extension], + ["eatghost", root + "audio/eatghost." + extension], + ["eatpill", root + "audio/eatpill." + extension], + ["eating", root + "audio/eating.short." + extension], + ["eating2", root + "audio/eating.short." + extension] + ]; + + load(audio_files, function() { loaded(); }); + }; + + function load(arr, callback) { + + if (arr.length === 0) { + callback(); + } else { + var x = arr.pop(); + audio.load(x[0], x[1], function() { load(arr, callback); }); + } + }; + + function loaded() { + + dialog("Press N to Start"); + + document.addEventListener("keydown", keyDown, true); + document.addEventListener("keypress", keyPress, true); + + timer = window.setInterval(mainLoop, 1000 / Pacman.FPS); + }; + + return { + "init" : init + }; + +}()); + +/* Human readable keyCode index */ +var KEY = {'BACKSPACE': 8, 'TAB': 9, 'NUM_PAD_CLEAR': 12, 'ENTER': 13, 'SHIFT': 16, 'CTRL': 17, 'ALT': 18, 'PAUSE': 19, 'CAPS_LOCK': 20, 'ESCAPE': 27, 'SPACEBAR': 32, 'PAGE_UP': 33, 'PAGE_DOWN': 34, 'END': 35, 'HOME': 36, 'ARROW_LEFT': 37, 'ARROW_UP': 38, 'ARROW_RIGHT': 39, 'ARROW_DOWN': 40, 'PRINT_SCREEN': 44, 'INSERT': 45, 'DELETE': 46, 'SEMICOLON': 59, 'WINDOWS_LEFT': 91, 'WINDOWS_RIGHT': 92, 'SELECT': 93, 'NUM_PAD_ASTERISK': 106, 'NUM_PAD_PLUS_SIGN': 107, 'NUM_PAD_HYPHEN-MINUS': 109, 'NUM_PAD_FULL_STOP': 110, 'NUM_PAD_SOLIDUS': 111, 'NUM_LOCK': 144, 'SCROLL_LOCK': 145, 'SEMICOLON': 186, 'EQUALS_SIGN': 187, 'COMMA': 188, 'HYPHEN-MINUS': 189, 'FULL_STOP': 190, 'SOLIDUS': 191, 'GRAVE_ACCENT': 192, 'LEFT_SQUARE_BRACKET': 219, 'REVERSE_SOLIDUS': 220, 'RIGHT_SQUARE_BRACKET': 221, 'APOSTROPHE': 222}; + +(function () { + /* 0 - 9 */ + for (var i = 48; i <= 57; i++) { + KEY['' + (i - 48)] = i; + } + /* A - Z */ + for (i = 65; i <= 90; i++) { + KEY['' + String.fromCharCode(i)] = i; + } + /* NUM_PAD_0 - NUM_PAD_9 */ + for (i = 96; i <= 105; i++) { + KEY['NUM_PAD_' + (i - 96)] = i; + } + /* F1 - F12 */ + for (i = 112; i <= 123; i++) { + KEY['F' + (i - 112 + 1)] = i; + } +})(); + +Pacman.WALL = 0; +Pacman.BISCUIT = 1; +Pacman.EMPTY = 2; +Pacman.BLOCK = 3; +Pacman.PILL = 4; + +Pacman.MAP = [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 4, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 4, 0], + [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], + [2, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 2], + [0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0], + [2, 2, 2, 2, 1, 1, 1, 0, 3, 3, 3, 0, 1, 1, 1, 2, 2, 2, 2], + [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], + [2, 2, 2, 0, 1, 0, 1, 1, 1, 2, 1, 1, 1, 0, 1, 0, 2, 2, 2], + [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0], + [0, 4, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4, 0], + [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0], + [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +]; + +Pacman.WALLS = [ + + [{"move": [0, 9.5]}, {"line": [3, 9.5]}, + {"curve": [3.5, 9.5, 3.5, 9]}, {"line": [3.5, 8]}, + {"curve": [3.5, 7.5, 3, 7.5]}, {"line": [1, 7.5]}, + {"curve": [0.5, 7.5, 0.5, 7]}, {"line": [0.5, 1]}, + {"curve": [0.5, 0.5, 1, 0.5]}, {"line": [9, 0.5]}, + {"curve": [9.5, 0.5, 9.5, 1]}, {"line": [9.5, 3.5]}], + + [{"move": [9.5, 1]}, + {"curve": [9.5, 0.5, 10, 0.5]}, {"line": [18, 0.5]}, + {"curve": [18.5, 0.5, 18.5, 1]}, {"line": [18.5, 7]}, + {"curve": [18.5, 7.5, 18, 7.5]}, {"line": [16, 7.5]}, + {"curve": [15.5, 7.5, 15.5, 8]}, {"line": [15.5, 9]}, + {"curve": [15.5, 9.5, 16, 9.5]}, {"line": [19, 9.5]}], + + [{"move": [2.5, 5.5]}, {"line": [3.5, 5.5]}], + + [{"move": [3, 2.5]}, + {"curve": [3.5, 2.5, 3.5, 3]}, + {"curve": [3.5, 3.5, 3, 3.5]}, + {"curve": [2.5, 3.5, 2.5, 3]}, + {"curve": [2.5, 2.5, 3, 2.5]}], + + [{"move": [15.5, 5.5]}, {"line": [16.5, 5.5]}], + + [{"move": [16, 2.5]}, {"curve": [16.5, 2.5, 16.5, 3]}, + {"curve": [16.5, 3.5, 16, 3.5]}, {"curve": [15.5, 3.5, 15.5, 3]}, + {"curve": [15.5, 2.5, 16, 2.5]}], + + [{"move": [6, 2.5]}, {"line": [7, 2.5]}, {"curve": [7.5, 2.5, 7.5, 3]}, + {"curve": [7.5, 3.5, 7, 3.5]}, {"line": [6, 3.5]}, + {"curve": [5.5, 3.5, 5.5, 3]}, {"curve": [5.5, 2.5, 6, 2.5]}], + + [{"move": [12, 2.5]}, {"line": [13, 2.5]}, {"curve": [13.5, 2.5, 13.5, 3]}, + {"curve": [13.5, 3.5, 13, 3.5]}, {"line": [12, 3.5]}, + {"curve": [11.5, 3.5, 11.5, 3]}, {"curve": [11.5, 2.5, 12, 2.5]}], + + [{"move": [7.5, 5.5]}, {"line": [9, 5.5]}, {"curve": [9.5, 5.5, 9.5, 6]}, + {"line": [9.5, 7.5]}], + [{"move": [9.5, 6]}, {"curve": [9.5, 5.5, 10.5, 5.5]}, + {"line": [11.5, 5.5]}], + + + [{"move": [5.5, 5.5]}, {"line": [5.5, 7]}, {"curve": [5.5, 7.5, 6, 7.5]}, + {"line": [7.5, 7.5]}], + [{"move": [6, 7.5]}, {"curve": [5.5, 7.5, 5.5, 8]}, {"line": [5.5, 9.5]}], + + [{"move": [13.5, 5.5]}, {"line": [13.5, 7]}, + {"curve": [13.5, 7.5, 13, 7.5]}, {"line": [11.5, 7.5]}], + [{"move": [13, 7.5]}, {"curve": [13.5, 7.5, 13.5, 8]}, + {"line": [13.5, 9.5]}], + + [{"move": [0, 11.5]}, {"line": [3, 11.5]}, {"curve": [3.5, 11.5, 3.5, 12]}, + {"line": [3.5, 13]}, {"curve": [3.5, 13.5, 3, 13.5]}, {"line": [1, 13.5]}, + {"curve": [0.5, 13.5, 0.5, 14]}, {"line": [0.5, 17]}, + {"curve": [0.5, 17.5, 1, 17.5]}, {"line": [1.5, 17.5]}], + [{"move": [1, 17.5]}, {"curve": [0.5, 17.5, 0.5, 18]}, {"line": [0.5, 21]}, + {"curve": [0.5, 21.5, 1, 21.5]}, {"line": [18, 21.5]}, + {"curve": [18.5, 21.5, 18.5, 21]}, {"line": [18.5, 18]}, + {"curve": [18.5, 17.5, 18, 17.5]}, {"line": [17.5, 17.5]}], + [{"move": [18, 17.5]}, {"curve": [18.5, 17.5, 18.5, 17]}, + {"line": [18.5, 14]}, {"curve": [18.5, 13.5, 18, 13.5]}, + {"line": [16, 13.5]}, {"curve": [15.5, 13.5, 15.5, 13]}, + {"line": [15.5, 12]}, {"curve": [15.5, 11.5, 16, 11.5]}, + {"line": [19, 11.5]}], + + [{"move": [5.5, 11.5]}, {"line": [5.5, 13.5]}], + [{"move": [13.5, 11.5]}, {"line": [13.5, 13.5]}], + + [{"move": [2.5, 15.5]}, {"line": [3, 15.5]}, + {"curve": [3.5, 15.5, 3.5, 16]}, {"line": [3.5, 17.5]}], + [{"move": [16.5, 15.5]}, {"line": [16, 15.5]}, + {"curve": [15.5, 15.5, 15.5, 16]}, {"line": [15.5, 17.5]}], + + [{"move": [5.5, 15.5]}, {"line": [7.5, 15.5]}], + [{"move": [11.5, 15.5]}, {"line": [13.5, 15.5]}], + + [{"move": [2.5, 19.5]}, {"line": [5, 19.5]}, + {"curve": [5.5, 19.5, 5.5, 19]}, {"line": [5.5, 17.5]}], + [{"move": [5.5, 19]}, {"curve": [5.5, 19.5, 6, 19.5]}, + {"line": [7.5, 19.5]}], + + [{"move": [11.5, 19.5]}, {"line": [13, 19.5]}, + {"curve": [13.5, 19.5, 13.5, 19]}, {"line": [13.5, 17.5]}], + [{"move": [13.5, 19]}, {"curve": [13.5, 19.5, 14, 19.5]}, + {"line": [16.5, 19.5]}], + + [{"move": [7.5, 13.5]}, {"line": [9, 13.5]}, + {"curve": [9.5, 13.5, 9.5, 14]}, {"line": [9.5, 15.5]}], + [{"move": [9.5, 14]}, {"curve": [9.5, 13.5, 10, 13.5]}, + {"line": [11.5, 13.5]}], + + [{"move": [7.5, 17.5]}, {"line": [9, 17.5]}, + {"curve": [9.5, 17.5, 9.5, 18]}, {"line": [9.5, 19.5]}], + [{"move": [9.5, 18]}, {"curve": [9.5, 17.5, 10, 17.5]}, + {"line": [11.5, 17.5]}], + + [{"move": [8.5, 9.5]}, {"line": [8, 9.5]}, {"curve": [7.5, 9.5, 7.5, 10]}, + {"line": [7.5, 11]}, {"curve": [7.5, 11.5, 8, 11.5]}, + {"line": [11, 11.5]}, {"curve": [11.5, 11.5, 11.5, 11]}, + {"line": [11.5, 10]}, {"curve": [11.5, 9.5, 11, 9.5]}, + {"line": [10.5, 9.5]}] +]; + +function cloneObj(obj) { + var i, newObj = (obj instanceof Array) ? [] : {}; + for (var i in obj) { + if (i === 'clone') { + continue; + } + if (obj[i] && typeof obj[i] === "object") { + newObj[i] = cloneObj(obj[i]); + } else { + newObj[i] = obj[i]; + } + } + return newObj; +}; + diff --git a/assets/css/components/pacman.css b/assets/css/components/pacman.css new file mode 100644 index 00000000..7ce6da2b --- /dev/null +++ b/assets/css/components/pacman.css @@ -0,0 +1,16 @@ +/** + * Pacman stylesheet + * + * @author Pierre HUBERT + */ + +.pacman-iframe { + width: 342px; + height: 426px; + margin: auto; + display: block; +} + +.pacman-iframe + p { + text-align: center; +} \ No newline at end of file diff --git a/assets/js/common/functionsSchema.js b/assets/js/common/functionsSchema.js index b6562427..930e06b9 100644 --- a/assets/js/common/functionsSchema.js +++ b/assets/js/common/functionsSchema.js @@ -1136,6 +1136,13 @@ var ComunicWeb = { }, }, + + /** + * Easter egg : pacman + */ + pacman: { + //TODO : implement + }, }, /** diff --git a/assets/js/components/pacman.js b/assets/js/components/pacman.js new file mode 100644 index 00000000..39847a9f --- /dev/null +++ b/assets/js/components/pacman.js @@ -0,0 +1,46 @@ +/** + * A little easter egg.... + * A pacman ! + * + * @author Pierre HUBERT + */ + +ComunicWeb.components.pacman = { + + /** + * Open pacman game + */ + open: function(){ + + var dialog = ComunicWeb.common.messages.createDialogSkeleton({ + title: "Pacman game", + type: "default" + }); + $(dialog.modal).modal("show"); + + //Create modal close function + var closeModal = function(){ + $(dialog.modal).modal("hide"); + }; + dialog.cancelButton.addEventListener("click", closeModal); + dialog.closeModal.addEventListener("click", closeModal); + + //This modal must be completely cleaned + $(dialog.modal).on("hidden.bs.modal", function(){ + emptyElem(dialog.modal); + dialog.modal.remove(); + }); + + //Create iframe + createElem2({ + appendTo: dialog.modalBody, + type: "iframe", + class: "pacman-iframe", + src: ComunicWeb.__config.assetsURL + "3rdparty/pacman" + }); + + //Add a notice + add_p(dialog.modalBody, "Please click on the pacman grid and press N to start a new game."); + }, + +} \ No newline at end of file diff --git a/assets/js/pages/settings/sections/general.js b/assets/js/pages/settings/sections/general.js index a64045d5..6eedc6df 100644 --- a/assets/js/pages/settings/sections/general.js +++ b/assets/js/pages/settings/sections/general.js @@ -79,7 +79,7 @@ ComunicWeb.pages.settings.sections.general = { }); //Display user ID - createFormGroup({ + var userIDInput = createFormGroup({ target: target, label: "User ID", type: "text", @@ -88,6 +88,18 @@ ComunicWeb.pages.settings.sections.general = { additionalGroupClasses: "input-user-id" }); + //Easter egg : open pacman when clicking 10 times on user ID input label + var clicks = 0; + userIDInput.parentNode.parentNode.addEventListener("click", function(){ + clicks++; + + if(clicks >= 10) { + ComunicWeb.components.pacman.open(); + clicks = 0; + } + + }); + //Display user email createFormGroup({ target: target, diff --git a/builder b/builder index 1ec7d50f..2ed545b2 100755 --- a/builder +++ b/builder @@ -234,6 +234,9 @@ rcopy($path_debug_assets."templates/", $path_release_assets."templates/"); //Copy dark theme rcopy($path_debug_assets."css/dark_theme.css", $path_release_assets."css/dark_theme.css"); +//Copy pacman +rcopy($path_debug_assets."3rdparty/pacman", $path_release_assets."3rdparty/pacman"); + //Begin to write root PHP File notice("Generate PHP root file"); $page_src = '