social_stream 0.23.2 → 0.23.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/base/app/assets/javascripts/layouts.js +0 -1
  2. data/base/app/assets/javascripts/social_stream.comments.js +10 -3
  3. data/base/app/assets/javascripts/social_stream.search.js.erb +3 -1
  4. data/base/app/assets/javascripts/social_stream.wall.js.erb +8 -1
  5. data/base/app/assets/stylesheets/{activities.css.scss → activities.css.scss.erb} +1 -1
  6. data/base/app/models/relation.rb +4 -0
  7. data/base/app/models/tie.rb +5 -0
  8. data/base/app/views/cheesecake/_index.html.erb +2 -2
  9. data/base/app/views/layouts/_search.html.erb +2 -2
  10. data/base/app/views/posts/_new_activity_fields.erb +0 -6
  11. data/base/lib/generators/social_stream/base/templates/relations.yml +4 -4
  12. data/base/lib/social_stream/base/version.rb +1 -1
  13. data/base/lib/tasks/db/populate.rake +2 -2
  14. data/base/spec/dummy/config/relations.yml +4 -4
  15. data/base/vendor/assets/javascripts/jquery.watermark.js +563 -0
  16. data/documents/app/assets/javascripts/social_stream.audio.js.erb +25 -0
  17. data/documents/app/assets/javascripts/social_stream.repository.js.erb +27 -0
  18. data/documents/app/assets/javascripts/social_stream.video.js.erb +38 -0
  19. data/documents/app/assets/stylesheets/documents.css.scss +11 -14
  20. data/documents/app/views/audios/_audio.html.erb +0 -18
  21. data/documents/app/views/audios/_audio_processed.html.erb +35 -39
  22. data/documents/app/views/common_documents/_document_info.html.erb +2 -2
  23. data/documents/app/views/common_documents/_edit_form.html.erb +1 -1
  24. data/documents/app/views/common_documents/_headers.html.erb +1 -1
  25. data/documents/app/views/common_documents/_index.html.erb +3 -0
  26. data/documents/app/views/pictures/_picture.html.erb +3 -1
  27. data/documents/app/views/videos/_video.html.erb +0 -20
  28. data/documents/app/views/videos/_video_processed.html.erb +56 -43
  29. data/documents/config/locales/en.yml +1 -1
  30. data/documents/config/locales/es.yml +1 -1
  31. data/documents/lib/social_stream/documents/version.rb +1 -1
  32. data/documents/social_stream-documents.gemspec +1 -1
  33. data/documents/vendor/assets/javascripts/jquery.jplayer.js +87 -68
  34. data/documents/vendor/assets/swf/Jplayer.swf +0 -0
  35. data/events/app/assets/javascripts/social_stream-events.js +2 -0
  36. data/events/app/assets/javascripts/social_stream.calendar.js.erb +98 -0
  37. data/events/app/assets/javascripts/social_stream.event.js +17 -0
  38. data/events/app/assets/javascripts/social_stream.events.poster.js +1 -0
  39. data/events/app/assets/javascripts/{events.js.coffee → social_stream.events.tools.js.coffee} +0 -16
  40. data/events/app/assets/stylesheets/events.css.scss +33 -0
  41. data/events/app/controllers/events_controller.rb +19 -9
  42. data/events/app/views/events/_event.html.erb +5 -0
  43. data/events/app/views/events/_sidebar_calendar.html.erb +6 -28
  44. data/events/app/views/events/index.js.erb +3 -0
  45. data/events/app/views/rooms/_form.html.erb +1 -1
  46. data/events/app/views/rooms/create.js.erb +1 -1
  47. data/events/lib/social_stream/events/version.rb +1 -1
  48. data/events/social_stream-events.gemspec +1 -1
  49. data/lib/social_stream/version.rb +1 -1
  50. data/presence/app/assets/javascripts/jquery.ui.chatbox.sstreampresence.js +1 -1
  51. data/presence/app/assets/javascripts/presence.js.erb +16 -1
  52. data/presence/app/assets/javascripts/presence_XmppClient.js.erb +10 -3
  53. data/presence/app/assets/javascripts/presence_game.js.erb +284 -49
  54. data/presence/app/assets/javascripts/presence_game_comunication.js.erb +313 -0
  55. data/presence/app/assets/javascripts/presence_game_interface.js.erb +134 -0
  56. data/presence/app/assets/javascripts/presence_game_ter.js.erb +237 -188
  57. data/presence/app/assets/javascripts/presence_persistence.js +1 -1
  58. data/presence/app/assets/javascripts/presence_uiManager.js.erb +4 -2
  59. data/presence/app/assets/javascripts/presence_utilities.js +1 -1
  60. data/presence/app/assets/javascripts/presence_videochat.js.erb +2 -3
  61. data/presence/app/assets/javascripts/presence_windowManager.js +8 -1
  62. data/presence/app/assets/stylesheets/TresEnRaya.css +57 -0
  63. data/presence/app/assets/stylesheets/chat.css.scss +22 -1
  64. data/presence/app/views/chat/_index.html.erb +15 -18
  65. data/presence/config/locales/en.yml +14 -1
  66. data/presence/config/locales/es.yml +14 -1
  67. data/presence/lib/social_stream/presence/version.rb +1 -1
  68. data/presence/lib/tasks/presence/installer.rake +2 -2
  69. data/presence/social_stream-presence.gemspec +1 -1
  70. data/presence/vendor/assets/javascripts/jquery.gamequery-0.5.1.js +1164 -0
  71. data/social_stream.gemspec +4 -4
  72. data/spec/dummy/config/relations.yml +4 -4
  73. metadata +44 -34
  74. data/base/vendor/assets/javascripts/jquery.watermarkinput.js +0 -81
  75. data/documents/app/assets/javascripts/documents.js.erb +0 -71
@@ -114,7 +114,7 @@ function restoreChatData(){
114
114
  if (! window.sessionStorage){
115
115
  return
116
116
  }
117
-
117
+
118
118
  restoreChatBoxes();
119
119
  }
120
120
 
@@ -1,3 +1,5 @@
1
+ //= require jquery.watermark
2
+ //
1
3
  ////////////////////
2
4
  //Reconnect button interface functions
3
5
  ////////////////////
@@ -129,7 +131,7 @@ function settingSearchContactFunctions(){
129
131
  defaultmessage: I18n.t('chat.zerocontacts')
130
132
  });
131
133
 
132
- $("#chat_partial #search_chat_contact_flexselect").Watermark(I18n.t('chat.search'),"#666");
134
+ $("#chat_partial #search_chat_contact_flexselect").watermark(I18n.t('chat.search'),"#666");
133
135
 
134
136
  //Select contact function
135
137
  //callback in changeSelectContactValue()
@@ -542,4 +544,4 @@ function updateConnectedUsersOfMainChatBox(){
542
544
  function updateMainChatBoxAfterConnectionBoxChanges(){
543
545
  changeMainChatBoxHeight(getChatBoxHeightRequiredForConnectionBoxes());
544
546
  updateConnectedUsersOfMainChatBox();
545
- }
547
+ }
@@ -1,7 +1,7 @@
1
1
  ////////////////////
2
2
  //Debug functions
3
3
  ////////////////////
4
- var sspresence_debugging=false;
4
+ var sspresence_debugging=true;
5
5
 
