not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
10 KiB

  1. // Level config
  2. FoodChain.buildLevels = [
  3. { size: 2, time: 2 }, // Level 1
  4. { size: 3, time: 5 }, // Level 2
  5. { size: 3, time: 3 }, // Level 3
  6. { size: 3, time: 2 }, // Level 4
  7. { size: 4, time: 5 }, // Level 5
  8. { size: 4, time: 3 }, // Level 6
  9. { size: 5, time: 3 } // Level 7
  10. ];
  11. // Build Game class
  12. enyo.kind({
  13. name: "FoodChain.BuildGame",
  14. kind: enyo.Control,
  15. published: {level: 1},
  16. classes: "board",
  17. components: [
  18. { name: "cards", components: [
  19. // Level - Score - Time bar
  20. { components: [
  21. { classes: "level-zone", components: [
  22. { name: "textlevel", classes: "title level-value" },
  23. { name: "level", content: "0", classes: "title level-value" }
  24. ]},
  25. { classes: "score-zone", components: [
  26. { name: "textscore", classes: "title score-text" },
  27. { name: "score", content: "0000", classes: "title score-value" },
  28. { name: "timercount", content: "0:0,0", classes: "title timer-value" }
  29. ]}
  30. ]},
  31. // Board zone
  32. { name: "gamebox", classes: "box", ontap: "unselect", ondrop: "drop", ondragover: "dragover", components: [] },
  33. // Buttons bar
  34. { name: "validate", kind: "ShadowButton", img: "validate", classes: "validate", ontap: "controlOrder" },
  35. { name: "play", kind: "ShadowButton", img: "play", classes: "play", ontap: "play" },
  36. { name: "pause", kind: "ShadowButton", img: "pause", classes: "play", ontap: "pause" },
  37. { name: "restart", kind: "ShadowButton", img: "restart", classes: "restart", ontap: "restart" },
  38. { name: "forward", kind: "ShadowButton", img: "forward", classes: "restart", ontap: "next" },
  39. { name: "home", kind: "ShadowButton", img: "home", classes: "home", ontap: "home" },
  40. // End of sound event
  41. {kind: "enyo.Signals", onEndOfSound: "endSound"}
  42. ]}
  43. ],
  44. // Constructor
  45. create: function() {
  46. this.inherited(arguments);
  47. this.previous = null;
  48. this.mixed = null;
  49. this.createComponent({ name: "timer", kind: "Timer", paused: true, onTriggered: "updateTimer" }, {owner: this});
  50. this.setLocale();
  51. this.$.score.setContent(String("0000"+FoodChain.context.score).slice(-4));
  52. FoodChain.context.game = this.kindName;
  53. this.levelChanged();
  54. },
  55. // Localization changed, update cards and string resource
  56. setLocale: function() {
  57. // Update string resources
  58. this.$.textlevel.setContent(__$FC("level"));
  59. this.$.textscore.setContent(__$FC("score"));
  60. // Update cards
  61. enyo.forEach(this.$.gamebox.getControls(), function(card) {
  62. card.setLocale();
  63. });
  64. },
  65. // Level changed, init board then start game
  66. levelChanged: function() {
  67. // Delete current cards on board
  68. FoodChain.context.level = this.level;
  69. var cards = [];
  70. enyo.forEach(this.$.gamebox.getControls(), function(card) {
  71. cards.push(card);
  72. });
  73. for (var i = 0 ; i < cards.length ; i++) {
  74. cards[i].destroy();
  75. }
  76. // Compute the start chain
  77. if (this.mixed == null) {
  78. var same;
  79. do {
  80. // Pick a random chain and ensure it's not the same that the previous one
  81. this.chain = FoodChain.randomChain(FoodChain.buildLevels[this.level-1].size);
  82. if (this.previous == null || this.previous.length != this.chain.length) {
  83. same = false;
  84. } else {
  85. same = true;
  86. for (var i = 0 ; same && i < this.chain.length ; i++ ) {
  87. if (this.previous[i] != this.chain[i])
  88. same = false;
  89. }
  90. }
  91. } while (same);
  92. this.mixed = FoodChain.mix(this.chain);
  93. }
  94. // Display cards
  95. var step = 99/this.mixed.length;
  96. var x = 5-this.mixed.length, y = 8;
  97. this.cards = [];
  98. for (var i = 0 ; i < this.mixed.length ; i++) {
  99. var autoplay = (i == 0) ? true: false;
  100. this.cards.push(this.$.gamebox.createComponent({ kind: "FoodChain.Card", cardname: this.mixed[i], x: x+"%", y: y, ontap: "taped", ondragstart: "dragstart", ondragfinish: "dragfinish"}, {owner: this}));
  101. if (i == 0) {
  102. FoodChain.sound.play(this.cards[i].sound);
  103. } else {
  104. this.cards[i].hide();
  105. }
  106. x = x + step;
  107. }
  108. // Box handling
  109. this.dragobject = null;
  110. this.selectedobject = null;
  111. this.zmax = 0;
  112. this.$.gamebox.removeClass("box-win");
  113. this.$.gamebox.removeClass("box-lost");
  114. // Saving context
  115. FoodChain.saveContext();
  116. // Button handling
  117. this.$.play.hide();
  118. this.$.pause.show();
  119. this.$.validate.show();
  120. this.$.restart.hide();
  121. this.$.forward.hide();
  122. this.$.home.hide();
  123. // Timer and level init
  124. this.$.level.setContent(" "+this.level);
  125. this.timecount = {mins:0, secs:0, tenth:0};
  126. this.$.timercount.removeClass("timer-overtime");
  127. this.displayTimer();
  128. this.$.timer.pause();
  129. this.render();
  130. },
  131. // Sound ended, play next card if any
  132. endSound: function(e, s) {
  133. // All is already displayed
  134. if (this.cards == null)
  135. return;
  136. // Display next card
  137. for (var i = 0 ; i < this.cards.length ; i++ ) {
  138. if (this.cards[i] != null && FoodChain.soundMatch(this.cards[i].sound,s.sound)) {
  139. this.cards[i] = null;
  140. if (i+1 < this.cards.length) {
  141. this.cards[i+1].show();
  142. FoodChain.sound.play(this.cards[i+1].sound);
  143. return;
  144. }
  145. }
  146. }
  147. // All card displayed, start timer
  148. this.cards = null;
  149. this.$.timer.resume();
  150. },
  151. // Display timer value
  152. displayTimer: function() {
  153. this.$.timercount.setContent(this.timecount.mins+":"+String("00"+this.timecount.secs).slice(-2)+","+this.timecount.tenth);
  154. },
  155. // Update timer
  156. updateTimer: function(s, e) {
  157. this.timecount.tenth = this.timecount.tenth + 1;
  158. if (this.timecount.tenth == 10) {
  159. this.timecount.tenth = 0;
  160. this.timecount.secs = this.timecount.secs + 1;
  161. var currentcount = this.timecount.mins * 60 + this.timecount.secs;
  162. if (currentcount >= FoodChain.buildLevels[this.level-1].time) {
  163. this.$.timercount.addClass("timer-overtime");
  164. }
  165. if (this.timecount.secs == 60) {
  166. this.timecount.secs = 0;
  167. this.timecount.mins = this.timecount.mins + 1;
  168. }
  169. }
  170. this.displayTimer();
  171. },
  172. // Play sound when card taped, set card as selected (avoid need of drag&drop)
  173. taped: function(s, e) {
  174. if (this.$.timer.paused)
  175. return true;
  176. FoodChain.log(s.cardname+" taped");
  177. // Use selection to avoid drag&drop
  178. if (this.selectedobject == null) {
  179. // No selection, set card as selected, play sound
  180. this.selectedobject = s;
  181. s.addClass("card-dragged");
  182. FoodChain.sound.play(s.sound);
  183. this.toTop(s);
  184. return true;
  185. } else if (s != this.selectedobject) {
  186. // A card is already selected, swap the 2 card
  187. var startx = this.selectedobject.getX(), starty = this.selectedobject.getY();
  188. var endx = s.getX(), endy = s.getY();
  189. this.selectedobject.moveTo(endx, endy);
  190. s.moveTo(startx, starty);
  191. this.selectedobject.removeClass("card-dragged");
  192. this.selectedobject = null;
  193. return true;
  194. }
  195. },
  196. // Tap on the board unselect current card
  197. unselect: function() {
  198. if (this.selectedobject != null) {
  199. this.selectedobject.removeClass("card-dragged");
  200. this.selectedobject = null;
  201. }
  202. },
  203. // Card drag start, change style to dragged
  204. dragstart: function(s, e) {
  205. if (this.$.timer.paused)
  206. return true;
  207. s.addClass("card-dragged");
  208. this.$.gamebox.addClass("box-dragging");
  209. FoodChain.sound.play(s.sound);
  210. this.dragobject = s;
  211. this.selectedobject = null;
  212. this.dragx = 0;
  213. this.dragy = e.clientY-s.y;
  214. this.toTop(this.dragobject);
  215. },
  216. // Card drag end, change style to not dragged
  217. dragfinish: function(s, e) {
  218. s.removeClass("card-dragged");
  219. this.$.gamebox.removeClass("box-dragging");
  220. },
  221. // Drag over the box, allow dragging
  222. dragover: function(s, e) {
  223. if (this.dragobject == null)
  224. return true;
  225. e.preventDefault();
  226. return false;
  227. },
  228. // Dropped in the box, change card parent
  229. drop: function(s, e) {
  230. if (this.dragobject == null || this.$.timer.paused)
  231. return true;
  232. e.preventDefault();
  233. this.dragobject.moveTo((e.clientX/window.innerWidth)*100+"%", e.clientY-this.dragy);
  234. this.dragobject = null;
  235. },
  236. // Set the card to top of the stack
  237. toTop: function(card) {
  238. this.zmax = this.zmax + 1;
  239. card.applyStyle("z-index", this.zmax)
  240. },
  241. // Validate cards order
  242. controlOrder: function() {
  243. // Stop timer
  244. this.$.timer.pause();
  245. // Hide button
  246. this.$.play.hide();
  247. this.$.pause.hide();
  248. this.$.validate.hide();
  249. // Get cards
  250. var cards = [];
  251. enyo.forEach(this.$.gamebox.getControls(), function(card) {
  252. cards.push(card);
  253. });
  254. // Sort using x card position
  255. cards = cards.sort(function (c1, c2) { return c1.x.replace("%","") - c2.x.replace("%",""); });
  256. // Check order
  257. var win = true;
  258. for (var i = 0 ; win && i < this.chain.length ; i++) {
  259. if (cards[i].cardname != this.chain[i])
  260. win = false;
  261. }
  262. // Play win or loose sound
  263. if (win) {
  264. FoodChain.sound.play("audio/applause");
  265. this.$.gamebox.addClass("box-win");
  266. this.computeScore();
  267. this.$.home.show();
  268. if (this.level != FoodChain.buildLevels.length)
  269. this.$.forward.show();
  270. }
  271. else {
  272. FoodChain.sound.play("audio/disappointed");
  273. this.$.gamebox.addClass("box-lost");
  274. this.$.home.show();
  275. this.$.restart.show();
  276. }
  277. },
  278. // Compute score
  279. computeScore: function() {
  280. var score = 10;
  281. var currentcount = this.timecount.mins * 60 + this.timecount.secs;
  282. if (currentcount < FoodChain.buildLevels[this.level-1].time) {
  283. score += (FoodChain.buildLevels[this.level-1].time - currentcount);
  284. }
  285. FoodChain.context.score += score;
  286. this.$.score.setContent(String("0000"+FoodChain.context.score).slice(-4));
  287. },
  288. // Resume game
  289. play: function() {
  290. // Show cards
  291. enyo.forEach(this.$.gamebox.getControls(), function(card) {
  292. card.show();
  293. });
  294. // Show pause button, hide play button
  295. this.$.timer.resume();
  296. this.$.play.hide();
  297. this.$.pause.show();
  298. this.$.home.hide();
  299. },
  300. // Pause game
  301. pause: function() {
  302. // Hide cards
  303. enyo.forEach(this.$.gamebox.getControls(), function(card) {
  304. card.hide();
  305. });
  306. // Show play button, hide pause button
  307. this.$.timer.pause();
  308. this.$.pause.hide();
  309. this.$.play.show();
  310. this.$.home.show();
  311. },
  312. // Restart the current level
  313. restart: function() {
  314. this.levelChanged();
  315. },
  316. // Go to the next level
  317. next: function() {
  318. this.level = this.level + 1;
  319. this.previous = this.chain;
  320. this.mixed = null;
  321. this.levelChanged();
  322. },
  323. // Go to the home page of the app
  324. home: function() {
  325. this.$.timer.stop();
  326. FoodChain.goHome();
  327. }
  328. });