From 883157e3a62a8d3affdf959dc991fa679dda73e9 Mon Sep 17 00:00:00 2001 From: Fabrice Ecaille Date: Wed, 25 Sep 2013 18:26:19 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + css/countdown.css | 53 + css/scoreboard.css | 54 + css/spaceinvaders.css | 102 ++ images/aliensprite.png | Bin 0 -> 13803 bytes images/background.png | Bin 0 -> 5854 bytes images/background2.png | Bin 0 -> 15885 bytes images/farm.png | Bin 0 -> 4592 bytes images/font.png | Bin 0 -> 4032 bytes images/invader.png | Bin 0 -> 1091 bytes images/ufo.png | Bin 0 -> 1887 bytes index.html | 40 + js/countdown.js | 84 ++ js/lettering.js | 71 ++ js/scoreboard.js | 44 + js/spaceinvaders-core.js | 233 ++++ js/spaceinvaders-models.js | 312 +++++ js/spaceinvaders-ui.js | 275 +++++ js/tools.js | 24 + lib/gamequery-0.7.1.js | 1849 ++++++++++++++++++++++++++++ lib/jquery-1.7.1.min.js | 4 + lib/jquery-ui-1.8.23.custom.min.js | 125 ++ 22 files changed, 3271 insertions(+) create mode 100644 .gitignore create mode 100644 css/countdown.css create mode 100644 css/scoreboard.css create mode 100644 css/spaceinvaders.css create mode 100644 images/aliensprite.png create mode 100644 images/background.png create mode 100644 images/background2.png create mode 100644 images/farm.png create mode 100644 images/font.png create mode 100644 images/invader.png create mode 100644 images/ufo.png create mode 100644 index.html create mode 100644 js/countdown.js create mode 100644 js/lettering.js create mode 100644 js/scoreboard.js create mode 100644 js/spaceinvaders-core.js create mode 100644 js/spaceinvaders-models.js create mode 100644 js/spaceinvaders-ui.js create mode 100644 js/tools.js create mode 100644 lib/gamequery-0.7.1.js create mode 100644 lib/jquery-1.7.1.min.js create mode 100644 lib/jquery-ui-1.8.23.custom.min.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/css/countdown.css b/css/countdown.css new file mode 100644 index 0000000..d9720aa --- /dev/null +++ b/css/countdown.css @@ -0,0 +1,53 @@ +#countdown { + float: left; + margin-top:12px; + margin-left:12px; + width:210px; + padding: 3px; + color: white; + background-color: black; + font-family: Tahoma; + font-size: 50px; +} + +.clock { + background : transparent url("../images/hours.png") no-repeat top left; + height:40px; + width:30px; + float:left; +} + +.separator { + background-position : -30px -220px; +} + +.n0 { + background-position : 0 -7px; +} +.n1 { + background-position : 0 -49px; +} +.n2 { + background-position : 0 -91px; +} +.n3 { + background-position : 0 -133px; +} +.n4 { + background-position : 0 -176px; +} +.n5 { + background-position : -30px -7px; +} +.n6 { + background-position : -30px -50px; +} +.n7 { + background-position : -30px -91px; +} +.n8 { + background-position : -30px -133px; +} +.n9 { + background-position : -30px -176px; +} \ No newline at end of file diff --git a/css/scoreboard.css b/css/scoreboard.css new file mode 100644 index 0000000..e3d2bc5 --- /dev/null +++ b/css/scoreboard.css @@ -0,0 +1,54 @@ +.scoreboard { + float: left; +/* margin-top:12px; + margin-left:12px; +*/ width: 180px; + height: 40px; + padding: 3px; + color: white; + background-color: black; + font-family: Tahoma; + font-size: 50px; +} + +.clock { + background : transparent url("../images/hours.png") no-repeat top left; + height:40px; + width:30px; + float:left; +} + +.separator { + background-position : -30px -220px; +} + +.n0 { + background-position : 0 -7px; +} +.n1 { + background-position : 0 -49px; +} +.n2 { + background-position : 0 -91px; +} +.n3 { + background-position : 0 -133px; +} +.n4 { + background-position : 0 -176px; +} +.n5 { + background-position : -30px -7px; +} +.n6 { + background-position : -30px -50px; +} +.n7 { + background-position : -30px -91px; +} +.n8 { + background-position : -30px -133px; +} +.n9 { + background-position : -30px -176px; +} diff --git a/css/spaceinvaders.css b/css/spaceinvaders.css new file mode 100644 index 0000000..746c8c3 --- /dev/null +++ b/css/spaceinvaders.css @@ -0,0 +1,102 @@ +#playground { + background-color: black; +} + +.alien { +} + +.shipShot { + background-color: green; +} + +.alienShot { + background-color: red; +} + +.weapon_bar { + height: 10px; + width: 100px; + position: absolute; + top: 5px; + background-color: black; +} + +.weapon_level { + height: 8px; + position: relative; + margin: 1px; +} +.weapon_level.good { + background-color: green; +} +.weapon_level.middle { + background-color: yellow; +} +.weapon_level.bad { + background-color: red; +} + +.life { + width: 32px; + height: 32px; + float: left; + background-image: url('../images/sprite.png'); + background-position: 0px -16px; +} + +/** SCOREBOARD**/ + +.clock { + background : transparent url("../images/font.png") no-repeat top left; + height:32px; + width:32px; + float:left; +} + +.clock.red { + background : transparent url("images/font-red.png") no-repeat top left; +} + +.clock.yellow { + background : transparent url("images/font-yellow.png") no-repeat top left; +} + +.clock.small { + position: relative; + top: 45%; + height: 16px; + width: 16px; +} + +.n0 { + background-position : 0px 0px; +} +.n1 { + background-position : -32px 0px; +} +.n2 { + background-position : -64px 0px; +} +.n3 { + background-position : -96px 0px; +} +.n4 { + background-position : -128px 0px; +} +.n5 { + background-position : -160px 0px; +} +.n6 { + background-position : -192px 0px; +} +.n7 { + background-position : -224px 0px; +} +.n8 { + background-position : -256px 0px; +} +.n9 { + background-position : -288px 0px; +} +/** Scoreboard end **/ + diff --git a/images/aliensprite.png b/images/aliensprite.png new file mode 100644 index 0000000000000000000000000000000000000000..0b03048f1d473be034ab02b93a777a2413dc8939 GIT binary patch literal 13803 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 Rvj2+)4D?KNpPfM6{2$26pj`j} literal 0 HcmV?d00001 diff --git a/images/background2.png b/images/background2.png new file mode 100644 index 0000000000000000000000000000000000000000..e66b9db4339c656c031dd5e5258788b4267d6894 GIT binary patch literal 15885 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 aAO9clwZtn;b8Ec-0000A&Oc6 literal 0 HcmV?d00001 diff --git a/images/font.png b/images/font.png new file mode 100644 index 0000000000000000000000000000000000000000..d22022b91ca01a9fcc444830cf4c7d65ae7372eb GIT binary patch literal 4032 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 ViAjvr|FCnzIU5J-sx#jA{tL36j6DDV literal 0 HcmV?d00001 diff --git a/images/invader.png b/images/invader.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2d2e93bc81d528b51e148116cd8a074c257fd4 GIT binary patch literal 1091 zcmV-J1ibr+P)Mmf7P>O#fw*J(Hw3W=HPRM;- z-0vng$)p|Pss}Ed`+es;_nhO8E#Z@qsqvwY%~5$ z%y6gt=3$0b<44@)vTpgpJiO5raUw}L*o-xSIa8{8pq+EGs#A#ln75+>yXO*SR@lUv z07%5M8&CRt#`iq^o$@8#iK0dR%%C2M%;~lX+)?usFx7~a2)c>bwrctj+c4dcD6D_a z6YJYsbpt4&nCH*ND$pT6fv$3nuY@8BT-!^08nKQ7eS&*|-N04Dc-seO`5R`VDm`1?sFL*^C#j#i8-5wV8*Z!Ak!tvHeHAdnC%(AQB|+RchKep1P=iF zb4zz>>HQMpWirv$t_|Pf8^J!jfVm>rLS7GhGS{5Ou!6sE0?k-&l2-i*pa*l>@F}oE zqR&te+!y?Q1?Fu=flGpeh^K*HfV04FrJ9cgt^pGBek6*(R^S=IM~V4Lumk9`XbGMI zFnldj1V)|mpG3R}d=C7bm{ueX152jR0bl^=36=VxT=xhOV?aglczF0$QoTaNSh?;I zN1P9gp1?S;qEcc%Fo4+vkcjEvJBFwT_U2A$FQVeW7hECDY!fgLSgCEJ%88&4Law3A zw}>xgHd{O_C>VBz-HX7y%(%rg&<8x0i}x~cGU&%cReu!RAGj5ZPh>8T@l7k7BA72M ziZbJfX_-A1&oB69EYco0zPwtY3>BbaW%(?TZUAeQ-bf44p1W9}yMX6V=mCW)r+Tko z3mIRWSq+nK;?IC-vL0BQWIeDM=nreBLcounlI_@ zs7O(8-7u+y=}v+NNFuJvObV{wIHFxii&p6a{{d}&B{FHmIx2W8w{*Ew^LBt{tiQ;O zT*2!bY978>5TOV5*}PD$d!*Cgm&8=nA&C!x?@KlJ0=NI~^nWDF`Oc43)C&Lr002ov JPDHLkV1now`knv) literal 0 HcmV?d00001 diff --git a/images/ufo.png b/images/ufo.png new file mode 100644 index 0000000000000000000000000000000000000000..25c73907879d2cea4e0ee83ca958bd170f88f6c3 GIT binary patch literal 1887 zcmV-l2cY2h3#KdgUXk@MZz=y_|#t%(uVroQVQ;b1vsN#aVDp_$c%5A%JIfGmr z1cw6*!#w?P&P)duaJV)5B>%kUJm-1O`~RQ!_Pj@l2uo>7DJx(BJ_LSZA{1x`+DyCz zYGo-J7m+0a5C{Afa03zm?gN>NZg&X<{2@T%{`kjY+YMTD7yi$B7EtH)VjERUF$|Sb zK|m&u3w#PB0`Vr|fEB3)dA82{e@&wyb- zHxZ06k;6@K+kj;AweNuMf&Z9z1$+g3DI%Ul3s6dZ1QY_FnAi}Q+(nxmcnW+0To#eu z8KY*IkRM@8%5Q*4=07=?8iT-JfZXX^r}TiihM&dw;=zCiql<@444LJK`QkurCQ`Hc z!+{t-d;mlPK^T+XCL)h~oV@~+Qh9(4I0&pY$qoWzfD2=MyMc*W%Gs_b&Bj*%E6p-^ z+P(LBrJv7x9c+q6h;_-Oo&Ye3` z>YO`wPIO(D!NEZ(D=YK)BO)TCwzgJWE|*kRR!*sN`0!z|+wD?US0^bcDevRe4p0?{ zfU8%piq|e*zU=cKKYm>Nt)QU5_w2=s7e4>(+qZrG($Z3&e{ynCHg4P~fCL8zOGihC z@7akHC*H@aDhT)tsNp?US62ssh)`Qw>+|2edzXQM0RTEWI(YQRw?NR^+6sWjYQpJs0?^RVKv!260231vQ|dQ0HO)n-2Kdao?uP=u16t-%Y_V7*D=X^<{;aGl zIeGG=tXsEkia$I&T*}MKW#7JiqLiBQZ2kK6vVZ@6iHwY#;*X4slmiD2h}CMHjYo^g zHS`DBD8_Pk2qV?~F|A4-lhYv}Xx5F)-;`3jfnQ=Qv)Mq@T>ZHWHVnML$Of*9$i10@ z0!rqTQV|$gW)AREv&;lSmWb>)#wqQ&i58&2yHU-_ZK3J3QYr@6h_TK4Bg(Jz_S*DR zWM~?`6_K|K;;|3`M~)ncPfJVNu4&qLmo8m;cIM2P($v({sL|2U)#c^oe+HMBY|aRsHtZv16NcU4J7Yj^^g(e|uwIy?W&o5s!#?o;-QdDI(Zxw(TO) zCn9~Vt*tLJGBQH0T)Fal5$U~n@#4|{%aPJ%v#qsQEIZoT+S)E$xbXKKJ9ZR=g@yG1 zn%nK}_r|&1ZXIK6k55cYI00NPmj@%y*EVn7Ja+Kl!ClqW)wi5Zr?zFwmOVWT3Y_u+1WXin3$M_aXi#qE|*V$N%|e|&gF8w1JHGS(i;nCIXO95 zH*el-s;{qa%FoYNr%#{WzpMhbZrvK4mzVc3V6UsIYb-1*j7v*P`@ke*A0Hnd@Wzgf zjlIQ4#~ov1V?zMr9Q6RjajR>i-29bcIEHcv*$a&e(&DBZ&OlI!V(e^ zz;8%691h>yP1?MzM#R9(ozQ*{Yu?iR!k@mUj Z{TC11<8@|tasB`R002ovPDHLkV1k_=iV6S# literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..82a00e6 --- /dev/null +++ b/index.html @@ -0,0 +1,40 @@ + + + Space invaders - Story + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ + + diff --git a/js/countdown.js b/js/countdown.js new file mode 100644 index 0000000..198a5d9 --- /dev/null +++ b/js/countdown.js @@ -0,0 +1,84 @@ +var COUNTDOWN = { + mustStop: false, + + init: function( minutes, seconds ) { + COUNTDOWN.minutes = minutes; + COUNTDOWN.seconds = seconds; + COUNTDOWN.mustStop = false; +// $( "#countdown" ).width( ( minutes > 0 ? 90 : 0 ) + 90); +// $( "#countdown" ).css( "background-color", "black" ); + }, + + start: function() { + if( COUNTDOWN.mustStop ) + return; + + COUNTDOWN.running = true; + + var currentMinutes = ""; + var currentSeconds = ""; + var imageMinutes = ""; + var imageSeconds = ""; + + currentMinutes = COUNTDOWN.minutes; + currentSeconds = COUNTDOWN.seconds; + + var nextMinutes = COUNTDOWN.minutes; + var nextSeconds = COUNTDOWN.seconds - 1; + + if( nextSeconds < 0 && nextMinutes > 0 ) { + nextSeconds = 59; + nextMinutes = Math.min(0, nextMinutes -1); + } + + COUNTDOWN.minutes = nextMinutes; + COUNTDOWN.seconds = nextSeconds; + + if( currentMinutes <= 0 && currentSeconds < 10 ) + $( "#countdown" ).css( "background-color", "red" ); + + if(parseInt(currentMinutes) < 10 ) currentMinutes = "0" + currentMinutes; + if(parseInt(currentSeconds) < 10 ) currentSeconds = "0" + currentSeconds; + + for(i = 0; i < String(currentMinutes).length; i++) { + imageMinutes += "
"; + } + + for(i = 0; i < String(currentSeconds).length; i++) { + imageSeconds += "
"; + } + + if( COUNTDOWN.minutes > 0) { + $("#subMinutes").empty().removeClass( "hide" ).append( imageMinutes );; + $(".clock.clock.separator").removeClass( "hide" ); + } else { + $("#subMinutes").empty().addClass( "hide" ); + $(".clock.clock.separator").addClass( "hide" ); + } + + $("#subSeconds").empty().append( imageSeconds ); + + if( nextMinutes >= 0 && nextSeconds >= 0 ) + setTimeout( "COUNTDOWN.start()", 1000 ); + else + COUNTDOWN.callback(); + }, + + add: function(seconds) { + console.log( "Adding " + seconds + " seconds to countdown" ); + COUNTDOWN.seconds = COUNTDOWN.seconds + seconds; + }, + + setTime: function( seconds ) { + console.log( "Setting " + seconds + " seconds to countdown" ); + COUNTDOWN.seconds = seconds; + }, + + stop: function() { + COUNTDOWN.mustStop = true; + }, + + callback: function() { + console.log( "COUNTDOWN.callback" ); + } +}; \ No newline at end of file diff --git a/js/lettering.js b/js/lettering.js new file mode 100644 index 0000000..977a3c8 --- /dev/null +++ b/js/lettering.js @@ -0,0 +1,71 @@ +(function($) { + function injector(t, splitter, klass, after) { + var a = t.text().split(splitter); + var html = "", + clazz = "clock", + letterSize = 32, + count = 0, + width = 0, + height = 0, + lineSize, + letter, iLetter, + i, x, y + forceSmall = false; + if( typeof customClazz != "undefined" ) { + clazz = " clock " + customClazz; + } + if (a.length) { + $(a).each( + function(i, letter) { + iLetter = (letter.charCodeAt(0) - 97); + if( letter === " " ) { + html += ""; + width += 16; + count = count + 1; + } else { + if( letter.charCodeAt(0) > 47 && letter.charCodeAt(0) < 58 ) { + letterSize = 32; + if( forceSmall ) { + letterSize = 16; + } + html += ""; + count = count + 1; + } else { + if( ( letter.charCodeAt(0) >= 'a'.charCodeAt(0) && letter.charCodeAt(0) <= 'z'.charCodeAt(0)) ) { + if( height < 16 ) { + height = 16; + } + width += 16; + lineSize = 20; + x = (iLetter % lineSize) * 16; + y = Math.floor(iLetter / lineSize) * 16 + 144; + html += ""; + count = count + 1; + } else { + if( letter.charCodeAt(0) >= 'A'.charCodeAt(0) && letter.charCodeAt(0) <= 'Z'.charCodeAt(0)) { + iLetter = letter.charCodeAt(0) - 'A'.charCodeAt(0); + if( height < 32 ) { + height = 32; + } + width += 32; + lineSize = 10; + x = (iLetter % lineSize) * 32; + y = Math.floor(iLetter / lineSize) * 32 + 32; + html += ""; + count = count + 1; + } + } + } + } + }); + t.empty().append(html); + } + } + + $.fn.lettering = function() { + return injector( $(this), '', 'char', '' ); // always + // pass + // an + // array + }; +})(jQuery); diff --git a/js/scoreboard.js b/js/scoreboard.js new file mode 100644 index 0000000..8325422 --- /dev/null +++ b/js/scoreboard.js @@ -0,0 +1,44 @@ +var SCOREBOARD = { + score: 0, + scoreLength: 6, + + init: function(size) { + if( typeof size !== "undefined" ) + SCOREBOARD.scoreLength = size; + SCOREBOARD.score = 0; + SCOREBOARD.set_score( 0 ); + }, + + add: function(addToScore, div) { + SCOREBOARD.set_score( SCOREBOARD.score + addToScore, div); + }, + + set_score: function( score, div ) { + var currentScore = ""; + var imageScore = ""; + + SCOREBOARD.score = score; + currentScore = SCOREBOARD.pad(); + + for(i = 0; i < String(currentScore).length; i++) { + imageScore += "
"; + } + + if( typeof div === "undefined" ) + div = $(".subScoreboard"); + div.empty(); + div.append( imageScore ); + }, + + pad: function() { + var str = '' + SCOREBOARD.score; + while (str.length < SCOREBOARD.scoreLength) { + str = '0' + str; + } + return str; + }, + + callback: function() { + console.log( "SCOREBOARD.callback" ); + } +}; \ No newline at end of file diff --git a/js/spaceinvaders-core.js b/js/spaceinvaders-core.js new file mode 100644 index 0000000..cee9855 --- /dev/null +++ b/js/spaceinvaders-core.js @@ -0,0 +1,233 @@ +var WAVES = [ + { + wave : [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ], + move : function() { + var offset = (PLAYGROUND_WIDTH - 16 * this.width) / 2; + if (Math.abs((this.getOriginX() - this.getX())) >= offset) { + this.directionX *= -1; + this.y = (this.y + this.height / 4); + } + } + }, + { + wave : [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ], + move : function() { + var offset = (PLAYGROUND_WIDTH - 16 * this.width) / 2; + if (Math.abs((this.getOriginX() - this.getX())) >= offset) { + this.directionX *= -1; + this.y = (this.y + this.height / 4); + } + } + } ]; + +Game = { + running : false, + wave : -1, + aliens : [], + ship : null, + score : 0, + + init : function() { + "use strict"; + Game.wave = Game.wave + 1; + var row, col; + var wave = WAVES[Game.wave].wave; + for (row = 0; row < wave.length; row = row + 1) { + var aliensRow = wave[row], type = aliensRow[0], offset = (PLAYGROUND_WIDTH - ((aliensRow.length - 1) * 0.5 + aliensRow.length) + * ALIENS_WIDTH) / 2; + for (col = 0; col < aliensRow.length; col = col + 1) { + Game.setAlien(col, row, offset, type, WAVES[Game.wave].move); + } + } + + SCOREBOARD.init(); + SCOREBOARD.set_score( Game.score ); + + Game.setShip(); + + Game.running = true; + }, + + levelComplete : function() { + "use strict"; + Game.running = false; + + setTimeout(function() { + Game.init(); + }, 3000); + }, + + hit : function() { + "use strict"; + if( !Game.running ) { + return false; + } + console.log( "Game.hit" ); + var health = Game.ship.hit(); + $(".alienShot").remove(); + $(".shipShot").remove(); + $("#life" + Game.ship.lives).remove(); + Game.running = false; + Game.ship.lives = Game.ship.lives - 1; + $("#hero").children().hide(); + + if( Game.ship.lives > 0 ) { + var _this = Game.ship; + setTimeout(function() { + Game.running = true; + $("#hero").children().show(); + _this.health = 1; + }, 2000); + } + else { + GUI.drawText( $("#message"), game_over, true ); + Game.show_game_over(); + } + }, + + setAlien : function(x, y, offset, type, move) { + "use strict"; + var id = x * ROWS + y; + var alien = new Alien("alien" + id, { + x : offset + x * ALIENS_WIDTH * 1.5, + y : START_Y + (y * 1.25 * ALIENS_HEIGHT) + }, move); + $("#actors").addSprite("alien" + id, $.extend({posx : alien.x, posy : alien.y}, animations.alien)); + alien.node = $("#alien" + id); + alien.node.addClass("alien"); + $("#alien" + id)[0].alien = alien; + Game.aliens.push(alien); + }, + + setShip : function() { + var type = SHIPS.scout; + Game.ship = new Ship("ship", { + x : $("#hero").x(), + y : $("#hero").y() + }, 3, animations.hero.ship.animation); + var hero = $("#hero"); + $.each(animations.hero, + function(id, obj){ + hero.addSprite(id, obj); + }); + Game.ship.node = $("#hero"); + }, + + addToScore : function( toAdd ) { + Game.score = Game.score + toAdd; + SCOREBOARD.add( toAdd ); + }, + + control : function() { + if( !Game.running ) { + return false; + } + + $(document).keyup(function(e){ + switch(e.keyCode) { + case 37: + e.preventDefault(); + Game.ship.left(false); + break; + case 39: + e.preventDefault(); + Game.ship.right(false); + break; + } + }); + $(document).keydown(function(e){ + switch(e.keyCode) { + case 37: + e.preventDefault(); + Game.ship.left(true); + break; + case 39: + e.preventDefault(); + Game.ship.right(true); + break; + case 32: + e.preventDefault(); + Game.ship.fire($("#shipShots"), "shipShot"); + return false; + } + }); + }, + + alienControl : function() { + if( !Game.running ) { + return false; + } + + $.each(Game.aliens, function(index, alien ) { + alien.move(); + if( alien.health > 0 && Math.random() < alien.aggression ) { + alien.fire($("#aliensShots"), "alienShot"); + } + }); + }, + + heroShotCollision : function() { + if( !Game.running ) { + return false; + } + + $(".shipShot").each(function(i,e) { + var posy = $(this).y(); + if( posy < -$(this).height() ) { + this.remove(); + return; + } + var weapon = $(this)[0].weapon; + $(this).y(weapon.directionY * weapon.speed, true); + $(this).x(weapon.directionX * weapon.speed, true); + var collisions = $(this).collision(".alien,."+$.gQ.groupCssClass); + collisions.each( function() { + var alien = $(this)[0]; + var aliensNotInArray = $.grep( Game.aliens, function( elementOfArray, index) { + return elementOfArray.id == alien.id; + }, true); + Game.aliens = aliensNotInArray; + $(this)[0].alien.hit(); + }) + if( collisions.length > 0 ) { + this.remove() + } + + if( Game.aliens.length == 0 ) { + Game.running = false; + Game.levelComplete(); + } + }); + }, + + alienShotCollision : function() { + if( !Game.running ) { + return false; + } + + $(".alienShot").each(function(i,e) { + var posy = $(this).y(); + if( posy > PLAYGROUND_HEIGHT ) { + this.remove(); + return; + } + var weapon = $(this)[0].weapon; + $(this).y(weapon.directionY * weapon.speed, true); + $(this).x(weapon.directionX * weapon.speed, true); + var collisions = $(this).collision("#ship,."+$.gQ.groupCssClass); + collisions.each( function() { + Game.hit(); + }) + if( collisions.length > 0 ) { + this.remove() + } + }); + } +}; diff --git a/js/spaceinvaders-models.js b/js/spaceinvaders-models.js new file mode 100644 index 0000000..5a9c4b6 --- /dev/null +++ b/js/spaceinvaders-models.js @@ -0,0 +1,312 @@ +/*** Weapons ***/ + +function Weapon() { + "use strict"; +} +Weapon.prototype = { + speed : 5, + strength : 10, + rof : 300, + ror : 1500, + load : 3, + max_load : 3, + width : 5, + height : 20, + shot_timer : false, + reload_timer : false, + directionX : 0, + directionY : 1, + animation : null, + + fire : function() { + if (this.shot_timer || this.load <= 0) { + return false; + } + + var _this = this; + this.load = Math.max(0,this.load - 1); + this.shot_timer = setInterval(function() { + if (_this.load > 0) { + clearTimeout(_this.shot_timer); + _this.shot_timer = false; + } + }, this.rof); + + if( !this.reload_timer) { + this.reload_timer = setInterval( function() { + _this.load = Math.min(_this.load + 1, _this.max_load); + if( _this.load == _this.max_load ) { + clearInterval(_this.reload_timer); + _this.reload_timer = false; + } + }, this.ror); + } + return true; + } + +} + +function HeroWeapon() { + "use strict"; + this.directionY = -1; +} +HeroWeapon.prototype = { + +} +heriter(HeroWeapon.prototype, Weapon.prototype); + +function AlienWeapon() { + "use strict"; + this.directionY = 1; + this.width = 5; + this.height = 10; +} +AlienWeapon.prototype = { + +} +heriter(AlienWeapon.prototype, Weapon.prototype); +/*** Weapons -END ***/ + + +/*** Actors ***/ +function Actor() { + "use strict"; +} +Actor.prototype = { + id : null, + node : null, + x : null, + y : null, + originX : 0, + originY : 0, + speed : null, + health : 1, + directionX : 0, + directionY : 0, + fireDirectionX : 0, + fireDirectionY : 0, + weapon : null, + animations : {}, + + getX : function() { + "use strict"; + return this.x; + }, + + getY : function() { + "use strict"; + return this.y; + }, + + move : function() { + "use strict"; + if (!Game.running) { + return; + } + this.x += this.directionX * this.speed; + this.y += this.directionY * this.speed; + this.x = Math.min(this.x, PLAYGROUND_WIDTH - this.node.w()); + this.x = Math.max(this.x, 0); + this.node.x(this.x); + this.node.y(this.y); + }, + + getOriginX : function() { + return this.originX; + }, + + getOriginY : function() { + return this.originY; + }, + + up : function(active) { + "use strict"; + this.directionY = active ? -1 : 0; + }, + + down : function(active) { + "use strict"; + this.directionY = active ? 1 : 0; + }, + + left : function(active) { + "use strict"; + this.directionX = active ? -1 : 0; + }, + + right : function(active) { + "use strict"; + this.directionX = active ? 1 : 0; + }, + + fire : function(layout, clazz) { + var name = "shot" + Math.ceil(Math.random() * 1000); + if (this.weapon.fire(layout)) { + layout.addSprite(name, $.extend({ posx : this.x + this.node.w() / 2, posy : this.y + this.fireDirectionY * this.node.h()}, this.weapon)); + $("#" + name).addClass(clazz) + $("#" + name)[0].weapon = this.weapon; + } + }, + + hit : function() { + this.health = this.health - 1; + if( this.health == 0 ) { + this.destroy(); + } + + return this.health; + }, + + destroy : function() { + $("#" + this.id).remove(); + } +}; + +/*** Actors - Aliens ***/ +function Alien(id, start, move) { + "use strict"; + + this.id = id; + this.x = start.x; + this.y = start.y; + this.moveFct = move; + + this.weapon = new AlienWeapon(); + this.fireDirectionY = 1; + + this.originX = this.x; + this.originY = this.y; + this.directionX = -1; + this.speed = 0.5; +} + +Alien.prototype = { + speed : 0, + directionX : 0, + directionY : 0, + moveFct : null, + width : ALIENS_WIDTH, + height : ALIENS_HEIGHT, + aggression : 0.0005, + + init : function() { + "use strict"; + this.speed = 0; + this.node.x(this.x); + this.node.y(this.y); + }, + + move : function() { + "use strict"; + this._super("move", arguments); + if (typeof this.moveFct !== undefined) { + this.moveFct(); + } + }, + + destroy : function() { + this._super("destroy", arguments); + Game.addToScore( 5 ); + } +}; + +heriter(Alien.prototype, Actor.prototype); + +/*** Actors - Aliens - END ***/ + +/*** Actors - Heroes - END ***/ +function Ship(id, start, speed, animation) { + "use strict"; + this.id = id; + this.x = start.x; + this.y = start.y; + + this.weapon = new HeroWeapon(); + this.fireDirectionY = -1; + + this.originX = this.x; + this.originY = this.y; + this.speed = speed; + + this.animation = animation; + + /*this.bigWheel = $("#bigWheel"); + this.smallWheel = $("#smallWheel"); + var bigWheelRadius = bigWheel.h() / 2, + smallWheelRadius = smallWheel.h() / 2; + this.bigWheelAngle = this.speed * 360 / ( 2 * Math.PI * bigWheelRadius ); + this.smallWheelAngle = this.speed * 360 / ( 2 * Math.PI * smallWheelRadius );*/ + +} + +Ship.prototype = { + speed : 0, + directionX : 0, + directionY : 0, + lives : 3, + animation : null, + /*bigWheel : null, + bigWheelAngle : 0, + smallWheel : null, + smallWheelAngle : 0,*/ + + init : function() { + "use strict"; + this.speed = 0; + this.node.x(this.x); + this.node.y(this.y); + }, + + /** + * Arc = (2* Pi * R) / (360) * alpha + * + */ + move : function() { + "use strict"; + this._super("move", arguments); + }, + +/* right : function(active) { + if( this.x + this.node.w() > PLAYGROUND_WIDTH ){ + return false; + } + this._super("right", arguments); + + this.bigWheel.rotate(this.bigWheelAngle, true); + this.smallWheel.rotate(this.smallWheelAngle, true); + }, + + left : function(active) { + if( this.x < 0 ){ + return false; + } + this._super("left", arguments); + + this.bigWheel.rotate(this.bigWheelAngle, true); + this.smallWheel.rotate(this.smallWheelAngle, true); + }, +*/ + up : function(active) { + if (this.y < (PLAYGROUND_HEIGHT - 2 * HUD_HEIGHT)) { + return false; + } + this._super("up", arguments); + }, + + destroy : function() { + $("#life" + this.lives).remove(); + this.lives = this.lives - 1; + $("#hero").children().hide(); + var _this = this; + setTimeout(function() { + $("#hero").children().show(); + _this.health = 1; + }, 2000); + } + +}; + +heriter(Ship.prototype, Actor.prototype); +/*** Actors - Heroes - END ***/ + +/*** Actors - END ***/ \ No newline at end of file diff --git a/js/spaceinvaders-ui.js b/js/spaceinvaders-ui.js new file mode 100644 index 0000000..852c35c --- /dev/null +++ b/js/spaceinvaders-ui.js @@ -0,0 +1,275 @@ +/*global jQuery, console */ + +var PLAYGROUND_WIDTH = 448, + PLAYGROUND_HEIGHT = 544, + REFRESH_RATE = 15, + HUD_HEIGHT = 70, + + ROWS = 5, + ALIENS = 11, + + ALIENS_WIDTH = 24, + ALIENS_HEIGHT = 17, + + START_Y = 40, + IMAGES_PREFIX = "images/"; + +var SHIPS = { + scout: {width: 30, height: 25}, + bomber: {width: 30, height: 25}, + cruser: {width: 30, height: 25} +}; + +var animations = { + hero : { + ship : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png" + }), + width : 48, + height : 24, + posx : 0, + posy : 17 + }, + /*cockpit : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsety : 24, + offsetx : 20 + }), + width : 20, + height : 33, + posx : 28, + posy : 3 + },*/ + smallWheel : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 0, + offsety : 24 + }), + posx : 4, + posy : 30, + width: 14, + height: 14 + }, + bigWheel : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 0, + offsety : 38 + }), + width : 19, + height : 19, + posx : 25, + posy : 27 + } + }, + alien : { + animation : new $.gQ.Animation({ + imageURL : IMAGES_PREFIX + "invader.png", + numberOfFrame : 2, + delta : ALIENS_WIDTH, + rate : 400, + type : $.gQ.ANIMATION_HORIZONTAL + }), + width : ALIENS_WIDTH, + height : ALIENS_HEIGHT + }, + ufo : { + animation: new $.gQ.Animation({imageURL: IMAGES_PREFIX + "ufo.png"}), + width: 48, + height: 32, + posy: 10 + }, + life : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 14, + offsety : 24 + }), + width: 32, + height: 16 + }, + weapons : { + carot : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 19, + offsety : 37 + }), + width: 19, + height: 19 + }, + corn : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 38, + offsety : 37 + }), + width: 19, + height: 19 + }, + gun : { + animation : new $.gameQuery.Animation({ + imageURL : IMAGES_PREFIX + "farm.png", + offsetx : 57, + offsety : 37 + }), + width: 19, + height: 19 + } + }, + backgrounds : { + farm: { + background1 : { + animation : new $.gQ.Animation({ + imageURL : IMAGES_PREFIX + "background.png" + }) + }, + background2 : { + animation : new $.gQ.Animation({ + imageURL : IMAGES_PREFIX + "background2.png" + }) + } + } + } +}; + +function updateWeaponLoad( load ) { + "use strict"; + var HTMLDiv = $("#weapon_load"); + HTMLDiv.removeClass().addClass("weapon_level"); + if( load > 2/3) { + HTMLDiv.addClass("good"); + } else { + if( load > 1/3) { + HTMLDiv.addClass("middle"); + } else { + HTMLDiv.addClass("bad"); + } + } + HTMLDiv.width( (load * 100) + "%" ); +} + +$(function(){ + "use strict"; + + //Playground Sprites + $("#playground").playground({height: PLAYGROUND_HEIGHT, width: PLAYGROUND_WIDTH, keyTracker: true}); + + $.playground({refreshRate: 60}) + .addGroup("background", {posx: 0, posy: HUD_HEIGHT, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .addSprite( "background1", {animation: animations.backgrounds.farm.background1.animation, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .addSprite( "background2", {animation: animations.backgrounds.farm.background2.animation, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .addSprite("ground", {posx: 0, posy : PLAYGROUND_HEIGHT - HUD_HEIGHT - 20, width: PLAYGROUND_WIDTH, height: 20}) + .end() + .addGroup("actors", {posx: 0, posy: HUD_HEIGHT, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .addGroup("hero", { + width: 48, + height: 60, + posx: (PLAYGROUND_WIDTH - 48) / 2, + posy: PLAYGROUND_HEIGHT - HUD_HEIGHT - 50 + }) + .end() + .end() + .addGroup( "shipShots", {posx: 0, posy: HUD_HEIGHT, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .end() + .addGroup( "aliensShots", {posx: 0, posy: HUD_HEIGHT, width: PLAYGROUND_WIDTH, height: PLAYGROUND_HEIGHT - HUD_HEIGHT}) + .end() + .addGroup( "hud", {width: PLAYGROUND_WIDTH, height: HUD_HEIGHT, posx: 0, posy: 0}) + .addSprite( "current_weapon", $.extend({posx: 10, posy: 40}, animations.weapons.gun)) + .addGroup("weapon_bar", { + posx : 50, + posy : 40, + width : 100, + height : 10 + }) + .addSprite("weapon_load", { + width : 100, + height : 10 + }) + .end() + .addGroup("scoreboard", { + posx: 10, + posy: 2, + width: 6 * 32, + height: 32 + }) + .addSprite( "subScoreboard", { + width: 6 * 32, + height: 32 + }) + .end() + .addGroup("lives", { + posx: PLAYGROUND_WIDTH - 100, + posy: 32, + width: 100, + height: 32 + }) + .addSprite("life3", animations.life) + .addSprite("life2", $.extend({posx: 32}, animations.life)) + .addSprite("life1", $.extend({posx: 64}, animations.life)) + .end() + .addGroup("levelGrp", { + posx: PLAYGROUND_WIDTH - 6 * 32 + 16, + posy: 2, + width: 32 + 5 * 16, + height: 16 + }) + .addSprite("levelLbl", { + width: 32 + 5 * 16 + }) + .addSprite("level", { + width : 64, + posx: 32 + 7 * 16, + posy: 16, + height: 16 + }) + .end() + .addSprite( "carot", $.extend({posx: 210, posy: 40}, animations.weapons.carot)) + .addSprite( "corn", $.extend({posx: 230, posy: 40}, animations.weapons.corn)) + .end() + ; + + $("#ground").css("background-color", "brown"); + $("#levelLbl").append("Level").lettering(); + $("#level").append("0").lettering(); + $("#scoreboard").addClass("scoreboard"); + $("#subScoreboard").addClass("subScoreboard"); + var hud = $("#hud"); + + /* + hud.append("
"); + hud.append("
'"); + hud.append("
'"); + hud.append("
'");*/ + + // Controls + $.playground().registerCallback(Game.control, REFRESH_RATE); + $.playground().registerCallback(Game.alienControl, REFRESH_RATE); + + // Collisions management + $.playground().registerCallback(Game.heroShotCollision, REFRESH_RATE); + $.playground().registerCallback(Game.alienShotCollision, REFRESH_RATE); + + // Refresh playground + $.playground().registerCallback(function(){ + updateWeaponLoad(Game.ship.weapon.load / Game.ship.weapon.max_load); + if( Game.running ) { + Game.ship.move(); + } + }, REFRESH_RATE); +}); + +$(document).ready(function () { + Game.init(); + $.loadCallback(function(percent){ + $("#loadingBar").width(400*percent); + }); + $.playground().startGame( + function() { + $("#welcomeScreen").remove(); + } + ); +}); diff --git a/js/tools.js b/js/tools.js new file mode 100644 index 0000000..9d58c51 --- /dev/null +++ b/js/tools.js @@ -0,0 +1,24 @@ +function heriter(destination, source) { + function initClassIfNecessary(obj) { + if( typeof obj["_super"] == "undefined" ) { + obj["_super"] = function() { + var methodName = arguments[0]; + var parameters = arguments[1]; + this["__parent_methods"][methodName].apply(this, parameters); + } + } + + if( typeof obj["__parent_methods"] == "undefined" ) { + obj["__parent_methods"] = {}; + } + } + + for (var element in source) { + if( typeof destination[element] != "undefined" ) { + initClassIfNecessary(destination); + destination["__parent_methods"][element] = source[element]; + } else { + destination[element] = source[element]; + } + } +} diff --git a/lib/gamequery-0.7.1.js b/lib/gamequery-0.7.1.js new file mode 100644 index 0000000..b9f6416 --- /dev/null +++ b/lib/gamequery-0.7.1.js @@ -0,0 +1,1849 @@ +/* + * gameQuery rev. 0.7.1 + * + * Copyright (c) 2012 Selim Arsever (http://gamequeryjs.com) + * licensed under the MIT-License + */ + +// This allows use of the convenient $ notation in a plugin +(function($) { + + // CSS Feature detection from: Craig Buckler (http://www.sitepoint.com/detect-css3-property-browser-support/) + var cssTransform = false; + + var detectElement = document.createElement("detect"), + CSSprefix = "Webkit,Moz,O,ms,Khtml".split(","), + All = ("transform," + CSSprefix.join("Transform,") + "Transform").split(","); + for (var i = 0, l = All.length; i < l; i++) { + if (detectElement.style[All[i]] === "") { + cssTransform = All[i]; + } + } + + // This prefix can be use whenever needed to namespace CSS classes, .data() inputs aso. + var gQprefix = "gQ_"; + + // Those are the possible states of the engine + var STATE_NEW = 0; // Not yet started for the first time + var STATE_RUNNING = 1; // Started and running + var STATE_PAUSED = 2; // Paused + + /** + * Utility function that returns the radius for a geometry. + * + * @param {object} elem DOM element + * @param {float} angle the angle in degrees + * @return {object} .x, .y radius of geometry + */ + var proj = function (elem, angle) { + switch (elem.geometry){ + case $.gameQuery.GEOMETRY_RECTANGLE : + var b = angle*Math.PI*2/360; + var Rx = Math.abs(Math.cos(b)*elem.width/2*elem.factor)+Math.abs(Math.sin(b)*elem.height/2*elem.factor); + var Ry = Math.abs(Math.cos(b)*elem.height/2*elem.factor)+Math.abs(Math.sin(b)*elem.width/2*elem.factor); + + return {x: Rx, y: Ry}; + } + }; + + /** + * Utility function that checks for collision between two elements. + * + * @param {object} elem1 DOM for the first element + * @param {float} offset1 offset of the first element + * @param {object} elem2 DOM for the second element + * @param {float} offset2 offset of the second element + * @return {boolean} if the two elements collide or not + */ + var collide = function(elem1, offset1, elem2, offset2) { + // test real collision (only for two rectangles...) + if((elem1.geometry == $.gameQuery.GEOMETRY_RECTANGLE && elem2.geometry == $.gameQuery.GEOMETRY_RECTANGLE)){ + + var dx = offset2.x + elem2.boundingCircle.x - elem1.boundingCircle.x - offset1.x; + var dy = offset2.y + elem2.boundingCircle.y - elem1.boundingCircle.y - offset1.y; + var a = Math.atan(dy/dx); + + var Dx = Math.abs(Math.cos(a-elem1.angle*Math.PI*2/360)/Math.cos(a)*dx); + var Dy = Math.abs(Math.sin(a-elem1.angle*Math.PI*2/360)/Math.sin(a)*dy); + + var R = proj(elem2, elem2.angle-elem1.angle); + + if((elem1.width/2*elem1.factor+R.x <= Dx) || (elem1.height/2*elem1.factor+R.y <= Dy)) { + return false; + } else { + var Dx = Math.abs(Math.cos(a-elem2.angle*Math.PI*2/360)/Math.cos(a)*-dx); + var Dy = Math.abs(Math.sin(a-elem2.angle*Math.PI*2/360)/Math.sin(a)*-dy); + + var R = proj(elem1, elem1.angle-elem2.angle); + + if((elem2.width/2*elem2.factor+R.x <= Dx) || (elem2.height/2*elem2.factor+R.y <= Dy)) { + return false; + } else { + return true; + } + } + } else { + return false; + } + }; + + /** + * Utility function computes the offset relative to the playground of a gameQuery element without using DOM's position. + * This should be faster than the standand .offset() function. + * + * Warning: No non-gameQuery elements should be present between this element and the playground div! + * + * @param {jQuery} element the jQuery wrapped DOM element representing the gameQuery object. + * @return {object} an object {x:, y: } containing the x and y offset. (Not top and left like jQuery's .offset()) + */ + var offset = function(element) { + // Get the tileSet offset (relative to the playground) + var offset = {x: 0, y: 0}; + var parent = element[0]; + + while(parent !== $.gameQuery.playground[0] && parent.gameQuery !== undefined) { + offset.x += parent.gameQuery.posx; + offset.y += parent.gameQuery.posy; + parent = parent.parentNode; + } + + return offset + } + + /** + * Utility function computes the index range of the tiles for a tilemap. + * + * @param {jQuery} element the jQuery wrapped DOM element representing the tilemap. + * @param {object} offset an object holding the x and y offset of the tilemap, this is optional and will be computed if not provided. + * @return {object} an object {firstColumn: , lastColumn: , fristRow: , lastRow: } + */ + var visibleTilemapIndexes = function (element, elementOffset) { + if (elementOffset === undefined) { + elementOffset = offset(element); + } + + var gameQuery = element[0].gameQuery; + // Activate the visible tiles + return { + firstRow: Math.max(Math.min(Math.floor(-elementOffset.y/gameQuery.height), gameQuery.sizey), 0), + lastRow: Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-elementOffset.y)/gameQuery.height), gameQuery.sizey), 0), + firstColumn: Math.max(Math.min(Math.floor(-elementOffset.x/gameQuery.width), gameQuery.sizex), 0), + lastColumn: Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-elementOffset.x)/gameQuery.width), gameQuery.sizex), 0) + } + } + + /** + * Utility function thast computes the buffered zone of a tilemap + * + * @param {jQuery} element the jQuery wrapped DOM element representing the tilemap. + * @param {object} visible an object describing the visible zone + * @return {object} an object {firstColumn: , lastColumn: , fristRow: , lastRow: } + */ + var bufferedTilemapIndexes = function (element, visible) { + var gameQuery = element[0].gameQuery; + + return { + firstRow: Math.max(Math.min(visible.firstRow - gameQuery.buffer, gameQuery.sizey), 0), + lastRow: Math.max(Math.min(visible.lastRow + gameQuery.buffer, gameQuery.sizey), 0), + firstColumn: Math.max(Math.min(visible.firstColumn - gameQuery.buffer, gameQuery.sizex), 0), + lastColumn: Math.max(Math.min(visible.lastColumn + gameQuery.buffer, gameQuery.sizex), 0) + } + } + + /** + * Utility function that creates a tile in the given tilemap + * + * @param {jQuery} tileSet the jQuery element representing the tile map + * @param {integer} row the row index of the tile in the tile map + * @param {integer} column the column index of the tile in the tile map + */ + var addTile = function(tileSet, row, column) { + var gameQuery = tileSet[0].gameQuery; + var name = tileSet.attr("id"); + + var tileDescription; + if(gameQuery.func) { + tileDescription = gameQuery.tiles(row,column)-1; + } else { + tileDescription = gameQuery.tiles[row][column]-1; + } + + var animation; + if(gameQuery.multi) { + animation = gameQuery.animations; + } else { + animation = gameQuery.animations[tileDescription]; + } + + if(tileDescription >= 0){ + tileSet.addSprite($.gameQuery.tileIdPrefix+name+"_"+row+"_"+column, + {width: gameQuery.width, + height: gameQuery.height, + posx: column*gameQuery.width, + posy: row*gameQuery.height, + animation: animation}); + + var newTile = tileSet.find("#"+$.gameQuery.tileIdPrefix+name+"_"+row+"_"+column); + if (gameQuery.multi) { + newTile.setAnimation(tileDescription); + } else { + newTile[0].gameQuery.animationNumber = tileDescription; + } + newTile.removeClass($.gameQuery.spriteCssClass); + newTile.addClass($.gameQuery.tileCssClass); + newTile.addClass($.gameQuery.tileTypePrefix+tileDescription); + } + } + + // Define the list of object/function accessible through $. + $.extend({ gameQuery: { + /** + * This is the Animation Object + */ + Animation: function (options, imediateCallback) { + // private default values + var defaults = { + imageURL: "", + numberOfFrame: 1, + delta: 0, + rate: 30, + type: 0, + distance: 0, + offsetx: 0, + offsety: 0 + }; + + // options extends defaults + options = $.extend(defaults, options); + + // "public" attributes: + this.imageURL = options.imageURL; // The url of the image to be used as an animation or sprite + this.numberOfFrame = options.numberOfFrame; // The number of frames to be displayed when playing the animation + this.delta = options.delta; // The distance in pixels between two frames + this.rate = options.rate; // The rate at which the frames change in miliseconds + this.type = options.type; // The type of the animation.This is a bitwise OR of the properties. + this.distance = options.distance; // The distance in pixels between two animations + this.offsetx = options.offsetx; // The x coordinate where the first sprite begins + this.offsety = options.offsety; // The y coordinate where the first sprite begins + + // Whenever a new animation is created we add it to the ResourceManager animation list + $.gameQuery.resourceManager.addAnimation(this, imediateCallback); + + return true; + }, + + /** + * "constants" for the different types of an animation + */ + ANIMATION_VERTICAL: 1, // Generated by a vertical offset of the background + ANIMATION_HORIZONTAL: 2, // Generated by a horizontal offset of the background + ANIMATION_ONCE: 4, // Played only once (else looping indefinitely) + ANIMATION_CALLBACK: 8, // A callback is exectued at the end of a cycle + ANIMATION_MULTI: 16, // The image file contains many animations + ANIMATION_PINGPONG: 32, // At the last frame of the animation it reverses (if used in conjunction with ONCE it will have no effect) + + // "constants" for the different type of geometry for a sprite + GEOMETRY_RECTANGLE: 1, + GEOMETRY_DISC: 2, + + // basic values + refreshRate: 30, + + /** + * An object to manage resource loading + */ + resourceManager: { + animations: [], // List of animations / images used in the game + sounds: [], // List of sounds used in the game + callbacks: [], // List of the functions called at each refresh + loadedAnimationsPointer: 0, // Keep track of the last loaded animation + loadedSoundsPointer: 0, // Keep track of the last loaded sound + + /** + * Load resources before starting the game. + */ + preload: function() { + // Start loading the images + for (var i = this.animations.length-1 ; i >= this.loadedAnimationsPointer; i --){ + this.animations[i].domO = new Image(); + this.animations[i].domO.src = this.animations[i].imageURL; + } + + // Start loading the sounds + for (var i = this.sounds.length-1 ; i >= this.loadedSoundsPointer; i --){ + this.sounds[i].load(); + } + + $.gameQuery.resourceManager.waitForResources(); + }, + + /** + * Wait for all the resources called for in preload() to finish loading. + */ + waitForResources: function() { + // Check the images + var imageCount = 0; + for(var i=this.loadedAnimationsPointer; i < this.animations.length; i++){ + if(this.animations[i].domO.complete){ + imageCount++; + } + } + // Check the sounds + var soundCount = 0; + for(var i=this.loadedSoundsPointer; i < this.sounds.length; i++){ + var temp = this.sounds[i].ready(); + if(temp){ + soundCount++; + } + } + // Call the load callback with the current progress + if($.gameQuery.resourceManager.loadCallback){ + var percent = (imageCount + soundCount)/(this.animations.length + this.sounds.length - this.loadedAnimationsPointer - this.loadedSoundsPointer)*100; + $.gameQuery.resourceManager.loadCallback(percent); + } + if(imageCount + soundCount < (this.animations.length + this.sounds.length - this.loadedAnimationsPointer - this.loadedSoundsPointer)){ + imgWait=setTimeout(function () { + $.gameQuery.resourceManager.waitForResources(); + }, 100); + } else { + this.loadedAnimationsPointer = this.animations.length; + this.loadedSoundsPointer = this.sounds.length; + + // All the resources are loaded! We can now associate the animation's images to their corresponding sprites + $.gameQuery.scenegraph.children().each(function(){ + // recursive call on the children: + $(this).children().each(arguments.callee); + // add the image as a background + if(this.gameQuery && this.gameQuery.animation){ + $(this).css("background-image", "url("+this.gameQuery.animation.imageURL+")"); + // we set the correct kind of repeat + if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) { + $(this).css("background-repeat", "repeat-x"); + } else if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) { + $(this).css("background-repeat", "repeat-y"); + } else { + $(this).css("background-repeat", "no-repeat"); + } + } + }); + + // Launch the refresh loop + if($.gameQuery.state === STATE_NEW){ + setInterval(function () { + $.gameQuery.resourceManager.refresh(); + },($.gameQuery.refreshRate)); + } + $.gameQuery.state = STATE_RUNNING; + if($.gameQuery.startCallback){ + $.gameQuery.startCallback(); + } + // Make the scenegraph visible + $.gameQuery.scenegraph.css("visibility","visible"); + } + }, + + /** + * This function refresh a unique sprite here 'this' represent a dom object + */ + refreshSprite: function() { + // Check if 'this' is a gameQuery element + if(this.gameQuery != undefined){ + var gameQuery = this.gameQuery; + // Does 'this' has an animation ? + if(gameQuery.animation){ + // Do we have anything to do? + if ( (gameQuery.idleCounter == gameQuery.animation.rate-1) && gameQuery.playing){ + + // Does 'this' loops? + if(gameQuery.animation.type & $.gameQuery.ANIMATION_ONCE){ + if(gameQuery.currentFrame < gameQuery.animation.numberOfFrame-1){ + gameQuery.currentFrame += gameQuery.frameIncrement; + } else if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-1) { + // Does 'this' has a callback ? + if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){ + if($.isFunction(gameQuery.callback)){ + gameQuery.callback(this); + gameQuery.callback = false; + } + } + } + } else { + if(gameQuery.animation.type & $.gameQuery.ANIMATION_PINGPONG){ + if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-1 && gameQuery.frameIncrement == 1) { + gameQuery.frameIncrement = -1; + } else if (gameQuery.currentFrame == 0 && gameQuery.frameIncrement == -1) { + gameQuery.frameIncrement = 1; + } + } + + gameQuery.currentFrame = (gameQuery.currentFrame+gameQuery.frameIncrement)%gameQuery.animation.numberOfFrame; + if(gameQuery.currentFrame == 0){ + // Does 'this' has a callback ? + if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){ + if($.isFunction(gameQuery.callback)){ + gameQuery.callback(this); + } + } + } + } + // Update the background + if((gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) && (gameQuery.animation.numberOfFrame > 1)){ + if(gameQuery.multi){ + $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.multi)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px"); + } else { + $(this).css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px"); + } + } else if((gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animation.numberOfFrame > 1)) { + if(gameQuery.multi){ + $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety-gameQuery.multi)+"px"); + } else { + $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety)+"px"); + } + } + } + gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animation.rate; + } + } + return true; + }, + + /** + * This function refresh a unique tile-map, here 'this' represent a dom object + */ + refreshTilemap: function() { + // Check if 'this' is a gameQuery element + if(this.gameQuery != undefined){ + var gameQuery = this.gameQuery; + if($.isArray(gameQuery.frameTracker)){ + for(var i=0; i 1)){ + $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx)+"px "+(-gameQuery.animations[animationNumber].offsety-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px"); + } else if((gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animations[animationNumber].numberOfFrame > 1)) { + $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px "+(-gameQuery.animations[animationNumber].offsety)+"px"); + } + } else { + if((gameQuery.animations.type & $.gameQuery.ANIMATION_VERTICAL) && (gameQuery.animations.numberOfFrame > 1)){ + $(this).css("background-position",""+(-gameQuery.animations.offsetx-this.gameQuery.multi)+"px "+(-gameQuery.animations.offsety-gameQuery.animations.delta*gameQuery.frameTracker)+"px"); + } else if((gameQuery.animations.type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animations.numberOfFrame > 1)) { + $(this).css("background-position",""+(-gameQuery.animations.offsetx-gameQuery.animations.delta*gameQuery.frameTracker)+"px "+(-gameQuery.animations.offsety-this.gameQuery.multi)+"px"); + } + } + }); + } + return true; + }, + + /** + * Called periodically to refresh the state of the game. + */ + refresh: function() { + if($.gameQuery.state === STATE_RUNNING) { + $.gameQuery.playground.find("."+$.gameQuery.spriteCssClass).each(this.refreshSprite); + $.gameQuery.playground.find("."+$.gameQuery.tilemapCssClass).each(this.refreshTilemap); + var deadCallback= new Array(); + for (var i = this.callbacks.length-1; i >= 0; i--){ + if(this.callbacks[i].idleCounter == this.callbacks[i].rate-1){ + var returnedValue = this.callbacks[i].fn(); + if(typeof returnedValue == 'boolean'){ + // If we have a boolean: 'true' means 'no more execution', 'false' means 'keep on executing' + if(returnedValue){ + deadCallback.push(i); + } + } else if(typeof returnedValue == 'number') { + // If we have a number it re-defines the time to the next call + this.callbacks[i].rate = Math.round(returnedValue/$.gameQuery.refreshRate); + this.callbacks[i].idleCounter = 0; + } + } + this.callbacks[i].idleCounter = (this.callbacks[i].idleCounter+1)%this.callbacks[i].rate; + } + for(var i = deadCallback.length-1; i >= 0; i--){ + this.callbacks.splice(deadCallback[i],1); + } + } + }, + + /** + * Add an animation to the resource Manager + */ + addAnimation: function(animation, callback) { + if($.inArray(animation,this.animations)<0){ + //normalize the animation rate: + animation.rate = Math.round(animation.rate/$.gameQuery.refreshRate); + if(animation.rate==0){ + animation.rate = 1; + } + this.animations.push(animation); + switch ($.gameQuery.state){ + case STATE_NEW: + case STATE_PAUSED: + // Nothing to do for now + break; + case STATE_RUNNING: + // immediatly load the animation and call the callback if any + this.animations[this.loadedAnimationsPointer].domO = new Image(); + this.animations[this.loadedAnimationsPointer].domO.src = animation.imageURL; + if (callback !== undefined){ + this.animations[this.loadedAnimationsPointer].domO.onload = callback; + } + this.loadedAnimationsPointer++; + break; + } + } + }, + + /** + * Add a sound to the resource Manager + */ + addSound: function(sound, callback){ + if($.inArray(sound,this.sounds)<0){ + this.sounds.push(sound); + switch ($.gameQuery.state){ + case STATE_NEW: + case STATE_PAUSED: + // Nothing to do for now + break; + case STATE_RUNNING: + // immediatly load the sound and call the callback if any + sound.load(); + // TODO callback.... + this.loadedSoundsPointer++; + break; + } + } + }, + + /** + * Register a callback + * + * @param {function} fn the callback + * @param {integer} rate the rate in ms at which the callback should be called (should be a multiple of the playground rate or will be rounded) + */ + registerCallback: function(fn, rate){ + rate = Math.round(rate/$.gameQuery.refreshRate); + if(rate==0){ + rate = 1; + } + this.callbacks.push({fn: fn, rate: rate, idleCounter: 0}); + }, + + /** + * Clear the animations and sounds + */ + clear: function(callbacksToo){ + this.animations = []; + this.loadedAnimationsPointer = 0; + this.sounds = []; + this.loadedSoundsPointer = 0; + if(callbacksToo) { + this.callbacks = []; + } + } + }, + + /** + * This is a single place to update the underlying data of sprites/groups/tiles after a position or dimesion modification. + */ + update: function(descriptor, transformation) { + // Did we really receive a descriptor or a jQuery object instead? + if(!$.isPlainObject(descriptor)){ + // Then we must get real descriptor + if(descriptor.length > 0){ + var gameQuery = descriptor[0].gameQuery; + } else { + var gameQuery = descriptor.gameQuery; + } + } else { + var gameQuery = descriptor; + } + // If we couldn't find one we return + if(!gameQuery) return; + if(gameQuery.tileSet === true){ + // We have a tilemap + + var visible = visibleTilemapIndexes(descriptor); + var buffered = gameQuery.buffered; + + // Test what kind of transformation we have and react accordingly + for(property in transformation){ + switch(property){ + case "x": + + if(visible.lastColumn > buffered.lastColumn) { + + // Detach the tilemap + var parent = descriptor[0].parentNode; + var tilemap = descriptor.detach(); + + var newBuffered = bufferedTilemapIndexes(descriptor, visible); + for(var i = gameQuery.buffered.firstRow; i < gameQuery.buffered.lastRow; i++){ + // Remove the newly invisible tiles + for(var j = gameQuery.buffered.firstColumn; j < Math.min(newBuffered.firstColumn, gameQuery.buffered.lastColumn); j++) { + tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); + } + // And add the newly visible tiles + for(var j = Math.max(gameQuery.buffered.lastColumn,newBuffered.firstColumn); j < newBuffered.lastColumn ; j++) { + addTile(tilemap,i,j); + } + } + + gameQuery.buffered.firstColumn = newBuffered.firstColumn; + gameQuery.buffered.lastColumn = newBuffered.lastColumn; + + // Attach the tilemap back + tilemap.appendTo(parent); + + } + + if(visible.firstColumn < buffered.firstColumn) { + + // Detach the tilemap + var parent = descriptor[0].parentNode; + var tilemap = descriptor.detach(); + + var newBuffered = bufferedTilemapIndexes(descriptor, visible); + for(var i = gameQuery.buffered.firstRow; i < gameQuery.buffered.lastRow; i++){ + // Remove the newly invisible tiles + for(var j = Math.max(newBuffered.lastColumn,gameQuery.buffered.firstColumn); j < gameQuery.buffered.lastColumn ; j++) { + tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); + } + // And add the newly visible tiles + for(var j = newBuffered.firstColumn; j < Math.min(gameQuery.buffered.firstColumn,newBuffered.lastColumn); j++) { + addTile(tilemap,i,j); + } + } + + gameQuery.buffered.firstColumn = newBuffered.firstColumn; + gameQuery.buffered.lastColumn = newBuffered.lastColumn; + + // Attach the tilemap back + tilemap.appendTo(parent); + } + break; + + case "y": + + if(visible.lastRow > buffered.lastRow) { + + // Detach the tilemap + var parent = descriptor[0].parentNode; + var tilemap = descriptor.detach(); + + var newBuffered = bufferedTilemapIndexes(descriptor, visible); + for(var j = gameQuery.buffered.firstColumn; j < gameQuery.buffered.lastColumn ; j++) { + // Remove the newly invisible tiles + for(var i = gameQuery.buffered.firstRow; i < Math.min(newBuffered.firstRow, gameQuery.buffered.lastRow); i++){ + tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); + } + // And add the newly visible tiles + for(var i = Math.max(gameQuery.buffered.lastRow, newBuffered.firstRow); i < newBuffered.lastRow; i++){ + addTile(tilemap,i,j); + } + } + + gameQuery.buffered.firstRow = newBuffered.firstRow; + gameQuery.buffered.lastRow = newBuffered.lastRow; + + // Attach the tilemap back + tilemap.appendTo(parent); + + } + + if(visible.firstRow < buffered.firstRow) { + + // Detach the tilemap + var parent = descriptor[0].parentNode; + var tilemap = descriptor.detach(); + + var newBuffered = bufferedTilemapIndexes(descriptor, visible); + for(var j = gameQuery.buffered.firstColumn; j < gameQuery.buffered.lastColumn ; j++) { + // Remove the newly invisible tiles + for(var i = Math.max(newBuffered.lastRow, gameQuery.buffered.firstRow); i < gameQuery.buffered.lastRow; i++){ + tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); + } + // And add the newly visible tiles + for(var i = newBuffered.firstRow; i < Math.min(gameQuery.buffered.firstRow, newBuffered.lastRow); i++){ + addTile(tilemap,i,j); + } + } + + gameQuery.buffered.firstRow = newBuffered.firstRow; + gameQuery.buffered.lastRow = newBuffered.lastRow; + + // Attach the tilemap back + tilemap.appendTo(parent); + } + break; + + case "angle": + //TODO + break; + + case "factor": + //TODO + break; + } + } + + } else { + var refreshBoundingCircle = $.gameQuery.playground && !$.gameQuery.playground.disableCollision; + + // Update the descriptor + for(property in transformation){ + switch(property){ + case "x": + if(refreshBoundingCircle){ + gameQuery.boundingCircle.x = gameQuery.posx+gameQuery.width/2; + } + break; + case "y": + if(refreshBoundingCircle){ + gameQuery.boundingCircle.y = gameQuery.posy+gameQuery.height/2; + } + break; + case "w": + case "h": + gameQuery.boundingCircle.originalRadius = Math.sqrt(Math.pow(gameQuery.width,2) + Math.pow(gameQuery.height,2))/2 + gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius; + break; + case "angle": //(in degrees) + gameQuery.angle = parseFloat(transformation.angle); + break; + case "factor": + gameQuery.factor = parseFloat(transformation.factor); + if(refreshBoundingCircle){ + gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius; + } + break; + } + } + } + }, + // State of the engine + state: STATE_NEW, + + // CSS classes used to mark game element + spriteCssClass: gQprefix + "sprite", + groupCssClass: gQprefix + "group", + tilemapCssClass: gQprefix + "tilemap", + tileCssClass: gQprefix + "tile", + // Prefix for CSS Ids or Classes + tileTypePrefix: gQprefix + "tileType_", + tileIdPrefix: gQprefix + "tile_" + }, + + /** + * Mute (or unmute) all the sounds. + */ + muteSound: function(muted){ + for (var i = $.gameQuery.resourceManager.sounds.length-1 ; i >= 0; i --) { + $.gameQuery.resourceManager.sounds[i].muted(muted); + } + }, + + /** + * Accessor for the currently defined playground as a jQuery object + */ + playground: function() { + return $.gameQuery.playground + }, + + /** + * Define a callback called during the loading of the game's resources. + * + * The function will recieve as unique parameter + * a number representing the progess percentage. + */ + loadCallback: function(callback){ + $.gameQuery.resourceManager.loadCallback = callback; + } + }); // end of the extensio of $ + + + // fragments used to create DOM element + var spriteFragment = $("
"); + var groupFragment = $("
"); + var tilemapFragment = $("
"); + + + // Define the list of object/function accessible through $("selector"). + $.fn.extend({ + /** + * Defines the currently selected div to which contains the game and initialize it. + * + * This is a non-destructive call + */ + playground: function(options) { + if(this.length == 1){ + if(this[0] == document){ + // Old usage detected, this is not supported anymore + throw "Old playground usage, use $.playground() to retreive the playground and $('mydiv').playground(options) to set the div!"; + } + options = $.extend({ + height: 320, + width: 480, + refreshRate: 30, + position: "absolute", + keyTracker: false, + mouseTracker: false, + disableCollision: false + }, options); + // We save the playground node and set some variable for this node: + $.gameQuery.playground = this; + $.gameQuery.refreshRate = options.refreshRate; + $.gameQuery.playground[0].height = options.height; + $.gameQuery.playground[0].width = options.width; + + // We initialize the display of the div + $.gameQuery.playground.css({ + position: options.position, + display: "block", + overflow: "hidden", + height: options.height+"px", + width: options.width+"px" + }) + .append(""+(g[0]>0&&N==g[1]-1?'
':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.23",window["DP_jQuery_"+dpuuid]=$})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.progressbar.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("
").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.core.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.23",save:function(a,b){for(var c=0;c
").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.blind.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.bounce.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m
").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.fade.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.fold.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.highlight.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.pulsate.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i
').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);; \ No newline at end of file