6
6
  function log(msg) {
7
7
  if(sspresence_debugging){
@@ -15,8 +15,7 @@ function clickVideoChatButton(slug){
15
15
 
16
16
  if (videoBoxVisibility) {
17
17
  openVideoChatWindow(slug);
18
- }
19
- else {
18
+ } else {
20
19
  closeVideoChatWindow(slug);
21
20
  }
22
21
  }
@@ -158,7 +157,7 @@ function receiveVideoChatResponseFromUser(slug,response){
158
157
  }
159
158
 
160
159
  //Cancelation received
161
- function receiveVideoChatCancelationFromUser(slug,response){
160
+ function receiveVideoChatCancelationFromUser(slug){
162
161
  if(slug in contactsInfo){
163
162
  if(contactsInfo[slug].videoChatStatus=="pending"){
164
163
  showNotificationOnVideoBox(slug,I18n.t("chat.videochat.cancel", {name: getNameFromSlug(slug)}));
@@ -146,6 +146,9 @@ function createGroupChatBox(group_slug,open){
146
146
 
147
147
  //Modify default box
148
148
 
149
+ //Delete games Tick
150
+ $(getChatBoxButtonForSlug(group_slug,"games")).remove()
151
+
149
152
  //Delete video Tick
150
153
  $(getChatBoxButtonForSlug(group_slug,"video")).remove();
151
154
 
@@ -188,9 +191,11 @@ function createMainChatBox(){
188
191
 
189
192
  //Modify default box
190
193
 
191
- //Delete closeTick and video Tick
194
+ //Delete closeTick, video Tick and games tick
192
195
  $(mainChatBox.parent().parent()).find(".ui-chatbox-titlebar").find(".ui-icon-closethick").remove();
193
196
  $(mainChatBox.parent().parent()).find(".ui-videobox-icon").remove();
197
+ $(mainChatBox.parent().parent()).find(".chat-gamesthick").remove();
198
+
194
199
  //Margin for minusthick
195
200
  (mainChatBox.parent().parent()).find(".ui-chatbox-titlebar").find(".chat-minusthick").parent().css("margin-right","5px")
196
201
  //Delete nofitications div
@@ -473,6 +478,8 @@ function getChatBoxButtonForSlug(slug,button){
473
478
  break;
474
479
  case "videoChange":
475
480
  return chatBoxButtons[3];
481
+ case "games":
482
+ return chatBoxButtons[4];
476
483
  break;
477
484
  default : return null;
478
485
  }
@@ -0,0 +1,57 @@
1
+ .tresEnRayaContainerDivClass {
2
+ border: none;
3
+ width: 100%;
4
+ height: 100%;
5
+ }
6
+
7
+ .tresEnRayaMessageDivClass {
8
+
9
+ }
10
+
11
+ .tresEnRayaContainerThemeClassic{
12
+ border: none;
13
+ background-image: url('games/ter/classic_board.png');
14
+ background-size: 100%;
15
+ }
16
+
17
+ .tresEnRayaContainerThemeModern{
18
+ border: none;
19
+ background-image: url('games/ter/modern_board.png');
20
+ background-size: 100%;
21
+ }
22
+
23
+ .tresEnRayaMessageThemeClassic {
24
+
25
+ }
26
+
27
+ .tresEnRayaMessageThemeModern {
28
+ background-color: black;
29
+ }
30
+
31
+ p.tresEnRayaMessagePThemeClassic {
32
+ text-align: center;
33
+ font-size: 80%;
34
+ }
35
+
36
+ p.tresEnRayaMessagePThemeModern {
37
+ text-align: center;
38
+ font-size: 80%;
39
+ color: white;
40
+ }
41
+
42
+ img.tresEnRayaImgThemeClassic{
43
+ border: none;
44
+ position: absolute;
45
+ }
46
+
47
+ img.tresEnRayaImgThemeModern{
48
+ border: none;
49
+ position: absolute;
50
+ }
51
+
52
+ #myGame{
53
+ width: 200px;
54
+ height: 200px;
55
+ margin-left: 200px;
56
+ margin-top: 300px;
57
+ }
@@ -122,6 +122,27 @@ p.video-request{
122
122
  height: 60%;
123
123
  }
124
124
 
125
+
126
+
127
+ /* Game stylesheet */
128
+ .gameButton {
129
+ cursor: pointer;
130
+ font-size: 100%;
131
+ }
132
+
133
+ p.game-info{
134
+ padding-top: 25%;
135
+ text-align: center;
136
+ }
137
+
138
+ p.game-request{
139
+ padding-top: 20%;
140
+ text-align: center;
141
+ font-size: 130%;
142
+ font-weight: bolder;
143
+ color: $main-color;
144
+ }
145
+
125
146
  /* notifications style sheet */
126
147
 
127
148
  div.ui-chatbox-notify{
@@ -181,7 +202,7 @@ p.ui-chatbox-notify-text{
181
202
  }
182
203
 
183
204
  .chat-gamesthick{
184
- /*display: block; */
205
+ /* display: block; */
185
206
  display: none;
186
207
  padding: 0px 1px 0px 1px;
187
208
  }
@@ -88,25 +88,22 @@
88
88
 
89
89
  $(document).ready(function () {
90
90
 
91
- //Inicial field
92
- $("#chat_partial").html($("#chat_connecting").html())
93
-
94
- if(getRestoreUserChatStatus()!="offline"){
95
- if (authByCookie()){
96
- connectToChat(user_jid,cookie,null);
97
- } else {
98
- //Auth by password
99
- connectToChat(user_jid,null,null);
100
- }
101
-
102
- initialTimer = setTimeout("updateChatWindow()", 10000);
103
- } else {
104
- updateChatWindow();
105
- }
91
+ //Inicial field
92
+ $("#chat_partial").html($("#chat_connecting").html())
93
+
94
+ if(getRestoreUserChatStatus()!="offline"){
95
+ if (authByCookie()){
96
+ connectToChat(user_jid,cookie,null);
97
+ } else {
98
+ //Auth by password
99
+ connectToChat(user_jid,null,null);
100
+ }
101
+ initialTimer = setTimeout("updateChatWindow()", 10000);
102
+ } else {
103
+ updateChatWindow();
104
+ }
106
105
 
107
- initAudio();
108
- initFocusListeners();
109
- checkVideocallFeature();
106
+ PRESENCE.CORE.init();
110
107
  });
111
108
 
112
109
  </script>
@@ -50,4 +50,17 @@ en:
50
50
  occupants: "Occupants"
51
51
  joining: "Joining..."
52
52
  joinError: "You can't join in the room \n {{errorMsg}}"
53
- offline: "You are offline"
53
+ offline: "You are offline"
54
+ game:
55
+ call: "{{name}} wants to play"
56
+ accept: Accept
57
+ deny: Deny
58
+ offline: "Unable to connect. You are offline"
59
+ guestOffline: "Unable to connect. {{name}} is offline"
60
+ unable: Unable to init game.
61
+ rejected: "{{name}} has rejected your invitation"
62
+ rejectedBusy: "{{name}} is busy"
63
+ cancel: "{{name}} cancel the invitation"
64
+ finish: "{{name}} close the game"
65
+ waiting: Waiting for response...
66
+ unknown: Unknown response
@@ -50,4 +50,17 @@ es:
50
50
  occupants: "Miembros"
51
51
  joining: "Accediendo..."
52
52
  joinError: "No se pudo acceder a la sala. \n {{errorMsg}}"
53
- offline: "Estás desconectado"
53
+ offline: "Estás desconectado"
54
+ game:
55
+ call: "{{name}} quiere iniciar una partida"
56
+ accept: Aceptar
57
+ deny: Rechazar
58
+ offline: "Imposible conectar. Estás desconectado"
59
+ guestOffline: "Imposible conectar. {{name}} está desconectado"
60
+ unable: Imposible iniciar partida.
61
+ rejected: "{{name}} ha rechazado tu invitación"
62
+ rejectedBusy: "{{name}} está ocupado"
63
+ cancel: "{{name}} canceló la partida"
64
+ finish: "{{name}} ha cerrado el juego"
65
+ waiting: Esperando respuesta...
66
+ unknown: Respuesta desconocida
@@ -1,5 +1,5 @@
1
1
  module SocialStream
2
2
  module Presence
3
- VERSION = "0.10.0"
3
+ VERSION = "0.10.2"
4
4
  end
5
5
  end
@@ -41,9 +41,9 @@ namespace :presence do
41
41
  password = STDIN.gets.chomp
42
42
  system "stty echo"
43
43
 
44
- if password.gsub(" ","")==""
44
+ if password.gsub(" ","")=="" and user != "root"
45
45
  puts "Please specify [sudo] password for " + user + " to execute the installer"
46
- puts "You can provided it from keyboard input or execute the task as presence:install:xmpp_server[sudo_password]"
46
+ puts "You can provide it from keyboard input or execute the task as presence:install:xmpp_server[sudo_password]"
47
47
  exit 0
48
48
  end
49
49
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  # Gem dependencies
22
- s.add_runtime_dependency('social_stream-base', '~> 0.17.0')
22
+ s.add_runtime_dependency('social_stream-base', '~> 0.17.2')
23
23
 
24
24
  s.add_runtime_dependency "xmpp4r"
25
25
 
@@ -0,0 +1,1164 @@
1
+ /*
2
+ * gameQuery rev. 0.5.1
3
+ *
4
+ * Copyright (c) 2008 Selim Arsever (gamequery.onaluf.org)
5
+ * licensed under the MIT (MIT-LICENSE.txt)
6
+ */
7
+ // this allow to used the convenient $ notation in a plugins
8
+ (function($) {
9
+
10
+ $.extend({ gameQuery: {
11
+ /**
12
+ * This is the Animation Object
13
+ */
14
+ Animation: function (options) {
15
+ // private default values
16
+ var defaults = {
17
+ imageURL: "",
18
+ numberOfFrame: 1,
19
+ delta: 0,
20
+ rate: 30,
21
+ type: 0,
22
+ distance: 0,
23
+ offsetx: 0,
24
+ offsety: 0
25
+ };
26
+
27
+ // options extends defaults
28
+ options = $.extend(defaults, options);
29
+
30
+ //"public" attributes:
31
+ this.imageURL = options.imageURL; // The url of the image to be used as an animation or sprite
32
+ this.numberOfFrame = options.numberOfFrame;// The number of frame to be displayed when playing the animation
33
+ this.delta = options.delta; // The the distance in pixels between two frame
34
+ this.rate = options.rate; // The rate at which the frame must be played in miliseconds
35
+ this.type = options.type; // The type of the animation.This is bitwise OR of the properties.
36
+ this.distance = options.distance; // The the distance in pixels between two animation
37
+ this.offsetx = options.offsetx; // The x coordinate where the first sprite begin
38
+ this.offsety = options.offsety; // The y coordinate where the first sprite begin
39
+
40
+ //Whenever a new animation is created we add it to the ResourceManager animation list
41
+ $.gameQuery.resourceManager.addAnimation(this);
42
+
43
+ return true;
44
+ },
45
+
46
+ // "constants" for the different type of an animation
47
+ ANIMATION_VERTICAL: 1, // genertated by a verical offset of the background
48
+ ANIMATION_HORIZONTAL: 2, // genertated by a horizontal offset of the background
49
+ ANIMATION_ONCE: 4, // played only once (else looping indefinitly)
50
+ ANIMATION_CALLBACK: 8, // A callack is exectued at the end of a cycle
51
+ ANIMATION_MULTI: 16, // The image file contains many animations
52
+
53
+ // "constants" for the different type of geometry for a sprite
54
+ GEOMETRY_RECTANGLE: 1,
55
+ GEOMETRY_DISC: 2,
56
+
57
+ // basic values
58
+ refreshRate: 30,
59
+
60
+ /**
61
+ * An object to manages the resources loading
62
+ **/
63
+ resourceManager: {
64
+ animations: [], // List of animation / images used in the game
65
+ sounds: [], // List of sounds used in the game
66
+ callbacks: [], // List of the functions called at each refresh
67
+ running: false, // State of the game,
68
+
69
+ /**
70
+ * This function the covers things to load befor to start the game.
71
+ **/
72
+ preload: function() {
73
+ //Start loading the images
74
+ for (var i = this.animations.length-1 ; i >= 0; i --){
75
+ this.animations[i].domO = new Image();
76
+ this.animations[i].domO.src = this.animations[i].imageURL;
77
+ }
78
+
79
+ //Start loading the sounds
80
+ for (var i = this.sounds.length-1 ; i >= 0; i --){
81
+ this.sounds[i].load();
82
+ }
83
+
84
+ $.gameQuery.resourceManager.waitForResources();
85
+ },
86
+
87
+ /**
88
+ * This function the waits for all the resources called for in preload() to finish loading.
89
+ **/
90
+ waitForResources: function() {
91
+ var loadbarEnabled = ($.gameQuery.loadbar != undefined);
92
+ if(loadbarEnabled){
93
+ $($.gameQuery.loadbar.id).width(0);
94
+ var loadBarIncremant = $.gameQuery.loadbar.width / (this.animations.length + this.sounds.length);
95
+ }
96
+ //check the images
97
+ var imageCount = 0;
98
+ for(var i=0; i < this.animations.length; i++){
99
+ if(this.animations[i].domO.complete){
100
+ imageCount++;
101
+ }
102
+ }
103
+ //check the sounds
104
+ var soundCount = 0;
105
+ for(var i=0; i < this.sounds.length; i++){
106
+ var temp = this.sounds[i].ready();
107
+ if(temp){
108
+ soundCount++;
109
+ }
110
+ }
111
+ //update the loading bar
112
+ if(loadbarEnabled){
113
+ $("#"+$.gameQuery.loadbar.id).width((imageCount+soundCount)*loadBarIncremant);
114
+ if($.gameQuery.loadbar.callback){
115
+ $.gameQuery.loadbar.callback((imageCount+soundCount)/(this.animations.length + this.sounds.length)*100);
116
+ }
117
+ }
118
+ if($.gameQuery.resourceManager.loadCallback){
119
+ var percent = (imageCount+soundCount)/(this.animations.length + this.sounds.length)*100;
120
+ $.gameQuery.resourceManager.loadCallback(percent);
121
+ }
122
+ if(imageCount + soundCount < (this.animations.length + this.sounds.length)){
123
+ imgWait=setTimeout(function () {
124
+ $.gameQuery.resourceManager.waitForResources();
125
+ }, 100);
126
+ } else {
127
+ // all the resources are loaded!
128
+ // We can associate the animation's images to their coresponding sprites
129
+ $.gameQuery.sceengraph.children().each(function(){
130
+ // recursive call on the children:
131
+ $(this).children().each(arguments.callee);
132
+ // add the image as a background
133
+ if(this.gameQuery && this.gameQuery.animation){
134
+ $(this).css("background-image", "url("+this.gameQuery.animation.imageURL+")");
135
+ // we set the correct kind of repeat
136
+ if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
137
+ $(this).css("background-repeat", "repeat-x");
138
+ } else if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
139
+ $(this).css("background-repeat", "repeat-y");
140
+ } else {
141
+ $(this).css("background-repeat", "no-repeat");
142
+ }
143
+ }
144
+ });
145
+
146
+ // And launch the refresh loop
147
+ $.gameQuery.resourceManager.running = true;
148
+ setInterval(function () {
149
+ $.gameQuery.resourceManager.refresh();
150
+ },($.gameQuery.refreshRate));
151
+ if($.gameQuery.startCallback){
152
+ $.gameQuery.startCallback();
153
+ }
154
+ //make the sceengraph visible
155
+ $.gameQuery.sceengraph.css("visibility","visible");
156
+ }
157
+ },
158
+
159
+ /**
160
+ * This function refresh a unique sprite here 'this' represent a dom object
161
+ **/
162
+ refreshSprite: function() {
163
+ //Call this function on all the children:
164
+ // is 'this' a sprite ?
165
+ if(this.gameQuery != undefined){
166
+ var gameQuery = this.gameQuery;
167
+ // does 'this' has an animation ?
168
+ if(gameQuery.animation){
169
+ //Do we have anything to do?
170
+ if(gameQuery.idleCounter == gameQuery.animation.rate-1){
171
+ // does 'this' loops?
172
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_ONCE){
173
+ if(gameQuery.currentFrame < gameQuery.animation.numberOfFrame-2){
174
+ gameQuery.currentFrame++;
175
+ } else if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-2) {
176
+ gameQuery.currentFrame++;
177
+ // does 'this' has a callback ?
178
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){
179
+ if($.isFunction(gameQuery.callback)){
180
+ gameQuery.callback(this);
181
+ }
182
+ }
183
+ }
184
+ } else {
185
+ gameQuery.currentFrame = (gameQuery.currentFrame+1)%gameQuery.animation.numberOfFrame;
186
+ if(gameQuery.currentFrame == 0){
187
+ // does 'this' has a callback ?
188
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){
189
+ if($.isFunction(gameQuery.callback)){
190
+ gameQuery.callback(this);
191
+ }
192
+ }
193
+ }
194
+ }
195
+ // update the background:
196
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL){
197
+ if(gameQuery.multi){
198
+ $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.multi)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px");
199
+ } else {
200
+ $(this).css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px");
201
+ }
202
+ } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
203
+ if(gameQuery.multi){
204
+ $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety-gameQuery.multi)+"px");
205
+ } else {
206
+ $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety)+"px");
207
+ }
208
+ }
209
+ }
210
+ gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animation.rate;
211
+ }
212
+ }
213
+ return true;
214
+ },
215
+
216
+ /**
217
+ * This function refresh a unique tile-map here 'this' represent a dom object
218
+ **/
219
+ refreshTilemap: function() {
220
+ //Call this function on all the children:
221
+ // is 'this' a sprite ?
222
+ if(this.gameQuery != undefined){
223
+ var gameQuery = this.gameQuery;
224
+ if($.isArray(gameQuery.frameTracker)){
225
+ for(var i=0; i<gameQuery.frameTracker.length; i++){
226
+ //Do we have anything to do?
227
+ if(gameQuery.idleCounter[i] == gameQuery.animations[i].rate-1){
228
+ // does 'this' loops?
229
+ if(gameQuery.animations[i].type & $.gameQuery.ANIMATION_ONCE){
230
+ if(gameQuery.frameTracker[i] < gameQuery.animations[i].numberOfFrame-1){
231
+ gameQuery.frameTracker[i]++;
232
+ }
233
+ } else {
234
+ gameQuery.frameTracker[i] = (gameQuery.frameTracker[i]+1)%gameQuery.animations[i].numberOfFrame;
235
+ }
236
+ }
237
+ gameQuery.idleCounter[i] = (gameQuery.idleCounter[i]+1)%gameQuery.animations[i].rate;
238
+ }
239
+ } else {
240
+ //Do we have anything to do?
241
+ if(gameQuery.idleCounter == gameQuery.animations.rate-1){
242
+ // does 'this' loops?
243
+ if(gameQuery.animations.type & $.gameQuery.ANIMATION_ONCE){
244
+ if(gameQuery.frameTracker < gameQuery.animations.numberOfFrame-1){
245
+ gameQuery.frameTracker++;
246
+ }
247
+ } else {
248
+ gameQuery.frameTracker = (gameQuery.frameTracker+1)%gameQuery.animations.numberOfFrame;
249
+ }
250
+ }
251
+ gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animations.rate;
252
+ }
253
+
254
+
255
+ // update the background of all active tiles:
256
+ $(this).find(".active").each(function(){
257
+ if($.isArray(gameQuery.frameTracker)){
258
+ var animationNumber = this.gameQuery.animationNumber
259
+ if(gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_VERTICAL){
260
+ $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx)+"px "+(-gameQuery.animations[animationNumber].offsety-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px");
261
+ } else if(gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_HORIZONTAL) {
262
+ $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px "+(-gameQuery.animations[animationNumber].offsety)+"px");
263
+ }
264
+ } else {
265
+ if(gameQuery.animations.type & $.gameQuery.ANIMATION_VERTICAL){
266
+ $(this).css("background-position",""+(-gameQuery.animations.offsetx-this.gameQuery.multi)+"px "+(-gameQuery.animations.offsety-gameQuery.animations.delta*gameQuery.frameTracker)+"px");
267
+ } else if(gameQuery.animations.type & $.gameQuery.ANIMATION_HORIZONTAL) {
268
+ $(this).css("background-position",""+(-gameQuery.animations.offsetx-gameQuery.animations.delta*gameQuery.frameTracker)+"px "+(-gameQuery.animations.offsety-this.gameQuery.multi)+"px");
269
+ }
270
+ }
271
+ });
272
+ }
273
+ return true;
274
+ },
275
+
276
+ /**
277
+ * This function is called periodically to refresh the state of the game.
278
+ **/
279
+ refresh: function() {
280
+ $.gameQuery.playground.find(".sprite").each(this.refreshSprite);
281
+ $.gameQuery.playground.find(".tileSet").each(this.refreshTilemap);
282
+ var deadCallback= new Array();
283
+ for (var i = this.callbacks.length-1; i >= 0; i--){
284
+ if(this.callbacks[i].idleCounter == this.callbacks[i].rate-1){
285
+ var returnedValue = this.callbacks[i].fn();
286
+ if(typeof returnedValue == 'boolean'){
287
+ // if we have a boolean: 'true' means 'no more execution', 'false' means 'execute once more'
288
+ if(returnedValue){
289
+ deadCallback.push(i);
290
+ }
291
+ } else if(typeof returnedValue == 'number') {
292
+ // if we have a number it re-defines the time to the nex call
293
+ this.callbacks[i].rate = Math.round(returnedValue/$.gameQuery.refreshRate);
294
+ this.callbacks[i].idleCounter = 0;
295
+ }
296
+ }
297
+ this.callbacks[i].idleCounter = (this.callbacks[i].idleCounter+1)%this.callbacks[i].rate;
298
+ }
299
+ for(var i = deadCallback.length-1; i >= 0; i--){
300
+ this.callbacks.splice(deadCallback[i],1);
301
+ }
302
+ },
303
+
304
+ addAnimation: function(animation) {
305
+ if($.inArray(animation,this.animations)<0){
306
+ //normalize the animationRate:
307
+ animation.rate = Math.round(animation.rate/$.gameQuery.refreshRate);
308
+ if(animation.rate==0){
309
+ animation.rate = 1;
310
+ }
311
+ this.animations.push(animation);
312
+ }
313
+ },
314
+
315
+ addSound: function(sound){
316
+ if($.inArray(sound,this.sounds)<0){
317
+ this.sounds.push(sound);
318
+ }
319
+ },
320
+
321
+
322
+ registerCallback: function(fn, rate){
323
+ rate = Math.round(rate/$.gameQuery.refreshRate);
324
+ if(rate==0){
325
+ rate = 1;
326
+ }
327
+ this.callbacks.push({fn: fn, rate: rate, idleCounter: 0});
328
+ }
329
+ },
330
+
331
+ // This is a single place to update the underlying data of sprites/groups/tiles
332
+ update: function(descriptor, transformation) {
333
+ // Did we really recieve a descriptor or a jQuery object instead?
334
+ if(!$.isPlainObject(descriptor)){
335
+ // Then we must get real descriptor
336
+ if(descriptor.length > 0){
337
+ var gameQuery = descriptor[0].gameQuery;
338
+ } else {
339
+ var gameQuery = descriptor.gameQuery;
340
+ }
341
+ } else {
342
+ var gameQuery = descriptor;
343
+ }
344
+ // If we couldn't find one we return
345
+ if(!gameQuery) return;
346
+ if(gameQuery.tileSet === true){
347
+ //then we have a tilemap!
348
+ descriptor = $(descriptor);
349
+ // find the tilemap offset relatif to the playground:
350
+ var playgroundOffset = $.gameQuery.playground.offset();
351
+ var tileSetOffset = descriptor.offset();
352
+ tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};
353
+ // test what kind of transformation we have and react accordingly:
354
+ // Update the descriptor
355
+ for(property in transformation){
356
+ switch(property){
357
+ case "left":
358
+ //Do we need to activate/desactive the first/last column
359
+ var left = parseFloat(transformation.left);
360
+ //Get the tileSet offset (relatif to the playground)
361
+ var playgroundOffset = $.gameQuery.playground.offset();
362
+ var tileSetOffset = descriptor.parent().offset();
363
+ tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left + left - playgroundOffset.left};
364
+
365
+ //actvates the visible tiles
366
+ var firstColumn = Math.max(Math.min(Math.floor(-tileSetOffset.left/gameQuery.width), gameQuery.sizex),0);
367
+ var lastColumn = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-tileSetOffset.left)/gameQuery.width), gameQuery.sizex),0);
368
+
369
+ for(var i = gameQuery.firstRow; i < gameQuery.lastRow; i++){
370
+ // if old first col < new first col
371
+ // deactivate the newly invisible tiles
372
+ for(var j = gameQuery.firstColumn; j < firstColumn ; j++) {
373
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
374
+ }
375
+ //and activate the newly visible tiles
376
+ for(var j = gameQuery.lastColumn; j < lastColumn ; j++) {
377
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
378
+ }
379
+
380
+ // if old first col > new first col
381
+ // deactivate the newly invisible tiles
382
+ for(var j = lastColumn; j < gameQuery.lastColumn ; j++) {
383
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
384
+ }
385
+ //activate the newly visible tiles
386
+ for(var j = firstColumn; j < gameQuery.firstColumn ; j++) {
387
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
388
+ }
389
+ }
390
+
391
+ gameQuery.firstColumn = firstColumn;
392
+ gameQuery.lastColumn = lastColumn;
393
+ break;
394
+ case "top":
395
+ //Do we need to activate/desactive the first/last row
396
+ var top = parseFloat(transformation.top);
397
+ //Get the tileSet offset (relatif to the playground)
398
+ var playgroundOffset = $.gameQuery.playground.offset();
399
+ var tileSetOffset = descriptor.parent().offset();
400
+ tileSetOffset = {top: tileSetOffset.top + top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};
401
+
402
+ //actvates the visible tiles
403
+ var firstRow = Math.max(Math.min(Math.floor(-tileSetOffset.top/gameQuery.height), gameQuery.sizey), 0);
404
+ var lastRow = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-tileSetOffset.top)/gameQuery.height), gameQuery.sizey), 0);
405
+
406
+
407
+ for(var j = gameQuery.firstColumn; j < gameQuery.lastColumn ; j++) {
408
+ // if old first row < new first row
409
+ // deactivate the newly invisible tiles
410
+ for(var i = gameQuery.firstRow; i < firstRow; i++){
411
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
412
+ }
413
+ //and activate the newly visible tiles
414
+ for(var i = gameQuery.lastRow; i < lastRow; i++){
415
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
416
+ }
417
+
418
+ // if old first row < new first row
419
+ // deactivate the newly invisible tiles
420
+ for(var i = lastRow; i < gameQuery.lastRow; i++){
421
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
422
+ }
423
+ //and activate the newly visible tiles
424
+ for(var i = firstRow; i < gameQuery.firstRow; i++){
425
+ $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
426
+ }
427
+ }
428
+
429
+ gameQuery.firstRow = firstRow;
430
+ gameQuery.lastRow = lastRow;
431
+
432
+ break;
433
+ case "angle": //(in degree)
434
+ //TODO
435
+ break;
436
+ case "factor":
437
+ //TODO
438
+ break;
439
+ }
440
+ }
441
+
442
+ } else {
443
+ var refreshBoundingCircle = $.gameQuery.playground && !$.gameQuery.playground.disableCollision;
444
+
445
+ // Update the descriptor
446
+ for(property in transformation){
447
+ switch(property){
448
+ case "left":
449
+ gameQuery.posx = parseFloat(transformation.left);
450
+ if(refreshBoundingCircle){
451
+ gameQuery.boundingCircle.x = gameQuery.posx+gameQuery.width/2;
452
+ }
453
+ break;
454
+ case "top":
455
+ gameQuery.posy = parseFloat(transformation.top);
456
+ if(refreshBoundingCircle){
457
+ gameQuery.boundingCircle.y = gameQuery.posy+gameQuery.height/2;
458
+ }
459
+ break;
460
+ case "width":
461
+ gameQuery.width = parseFloat(transformation.width);
462
+ break;
463
+ case "height":
464
+ gameQuery.height = parseFloat(transformation.height);
465
+ break;
466
+ case "angle": //(in degree)
467
+ gameQuery.angle = parseFloat(transformation.angle);
468
+ break;
469
+ case "factor":
470
+ gameQuery.factor = parseFloat(transformation.factor);
471
+ if(refreshBoundingCircle){
472
+ gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius;
473
+ }
474
+ break;
475
+ }
476
+ }
477
+ }
478
+ },
479
+
480
+ // This is a utility function that returns the radius for a geometry
481
+ proj: function (elem, angle) {
482
+ switch (elem.geometry){
483
+ case $.gameQuery.GEOMETRY_RECTANGLE :
484
+ var b = angle*Math.PI*2/360;
485
+ var Rx = Math.abs(Math.cos(b)*elem.width/2*elem.factor)+Math.abs(Math.sin(b)*elem.height/2*elem.factor);
486
+ var Ry = Math.abs(Math.cos(b)*elem.height/2*elem.factor)+Math.abs(Math.sin(b)*elem.width/2*elem.factor);
487
+
488
+ return {x: Rx, y: Ry};
489
+ }
490
+ },
491
+
492
+ // This is a utility function for collision of two object
493
+ collide: function(elem1, offset1, elem2, offset2) {
494
+ // test real collision (only for two rectangle...)
495
+ if((elem1.geometry == $.gameQuery.GEOMETRY_RECTANGLE && elem2.geometry == $.gameQuery.GEOMETRY_RECTANGLE)){
496
+
497
+ var dx = offset2.x + elem2.boundingCircle.x - elem1.boundingCircle.x - offset1.x;
498
+ var dy = offset2.y + elem2.boundingCircle.y - elem1.boundingCircle.y - offset1.y;
499
+ var a = Math.atan(dy/dx);
500
+
501
+ var Dx = Math.abs(Math.cos(a-elem1.angle*Math.PI*2/360)/Math.cos(a)*dx);
502
+ var Dy = Math.abs(Math.sin(a-elem1.angle*Math.PI*2/360)/Math.sin(a)*dy);
503
+
504
+ var R = $.gameQuery.proj(elem2, elem2.angle-elem1.angle);
505
+
506
+ if((elem1.width/2*elem1.factor+R.x <= Dx) || (elem1.height/2*elem1.factor+R.y <= Dy)) {
507
+ return false;
508
+ } else {
509
+ var Dx = Math.abs(Math.cos(a-elem2.angle*Math.PI*2/360)/Math.cos(a)*-dx);
510
+ var Dy = Math.abs(Math.sin(a-elem2.angle*Math.PI*2/360)/Math.sin(a)*-dy);
511
+
512
+ var R = $.gameQuery.proj(elem1, elem1.angle-elem2.angle);
513
+
514
+ if((elem2.width/2*elem2.factor+R.x <= Dx) || (elem2.height/2*elem2.factor+R.y <= Dy)) {
515
+ return false;
516
+ } else {
517
+ return true;
518
+ }
519
+ }
520
+ } else {
521
+ return false;
522
+ }
523
+ }
524
+ // This function mute (or unmute) all the sounds.
525
+ }, muteSound: function(muted){
526
+ for (var i = $.gameQuery.resourceManager.sounds.length-1 ; i >= 0; i --) {
527
+ $.gameQuery.resourceManager.sounds[i].muted(muted);
528
+ }
529
+ }, playground: function() {
530
+ return $.gameQuery.playground
531
+ // This function define a callback that will be called upon during the
532
+ // loading of the game's resources. The function will recieve as unique
533
+ // parameter a number representing the progess percentage.
534
+ }, loadCallback: function(callback){
535
+ $.gameQuery.resourceManager.loadCallback = callback;
536
+ }});
537
+
538
+ $.fn.extend({
539
+ /**
540
+ * Define the div to use for the display the game and initailize it.
541
+ * This could be called on any node it doesn't matter.
542
+ * The returned node is the playground node.
543
+ * This IS a desrtuctive call
544
+ **/
545
+ playground: function(options) {
546
+ if(this.length == 1){
547
+ if(this[0] == document){ // Old usage check
548
+ throw "Old playground usage, use $.playground() to retreive the playground and $('mydiv').playground(options) to set the div!";
549
+ }
550
+ options = $.extend({
551
+ height: 320,
552
+ width: 480,
553
+ refreshRate: 30,
554
+ position: "absolute",
555
+ keyTracker: false,
556
+ disableCollision: false
557
+ }, options);
558
+ //We save the playground node and set some variable for this node:
559
+ $.gameQuery.playground = this;
560
+ $.gameQuery.refreshRate = options.refreshRate;
561
+ $.gameQuery.playground[0].height = options.height;
562
+ $.gameQuery.playground[0].width = options.width;
563
+
564
+ // We initialize the apearance of the div
565
+ $.gameQuery.playground.css({
566
+ position: options.position,
567
+ display: "block",
568
+ overflow: "hidden",
569
+ height: options.height+"px",
570
+ width: options.width+"px"
571
+ })
572
+ .append("<div id='sceengraph' style='visibility: hidden'/>");
573
+
574
+ $.gameQuery.sceengraph = $("#sceengraph");
575
+
576
+ //Add the keyTracker to the gameQuery object:
577
+ $.gameQuery.keyTracker = {};
578
+ // we only enable the real tracking if the users wants it
579
+ if(options.keyTracker){
580
+ $(document).keydown(function(event){
581
+ $.gameQuery.keyTracker[event.keyCode] = true;
582
+ });
583
+ $(document).keyup(function(event){
584
+ $.gameQuery.keyTracker[event.keyCode] = false;
585
+ });
586
+ }
587
+ }
588
+ return this;
589
+ },
590
+
591
+ /**
592
+ * Starts the game. The resources from the resource manager are preloaded if necesary
593
+ * Works only for the playgroung node.
594
+ * This is a non-desrtuctive call
595
+ **/
596
+ startGame: function(callback) {
597
+ //if the element is the playground we start the game:
598
+ $.gameQuery.startCallback = callback;
599
+ $.gameQuery.resourceManager.preload();
600
+ return this;
601
+ },
602
+
603
+ /**
604
+ * Add a group to the sceen graph
605
+ * works only on the sceengraph root or on another group
606
+ * This IS a desrtuctive call and should be terminated with end() to go back one level up in the chaining
607
+ **/
608
+ addGroup: function(group, options) {
609
+ options = $.extend({
610
+ width: 32,
611
+ height: 32,
612
+ posx: 0,
613
+ posy: 0,
614
+ overflow: "visible",
615
+ geometry: $.gameQuery.GEOMETRY_RECTANGLE,
616
+ angle: 0,
617
+ factor: 1
618
+ }, options);
619
+
620
+ var newGroupElement = "<div id='"+group+"' class='group' style='position: absolute; display: block; overflow: "+options.overflow+"; top: "+options.posy+"px; left: "+options.posx+"px; height: "+options.height+"px; width: "+options.width+"px;' />";
621
+ if(this == $.gameQuery.playground){
622
+ $.gameQuery.sceengraph.append(newGroupElement);
623
+ } else if ((this == $.gameQuery.sceengraph)||(this.hasClass("group"))){
624
+ this.append(newGroupElement);
625
+ }
626
+ var newGroup = $("#"+group);
627
+ newGroup[0].gameQuery = options;
628
+ newGroup[0].gameQuery.boundingCircle = {x: options.posx + options.width/2,
629
+ y: options.posy + options.height/0,
630
+ originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
631
+ newGroup[0].gameQuery.boundingCircle.radius = newGroup[0].gameQuery.boundingCircle.originalRadius;
632
+ newGroup[0].gameQuery.group = true;
633
+ return this.pushStack(newGroup);
634
+ },
635
+
636
+ /**
637
+ * Add a sprite to the current node.
638
+ * Works only on the playground, the sceengraph root or a sceengraph group
639
+ * This is a non-desrtuctive call
640
+ **/
641
+ addSprite: function(sprite, options) {
642
+ options = $.extend({
643
+ width: 32,
644
+ height: 32,
645
+ posx: 0,
646
+ posy: 0,
647
+ idleCounter: 0,
648
+ currentFrame: 0,
649
+ geometry: $.gameQuery.GEOMETRY_RECTANGLE,
650
+ angle: 0,
651
+ factor: 1
652
+ }, options);
653
+
654
+ var newSpriteElem = "<div id='"+sprite+"' class='sprite' style='position: absolute; display: block; overflow: hidden; height: "+options.height+"px; width: "+options.width+"px; left: "+options.posx+"px; top: "+options.posy+"px; background-position: "+((options.animation)? -options.animation.offsetx : 0)+"px "+((options.animation)? -options.animation.offsety : 0)+"px;' />";
655
+ if(this == $.gameQuery.playground){
656
+ $.gameQuery.sceengraph.append(newSpriteElem);
657
+ } else {
658
+ this.append(newSpriteElem);
659
+ }
660
+
661
+ //if the game has already started we want to add the animation's image as a background now:
662
+ if(options.animation){
663
+ if($.gameQuery.resourceManager.running){
664
+ $("#"+sprite).css("background-image", "url("+options.animation.imageURL+")");
665
+ }
666
+ if(options.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
667
+ $("#"+sprite).css("background-repeat", "repeat-x");
668
+ } else if(options.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
669
+ $("#"+sprite).css("background-repeat", "repeat-y");
670
+ } else {
671
+ $("#"+sprite).css("background-repeat", "no-repeat");
672
+ }
673
+ }
674
+
675
+
676
+ var spriteDOMObject = $("#"+sprite)[0];
677
+ if(spriteDOMObject != undefined){
678
+ spriteDOMObject.gameQuery = options;
679
+ //Compute bounding Cirlce:
680
+ spriteDOMObject.gameQuery.boundingCircle = {x: options.posx + options.width/2,
681
+ y: options.posy + options.height/2,
682
+ originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
683
+ spriteDOMObject.gameQuery.boundingCircle.radius = spriteDOMObject.gameQuery.boundingCircle.originalRadius;
684
+ }
685
+ return this;
686
+ },
687
+
688
+ /**
689
+ * Remove the sprite on which it is called. This is here for backward compatibility but it doesn't
690
+ * do anything more than simply calling .remove()
691
+ * This is a non-desrtuctive call.
692
+ **/
693
+ removeSprite: function() {
694
+ this.remove();
695
+ return this;
696
+ },
697
+
698
+ /**
699
+ * Add a Tile Map to the selected element.
700
+ * This is a non-destructive call.
701
+ **/
702
+ addTilemap: function(name, tileDescription, animationList, options){
703
+ options = $.extend({
704
+ width: 32,
705
+ height: 32,
706
+ sizex: 32,
707
+ sizey: 32,
708
+ posx: 0,
709
+ posy: 0
710
+ }, options);
711
+
712
+ //var newSpriteElem = "<div id='"+sprite+"' style='position: absolute; display: block; overflow: hidden; height: "+options.height+"px; width: "+options.width+"px; left: "+options.posx+"px; top: "+options.posy+"px; background-position: 0px 0px;' />";
713
+
714
+ var tileSet = $("<div class='tileSet' style='position: absolute; display: block; overflow: hidden;' />");
715
+ tileSet.css({top: options.posy, left: options.posx, height: options.height*options.sizey, width: options.width*options.sizex}).attr("id",name);
716
+ if(this == $.gameQuery.playground){
717
+ $.gameQuery.sceengraph.append(tileSet);
718
+ } else {
719
+ this.append(tileSet);
720
+ }
721
+
722
+ if($.isArray(animationList)){
723
+ var frameTracker = [];
724
+ var idleCounter = [];
725
+ for(var i=0; i<animationList.length; i++){
726
+ frameTracker[i] = 0;
727
+ idleCounter[i] = 0;
728
+ }
729
+ tileSet[0].gameQuery = options
730
+ tileSet[0].gameQuery.frameTracker = frameTracker;
731
+ tileSet[0].gameQuery.animations = animationList;
732
+ tileSet[0].gameQuery.idleCounter = idleCounter;
733
+ tileSet[0].gameQuery.tileSet = true;
734
+ } else {
735
+ tileSet[0].gameQuery = options
736
+ tileSet[0].gameQuery.frameTracker = 0;
737
+ tileSet[0].gameQuery.animations = animationList;
738
+ tileSet[0].gameQuery.idleCounter = 0;
739
+ tileSet[0].gameQuery.tileSet = true;
740
+ }
741
+
742
+ if(typeof tileDescription == "function"){
743
+ for(var i=0; i<options.sizey; i++){
744
+ for(var j=0; j<options.sizex; j++){
745
+ if(tileDescription(i,j) != 0){
746
+ if($.isArray(animationList)){
747
+ // for many simple animation:
748
+ tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
749
+ {width: options.width,
750
+ height: options.height,
751
+ posx: j*options.width,
752
+ posy: i*options.height,
753
+ animation: animationList[tileDescription(i,j)-1]});
754
+ var newTile = $("#tile_"+name+"_"+i+"_"+j);
755
+ newTile.removeClass("sprite");
756
+ newTile.addClass("tileType_"+(tileDescription(i,j)-1));
757
+ newTile[0].gameQuery.animationNumber = tileDescription(i,j)-1;
758
+ } else {
759
+ // for multi-animation:
760
+ tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
761
+ {width: options.width,
762
+ height: options.height,
763
+ posx: j*options.width,
764
+ posy: i*options.height,
765
+ animation: animationList});
766
+ var newTile = $("#tile_"+name+"_"+i+"_"+j);
767
+ newTile.setAnimation(tileDescription(i,j)-1);
768
+ newTile.removeClass("sprite");
769
+ newTile.addClass("tileType_"+(tileDescription(i,j)-1));
770
+ }
771
+ }
772
+ }
773
+ }
774
+ } else if(typeof tileDescription == "object") {
775
+ for(var i=0; i<tileDescription.length; i++){
776
+ for(var j=0; j<tileDescription[0].length; j++){
777
+ if(tileDescription[i][j] != 0){
778
+ if($.isArray(animationList)){
779
+ // for many simple animation:
780
+ tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
781
+ {width: options.width,
782
+ height: options.height,
783
+ posx: j*options.width,
784
+ posy: i*options.height,
785
+ animation: animationList[tileDescription[i][j]-1]});
786
+ var newTile = $("#tile_"+name+"_"+i+"_"+j);
787
+ newTile.removeClass("sprite");
788
+ newTile.addClass("tileType_"+(tileDescription[i][j]-1));
789
+ newTile[0].gameQuery.animationNumber = tileDescription[i][j]-1;
790
+ } else {
791
+ // for multi-animation:
792
+ tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
793
+ {width: options.width,
794
+ height: options.height,
795
+ posx: j*options.width,
796
+ posy: i*options.height,
797
+ animation: animationList});
798
+ var newTile = $("#tile_"+name+"_"+i+"_"+j);
799
+ newTile.setAnimation(tileDescription[i][j]-1);
800
+ newTile.removeClass("active");
801
+ newTile.addClass("tileType_"+(tileDescription[i][j]-1));
802
+ }
803
+ }
804
+ }
805
+ }
806
+ }
807
+ //Get the tileSet offset (relatif to the playground)
808
+ var playgroundOffset = $.gameQuery.playground.offset();
809
+ var tileSetOffset = tileSet.offset();
810
+ tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};
811
+
812
+ //actvates the visible tiles
813
+ var firstRow = Math.max(Math.min(Math.floor(-tileSetOffset.top/options.height), options.sizey), 0);
814
+ var lastRow = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-tileSetOffset.top)/options.height), options.sizey), 0);
815
+ var firstColumn = Math.max(Math.min(Math.floor(-tileSetOffset.left/options.width), options.sizex), 0);
816
+ var lastColumn = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-tileSetOffset.left)/options.width), options.sizex), 0);
817
+
818
+ tileSet[0].gameQuery.firstRow = firstRow;
819
+ tileSet[0].gameQuery.lastRow = lastRow;
820
+ tileSet[0].gameQuery.firstColumn = firstColumn;
821
+ tileSet[0].gameQuery.lastColumn = lastColumn;
822
+
823
+ for(var i = firstRow; i < lastRow; i++){
824
+ for(var j = firstColumn; j < lastColumn ; j++) {
825
+ $("#tile_"+name+"_"+i+"_"+j).toggleClass("active");
826
+ }
827
+ }
828
+ return this.pushStack(tileSet);
829
+ },
830
+
831
+ /**
832
+ * Changes the animation associated with a sprite.
833
+ * WARNING: no check are made to ensure that the object is really a sprite
834
+ * This is a non-desrtuctive call
835
+ **/
836
+ setAnimation: function(animation, callback) {
837
+ var gameQuery = this[0].gameQuery;
838
+ if(typeof animation == "number"){
839
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_MULTI){
840
+ var distance = gameQuery.animation.distance * animation;
841
+ gameQuery.multi = distance;
842
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
843
+ gameQuery.currentFrame = 0;
844
+ this.css("background-position",""+(-distance-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety)+"px");
845
+ } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
846
+ gameQuery.currentFrame = 0;
847
+ this.css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-distance-gameQuery.animation.offsety)+"px");
848
+ }
849
+ }
850
+ } else {
851
+ if(animation){
852
+ gameQuery.animation = animation;
853
+ gameQuery.currentFrame = 0;
854
+ this.css({"background-image": "url("+animation.imageURL+")", "background-position": ""+(-animation.offsetx)+"px "+(-animation.offsety)+"px"});
855
+
856
+ if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
857
+ this.css("background-repeat", "repeat-x");
858
+ } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
859
+ this.css("background-repeat", "repeat-y");
860
+ } else {
861
+ this.css("background-repeat", "no-repeat");
862
+ }
863
+ } else {
864
+ this.css("background-image", "");
865
+ }
866
+ }
867
+
868
+ if(callback != undefined){
869
+ this[0].gameQuery.callback = callback;
870
+ }
871
+
872
+ return this;
873
+ },
874
+
875
+ /**
876
+ * This function add the sound to the resourceManger for later use and associate it to the selected dom element(s).
877
+ * This is a non-desrtuctive call
878
+ **/
879
+ addSound: function(sound, add) {
880
+ // Does a SoundWrapper exists
881
+ if($.gameQuery.SoundWrapper) {
882
+ var gameQuery = this[0].gameQuery;
883
+ // should we add to existing sounds ?
884
+ if(add) {
885
+ // we do, have we some sound associated with 'this'?
886
+ var sounds = gameQuery.sounds;
887
+ if(sounds) {
888
+ // yes, we add it
889
+ sounds.push(sound);
890
+ } else {
891
+ // no, we create a new sound array
892
+ gameQuery.sounds = [sound];
893
+ }
894
+ } else {
895
+ // no, we replace all sounds with this one
896
+ gameQuery.sounds = [sound];
897
+ }
898
+ }
899
+ return this;
900
+ },
901
+
902
+ /**
903
+ * This function plays the sound(s) associated with the selected dom element(s)
904
+ * This is a non-desrtuctive call
905
+ **/
906
+ playSound: function() {
907
+ $(this).each(function(){
908
+ var gameQuery = this.gameQuery;
909
+ if(gameQuery.sounds) {
910
+ for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
911
+ gameQuery.sounds[i].play();
912
+ }
913
+ }
914
+ });
915
+
916
+ return this;
917
+ },
918
+
919
+ /**
920
+ * This function stops the sound(s) associated with the selected dom element(s) and rewind them
921
+ * This is a non-desrtuctive call
922
+ **/
923
+ stopSound: function() {
924
+ $(this).each(function(){
925
+ var gameQuery = this.gameQuery;
926
+ if(gameQuery.sounds) {
927
+ for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
928
+ gameQuery.sounds[i].stop();
929
+ }
930
+ }
931
+ });
932
+ return this;
933
+ },
934
+
935
+ /**
936
+ * This function pauses the sound(s) associated with the selected dom element(s)
937
+ * This is a non-desrtuctive call
938
+ **/
939
+ pauseSound: function() {
940
+ $(this).each(function(){
941
+ var gameQuery = this.gameQuery;
942
+ if(gameQuery.sounds) {
943
+ for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
944
+ gameQuery.sounds[i].pause();
945
+ }
946
+ }
947
+ });
948
+ return this;
949
+ },
950
+
951
+ /**
952
+ * this function mute or unmute the selected sound or all the sounds if none is specified
953
+ **/
954
+ muteSound: function(muted) {
955
+ $(this).each(function(){
956
+ var gameQuery = this.gameQuery;
957
+ if(gameQuery.sounds) {
958
+ for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
959
+ gameQuery.sounds[i].muted(muted);
960
+ }
961
+ }
962
+ });
963
+ return this;
964
+ },
965
+
966
+ /**
967
+ * Register a callback to be trigered every "rate"
968
+ * This is a non-desrtuctive call
969
+ **/
970
+ registerCallback: function(fn, rate) {
971
+ $.gameQuery.resourceManager.registerCallback(fn, rate);
972
+ return this;
973
+ },
974
+
975
+ /**
976
+ * @DEPRECATED: use loadCallback() instead
977
+ * Set the id of the div to use as a loading bar while the games media are loaded during the preload.
978
+ * If a callback function is given it will be called each time the loading progression changes with
979
+ * the precentage passed as unique argument.
980
+ * This is a non-desrtuctive call
981
+ **/
982
+ setLoadBar: function(elementId, finalwidth, callback) {
983
+ $.gameQuery.loadbar = {id: elementId, width: finalwidth, callback: callback};
984
+ return this;
985
+ },
986
+
987
+ /**
988
+ * This function retreive a list of object in collision with the subject:
989
+ * - if 'this' is a sprite or a group, the function will retrieve the list of sprites (not groups) that touch it
990
+ * - if 'this' is the playground, the function will return a list of all pair of collisioning elements. They are represented
991
+ * by a jQuery object containing a series of paire. Each paire represents two object colliding.(not yet implemented)
992
+ * For now all abject are considered to be boxes.
993
+ * This IS a desrtuctive call and should be terminated with end() to go back one level up in the chaining
994
+ **/
995
+ collision: function(filter){
996
+ var resultList = [];
997
+
998
+ //retrieve 'this' offset by looking at the parents
999
+ var itsParent = this[0].parentNode, offsetX = 0, offsetY = 0;
1000
+ while (itsParent != $.gameQuery.playground[0]){
1001
+ if(itsParent.gameQuery){
1002
+ offsetX += itsParent.gameQuery.posx;
1003
+ offsetY += itsParent.gameQuery.posy;
1004
+ }
1005
+ itsParent = itsParent.parentNode;
1006
+ }
1007
+
1008
+ // retrieve the gameQuery object
1009
+ var gameQuery = this[0].gameQuery;
1010
+
1011
+
1012
+ // retrieve the playground's absolute position and size information
1013
+ var pgdGeom = {top: 0, left: 0, bottom: $.playground().height(), right: $.playground().width()};
1014
+
1015
+ // Does 'this' is inside the playground ?
1016
+ if( (gameQuery.boundingCircle.y + gameQuery.boundingCircle.radius + offsetY < pgdGeom.top) ||
1017
+ (gameQuery.boundingCircle.x + gameQuery.boundingCircle.radius + offsetX < pgdGeom.left) ||
1018
+ (gameQuery.boundingCircle.y - gameQuery.boundingCircle.radius + offsetY > pgdGeom.bottom) ||
1019
+ (gameQuery.boundingCircle.x - gameQuery.boundingCircle.radius + offsetX > pgdGeom.right)){
1020
+ return this.pushStack(new $([]));
1021
+ }
1022
+
1023
+ if(this == $.gameQuery.playground){
1024
+ //TODO Code the "all against all" collision detection and find a nice way to return a list of pairs of elements
1025
+ } else {
1026
+ // we must find all the element that touches 'this'
1027
+ var elementsToCheck = new Array();
1028
+ elementsToCheck.push($.gameQuery.sceengraph.children(filter).get());
1029
+ elementsToCheck[0].offsetX = 0;
1030
+ elementsToCheck[0].offsetY = 0;
1031
+
1032
+ for(var i = 0, len = elementsToCheck.length; i < len; i++) {
1033
+ var subLen = elementsToCheck[i].length;
1034
+ while(subLen--){
1035
+ var elementToCheck = elementsToCheck[i][subLen];
1036
+ // is it a gameQuery generated element?
1037
+ if(elementToCheck.gameQuery){
1038
+ // we don't want to check groups
1039
+ if(!elementToCheck.gameQuery.group && !elementToCheck.gameQuery.tileSet){
1040
+ // does it touches the selection?
1041
+ if(this[0]!=elementToCheck){
1042
+ // check bounding circle collision
1043
+ // 1) distance between center:
1044
+ var distance = Math.sqrt(Math.pow(offsetY + gameQuery.boundingCircle.y - elementsToCheck[i].offsetY - elementToCheck.gameQuery.boundingCircle.y, 2) + Math.pow(offsetX + gameQuery.boundingCircle.x - elementsToCheck[i].offsetX - elementToCheck.gameQuery.boundingCircle.x, 2));
1045
+ if(distance - gameQuery.boundingCircle.radius - elementToCheck.gameQuery.boundingCircle.radius <= 0){
1046
+ // check real collision
1047
+ if($.gameQuery.collide(gameQuery, {x: offsetX, y: offsetY}, elementToCheck.gameQuery, {x: elementsToCheck[i].offsetX, y: elementsToCheck[i].offsetY})) {
1048
+ // add to the result list if collision detected
1049
+ resultList.push(elementsToCheck[i][subLen]);
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ // Add the children nodes to the list
1055
+ var eleChildren = $(elementToCheck).children(filter);
1056
+ if(eleChildren.length){
1057
+ elementsToCheck.push(eleChildren.get());
1058
+ elementsToCheck[len].offsetX = elementToCheck.gameQuery.posx + elementsToCheck[i].offsetX;
1059
+ elementsToCheck[len].offsetY = elementToCheck.gameQuery.posy + elementsToCheck[i].offsetY;
1060
+ len++;
1061
+ }
1062
+ }
1063
+ }
1064
+ }
1065
+ return this.pushStack($(resultList));
1066
+ }
1067
+ },
1068
+
1069
+ /**
1070
+ * This is an internal function doing the combine action of rotate and scale
1071
+ * Both argument are mandatory. To get the values back use .rotate() or
1072
+ * .scale()
1073
+ **/
1074
+ transform: function(angle, factor) {
1075
+ var gameQuery = this[0].gameQuery;
1076
+ // Mark transformed and compute bounding box
1077
+ $.gameQuery.update(gameQuery,{angle: angle, factor: factor});
1078
+
1079
+ if(this.css("MozTransform")) {
1080
+ // For firefox from 3.5
1081
+ var transform = "rotate("+angle+"deg) scale("+factor+")";
1082
+ this.css("MozTransform",transform);
1083
+ } else if(this.css("WebkitTransform")!==null && this.css("WebkitTransform")!==undefined) {
1084
+ // For safari from 3.1 (and chrome)
1085
+ var transform = "rotate("+angle+"deg) scale("+factor+")";
1086
+ this.css("WebkitTransform",transform);
1087
+ } else if(this.css("filter")!==undefined){
1088
+ var angle_rad = Math.PI * 2 / 360 * angle;
1089
+ // For ie from 5.5
1090
+ var cos = Math.cos(angle_rad) * factor;
1091
+ var sin = Math.sin(angle_rad) * factor;
1092
+ var previousWidth = this.width();
1093
+ var previousHeight = this.height();
1094
+ this.css("filter","progid:DXImageTransform.Microsoft.Matrix(M11="+cos+",M12="+(-sin)+",M21="+sin+",M22="+cos+",SizingMethod='auto expand',FilterType='nearest neighbor')");
1095
+ var newWidth = this.width();
1096
+ var newHeight = this.height();
1097
+ this.css("left", ""+(gameQuery.posx-(newWidth-previousWidth)/2)+"px");
1098
+ this.css("top", ""+(gameQuery.posy-(newHeight-previousHeight)/2)+"px");
1099
+ }
1100
+ return this;
1101
+ },
1102
+
1103
+ /**
1104
+ * This function rotates the selected element(s) clock-wise. The argument is a degree.
1105
+ **/
1106
+ rotate: function(angle){
1107
+ var gameQuery = this[0].gameQuery;
1108
+
1109
+ if(angle !== undefined) {
1110
+ return this.transform(angle % 360, this.scale());
1111
+ } else {
1112
+ var ang = gameQuery.angle;
1113
+ return ang ? ang : 0;
1114
+ }
1115
+ },
1116
+
1117
+ /**
1118
+ * This function change the scale of the selected element(s). The passed argument is a ratio:
1119
+ * 1.0 = original size
1120
+ * 0.5 = half the original size
1121
+ * 2.0 = twice the original size
1122
+ **/
1123
+ scale: function(factor){
1124
+ var gameQuery = this[0].gameQuery;
1125
+
1126
+ if(factor !== undefined) {
1127
+ return this.transform(this.rotate(), factor);
1128
+ } else {
1129
+ var fac = gameQuery.factor;
1130
+ return fac ? fac : 1;
1131
+ }
1132
+ }
1133
+ });
1134
+
1135
+
1136
+ // cssHooks to track changes to sprites
1137
+ $.cssHooks["left"] = {
1138
+ set: function(elem, value) {
1139
+ $.gameQuery.update(elem, {left: value});
1140
+ return value;
1141
+ }
1142
+ }
1143
+
1144
+ $.cssHooks["top"] = {
1145
+ set: function(elem, value) {
1146
+ $.gameQuery.update(elem, {top: value});
1147
+ return value;
1148
+ }
1149
+ }
1150
+
1151
+ $.cssHooks["width"] = {
1152
+ set: function(elem, value) {
1153
+ $.gameQuery.update(elem, {width: value});
1154
+ return value;
1155
+ }
1156
+ }
1157
+
1158
+ $.cssHooks["height"] = {
1159
+ set: function(elem, value) {
1160
+ $.gameQuery.update(elem, {height: value});
1161
+ return value;
1162
+ }
1163
+ }
1164
+ })(jQuery);