commit 883157e3a62a8d3affdf959dc991fa679dda73e9 Author: Fabrice Ecaille Date: Wed Sep 25 18:26:19 2013 +0200 Initial commit 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 0000000..0b03048 Binary files /dev/null and b/images/aliensprite.png differ diff --git a/images/background.png b/images/background.png new file mode 100644 index 0000000..2724894 Binary files /dev/null and b/images/background.png differ diff --git a/images/background2.png b/images/background2.png new file mode 100644 index 0000000..e66b9db Binary files /dev/null and b/images/background2.png differ diff --git a/images/farm.png b/images/farm.png new file mode 100644 index 0000000..5d3cc1b Binary files /dev/null and b/images/farm.png differ diff --git a/images/font.png b/images/font.png new file mode 100644 index 0000000..d22022b Binary files /dev/null and b/images/font.png differ diff --git a/images/invader.png b/images/invader.png new file mode 100644 index 0000000..fe2d2e9 Binary files /dev/null and b/images/invader.png differ diff --git a/images/ufo.png b/images/ufo.png new file mode 100644 index 0000000..25c7390 Binary files /dev/null and b/images/ufo.png differ 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