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.

486 lines
17 KiB

  1. define(["sugar-web/activity/activity", "sugar-web/graphics/radiobuttonsgroup", "sugar-web/graphics/presencepalette", "sugar-web/env", "sugar-web/graphics/icon", "sugar-web/datastore", "webL10n", "humane"], function (activity, radioButtonsGroup, presencepalette, env, icon, datastore, webL10n, humane) {
  2. var app;
  3. var presence=null;
  4. var isHost=false;
  5. var numberofplayers=0;
  6. var opponentuser=null;
  7. var levelRadio;
  8. var xoLogo = '<?xml version="1.0" ?><!DOCTYPE svg PUBLIC \'-//W3C//DTD SVG 1.1//EN\' \'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\' [<!ENTITY stroke_color "#010101"><!ENTITY fill_color "#FFFFFF">]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_"><path d="M33.233,35.1l10.102,10.1c0.752,0.75,1.217,1.783,1.217,2.932 c0,2.287-1.855,4.143-4.146,4.143c-1.145,0-2.178-0.463-2.932-1.211L27.372,40.961l-10.1,10.1c-0.75,0.75-1.787,1.211-2.934,1.211 c-2.284,0-4.143-1.854-4.143-4.141c0-1.146,0.465-2.184,1.212-2.934l10.104-10.102L11.409,24.995 c-0.747-0.748-1.212-1.785-1.212-2.93c0-2.289,1.854-4.146,4.146-4.146c1.143,0,2.18,0.465,2.93,1.214l10.099,10.102l10.102-10.103 c0.754-0.749,1.787-1.214,2.934-1.214c2.289,0,4.146,1.856,4.146,4.145c0,1.146-0.467,2.18-1.217,2.932L33.233,35.1z" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/><circle cx="27.371" cy="10.849" fill="&fill_color;" r="8.122" stroke="&stroke_color;" stroke-width="3.5"/></g></svg>';
  9. var generateXOLogoWithColor = function(color) {
  10. var coloredLogo = xoLogo;
  11. coloredLogo = coloredLogo.replace("#010101", color.stroke)
  12. coloredLogo = coloredLogo.replace("#FFFFFF", color.fill)
  13. return "data:image/svg+xml;base64," + btoa(coloredLogo);
  14. }
  15. env.getEnvironment(function(err, environment) {
  16. currentenv=environment;
  17. // Set current language to Sugarizer
  18. var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
  19. var language = environment.user ? environment.user.language : defaultLanguage;
  20. webL10n.language.code = language;
  21. // Shared instances
  22. if (environment.sharedId) {
  23. console.log("Shared instance");
  24. document.getElementById("level-easy-button").classList.remove('active');
  25. document.getElementById("level-medium-button").classList.remove('active');
  26. document.getElementById("level-hard-button").classList.remove('active');
  27. document.getElementById("level-easy-button").setAttribute('disabled', 'disabled');
  28. document.getElementById("level-easy-button").setAttribute('title', 'Not available in multiplayer');
  29. document.getElementById("level-medium-button").setAttribute('disabled', 'disabled');
  30. document.getElementById("level-medium-button").setAttribute('title', 'Not available in multiplayer');
  31. document.getElementById("level-hard-button").setAttribute('disabled', 'disabled');
  32. document.getElementById("level-hard-button").setAttribute('title', 'Not available in multiplayer');
  33. document.getElementById("switch-player-button").setAttribute('disabled', 'disabled');
  34. document.getElementById("switch-player-button").setAttribute('title', 'Only Host can do it');
  35. document.getElementById("new-game-button").setAttribute('disabled', 'disabled');
  36. document.getElementById("new-game-button").setAttribute('title', 'Only Host can do it');
  37. presence = activity.getPresenceObject(function(error, network) {
  38. network.listSharedActivityUsers(environment.sharedId, function(users) {
  39. for (var i = 0 ; i < users.length ;i++) {
  40. if (users[i].networkId != network.getUserInfo().networkId) {
  41. opponentuser = users[i];
  42. break;
  43. }
  44. }
  45. });
  46. network.onDataReceived(enyo.bind(app, "onNetworkDataReceived"));
  47. network.onSharedActivityUserChanged(enyo.bind(app, "onNetworkUserChanged"));
  48. });
  49. }
  50. });
  51. // Manipulate the DOM only when it is ready.
  52. requirejs(['domReady!'], function (doc) {
  53. // Initialize the Sugar activity.
  54. activity.setup();
  55. // Initialize buttons
  56. document.getElementById("new-game-button").onclick = function() {
  57. app.doRenew();
  58. };
  59. levelRadio = new radioButtonsGroup.RadioButtonsGroup([
  60. document.getElementById("level-easy-button"),
  61. document.getElementById("level-medium-button"),
  62. document.getElementById("level-hard-button")]
  63. );
  64. document.getElementById("switch-player-button").onclick = function() {
  65. app.switchPlayer();
  66. if (presence) {
  67. presence.sendMessage(presence.getSharedInfo().id, {
  68. user: presence.getUserInfo(),
  69. action: "update",
  70. content: 0
  71. });
  72. }
  73. if(isHost)
  74. document.getElementById("switch-player-button").disabled = true;
  75. };
  76. // Initialize the game
  77. app = new LOLGameApp({activity: activity});
  78. app.load();
  79. app.renderInto(document.getElementById("canvas"));
  80. // Link presence palette
  81. var palette = new presencepalette.PresencePalette(document.getElementById("network-button"), undefined);
  82. palette.addEventListener('shared', function() {
  83. palette.popDown();
  84. console.log("Want to share");
  85. presence = activity.getPresenceObject(function(error, network) {
  86. if (error) {
  87. console.log("Sharing error");
  88. return;
  89. }
  90. network.createSharedActivity('org.olpc-france.LOLActivity', function(groupId) {
  91. console.log("Activity shared");
  92. document.getElementById("level-easy-button").classList.remove('active');
  93. document.getElementById("level-medium-button").classList.remove('active');
  94. document.getElementById("level-hard-button").classList.remove('active');
  95. document.getElementById("level-easy-button").setAttribute('disabled', 'disabled');
  96. document.getElementById("level-easy-button").setAttribute('title', 'Not available in multiplayer');
  97. document.getElementById("level-medium-button").setAttribute('disabled', 'disabled');
  98. document.getElementById("level-medium-button").setAttribute('title', 'Not available in multiplayer');
  99. document.getElementById("level-hard-button").setAttribute('disabled', 'disabled');
  100. document.getElementById("level-hard-button").setAttribute('title', 'Not available in multiplayer');
  101. isHost=true;
  102. app.drawBoard();
  103. });
  104. network.onDataReceived(enyo.bind(app, "onNetworkDataReceived"));
  105. network.onSharedActivityUserChanged(enyo.bind(app, "onNetworkUserChanged"));
  106. });
  107. });
  108. });
  109. // Main app class
  110. enyo.kind({
  111. name: "LOLGameApp",
  112. kind: enyo.Control,
  113. published: {size: 13, level: 1, count: 13, activity: null},
  114. components: [
  115. {classes: "playboard", components:[
  116. {name: "player", classes: "player-image"},
  117. {name: "box", classes: "lol-box", components: [
  118. ]},
  119. {name: "computer", classes: "computer-image"}
  120. ]},
  121. {name: "playbutton", kind: "Image", src: "icons/play.png", classes: "play", ontap: "doPlay", showing: false},
  122. {name: "endaudio", kind: "HTML5.Audio", preload: "auto", autobuffer: true, controlsbar: false},
  123. {name: "endmessage", content: "", showing: false, classes: "end-message"}
  124. ],
  125. // Constructor
  126. create: function() {
  127. this.inherited(arguments);
  128. this.init();
  129. },
  130. // Init game
  131. init: function() {
  132. // Init game context
  133. this.game = new LOLGame(this.count);
  134. if (this.count > 0) this.player = this.game.getPlayer();
  135. this.count = this.size;
  136. this.selectedCount = 0;
  137. // Initialize level
  138. document.getElementById("level-easy-button").classList.remove('active');
  139. document.getElementById("level-medium-button").classList.remove('active');
  140. document.getElementById("level-hard-button").classList.remove('active');
  141. if (!presence) {
  142. if (this.level == 1) document.getElementById("level-easy-button").classList.add('active');
  143. else if (this.level == 2) document.getElementById("level-medium-button").classList.add('active');
  144. else if (this.level == 3) document.getElementById("level-hard-button").classList.add('active');
  145. }
  146. },
  147. // Render
  148. rendered: function() {
  149. this.inherited(arguments);
  150. // Draw board
  151. this.drawBoard();
  152. },
  153. // Redraw the board
  154. drawBoard: function() {
  155. // Clean board
  156. this.selectedCount = 0;
  157. var items = [];
  158. enyo.forEach(this.$.box.getControls(), function(item) {
  159. items.push(item);
  160. });
  161. for (var i = 0 ; i < items.length ; i++) {
  162. items[i].destroy();
  163. }
  164. // Redraw board
  165. for (var i = 0 ; i < this.game.getLength(); i++) {
  166. this.$.box.createComponent(
  167. { kind: "LOLItem", ontap: "selectItem" },
  168. { owner: this }
  169. ).render();
  170. }
  171. this.showCurrentPlayer();
  172. document.getElementById("switch-player-button").disabled = (this.game.getLength() != this.size);
  173. // Test end condition
  174. if (this.game.endOfGame()) {
  175. if (!presence) {
  176. this.$.endmessage.addClass(this.game.getPlayer() != this.player ? "end-message-win" : "end-message-lost");
  177. this.$.endmessage.removeClass(this.game.getPlayer() != this.player ? "end-message-lost" : "end-message-win");
  178. } else {
  179. this.$.player.addClass("empty-image");
  180. this.$.computer.addClass("empty-image");
  181. this.$.computer.removeClass("oponent-image");
  182. this.$.endmessage.removeClass("end-message-lost");
  183. this.$.endmessage.addClass(this.game.getPlayer() != this.player ? "end-message-win" : "player-lost");
  184. this.$.endmessage.removeClass(this.game.getPlayer() != this.player ? "player-lost" : "end-message-win");
  185. }
  186. this.$.endaudio.setSrc(this.game.getPlayer() != this.player ? "audio/applause.ogg" : "audio/disappointed.ogg");
  187. this.$.endaudio.play();
  188. this.$.endmessage.show();
  189. }
  190. this.$.endmessage.setShowing(this.game.endOfGame());
  191. // Play for computer
  192. if (this.game.getPlayer() != this.player && !this.game.endOfGame()) {
  193. if (presence) {
  194. this.oponentPlay();
  195. } else {
  196. this.computerPlay();
  197. }
  198. }
  199. },
  200. Stop: function() {
  201. var stopEvent = document.createEvent("CustomEvent");
  202. stopEvent.initCustomEvent('activityStop', false, false, {
  203. 'cancelable': true
  204. });
  205. var result = window.dispatchEvent(stopEvent);
  206. if (result) {
  207. activity.close();
  208. }
  209. },
  210. onNetworkDataReceived: function(msg) {
  211. if (presence.getUserInfo().networkId === msg.user.networkId) {
  212. return;
  213. }
  214. switch(msg.action){
  215. case 'init':
  216. console.log("init");
  217. this.game = new LOLGame(msg.content);
  218. this.game.reverse();
  219. app.drawBoard();
  220. opponentuser=msg.user;
  221. break;
  222. case 'update':
  223. console.log("update");
  224. if (msg.content > 0) {
  225. this.doOpponent(msg.content);
  226. } else {
  227. this.game.reverse();
  228. app.drawBoard();
  229. }
  230. break;
  231. case 'exit':
  232. console.log("already two players");
  233. if(msg.content == presence.getUserInfo().networkId){
  234. app.Stop();
  235. }
  236. break;
  237. }
  238. },
  239. onNetworkUserChanged: function(msg) {
  240. var html = "<img style='height:30px;' src='" + generateXOLogoWithColor(msg.user.colorvalue) + "'>";
  241. humane.log(html + webL10n.get((msg.move == 1 ? "PlayerJoin":"PlayerLeave"),{user: msg.user.name}));
  242. console.log("User "+msg.user.name+" "+(msg.move == 1 ? "join": "leave"));
  243. if (msg.move != 1) return;
  244. if (isHost) {
  245. if (numberofplayers==0) {
  246. presence.sendMessage(presence.getSharedInfo().id, {
  247. user: presence.getUserInfo(),
  248. action: 'init',
  249. content: this.game.getLength()
  250. });
  251. numberofplayers++;
  252. opponentuser = msg.user;
  253. } else {
  254. presence.sendMessage(presence.getSharedInfo().id, {
  255. user: presence.getUserInfo(),
  256. action: 'exit',
  257. content: msg.user.networkId
  258. });
  259. }
  260. }
  261. },
  262. // Get current level
  263. getLevel: function() {
  264. var buttons = ["level-easy-button","level-medium-button","level-hard-button"];
  265. console.log(buttons.indexOf(levelRadio.getActive().id)+1);
  266. return buttons.indexOf(levelRadio.getActive().id)+1;
  267. },
  268. // Show the current player turn
  269. showCurrentPlayer: function() {
  270. if (this.player == this.game.getPlayer() && !this.game.endOfGame()) {
  271. this.$.player.removeClass("empty-image");
  272. if (this.$.player.hasNode()) icon.colorize(this.$.player.hasNode(), currentenv.user.colorvalue, function() {});
  273. }
  274. else
  275. this.$.player.addClass("empty-image");
  276. if (this.player != this.game.getPlayer() && !this.game.endOfGame())
  277. this.$.computer.removeClass("empty-image");
  278. else
  279. this.$.computer.addClass("empty-image");
  280. },
  281. // Select an item
  282. selectItem: function(item) {
  283. if (this.player != this.game.getPlayer())
  284. return;
  285. var value = item.getSelected();
  286. if (this.selectedCount == 3 && !value) {
  287. this.$.playbutton.show();
  288. return;
  289. }
  290. this.selectedCount = !value ? this.selectedCount + 1 : this.selectedCount - 1;
  291. item.setSelected(!value);
  292. if (this.selectedCount > 0)
  293. this.$.playbutton.show();
  294. else
  295. this.$.playbutton.hide();
  296. },
  297. // Switch player
  298. switchPlayer: function() {
  299. this.game.reverse();
  300. this.player = this.player % 2;
  301. this.drawBoard();
  302. },
  303. // Play for the player
  304. doPlay: function() {
  305. if (this.player != this.game.getPlayer())
  306. return;
  307. if (this.selectedCount == 0)
  308. return;
  309. this.save(this.game.play(this.selectedCount));
  310. if (presence) {
  311. presence.sendMessage(presence.getSharedInfo().id, {
  312. user: presence.getUserInfo(),
  313. action: "update",
  314. content: this.selectedCount
  315. });
  316. }
  317. this.drawBoard();
  318. this.$.playbutton.hide();
  319. },
  320. oponentPlay: function() {
  321. if (this.player == this.game.getPlayer() && !this.game.endOfGame()) {
  322. this.$.player.removeClass("empty-image");
  323. icon.colorize(this.$.player.hasNode(), currentenv.user.colorvalue, function() {});
  324. } else {
  325. this.$.player.addClass("empty-image");
  326. }
  327. if (this.player != this.game.getPlayer() && !this.game.endOfGame()){
  328. this.$.computer.removeClass("empty-image");
  329. this.$.computer.addClass("oponent-image");
  330. if (opponentuser) icon.colorize(this.$.computer.hasNode(), opponentuser.colorvalue, function() {})
  331. }else
  332. this.$.computer.addClass("empty-image");
  333. },
  334. // Let's computer play
  335. computerPlay: function() {
  336. if (this.player == this.game.getPlayer())
  337. return;
  338. this.selectedCount = 0;
  339. this.step = 0;
  340. this.timer = window.setInterval(enyo.bind(this, "doComputer"), 400+50*this.getLevel());
  341. },
  342. // Play for the computer
  343. doComputer: function() {
  344. // First, think to the shot and select item
  345. if (this.step == 0) {
  346. this.step++;
  347. var shot = this.game.think(this.getLevel());
  348. var context = this;
  349. enyo.forEach(this.$.box.getControls(), function(item) {
  350. if (context.selectedCount < shot) {
  351. item.setSelected(true);
  352. context.selectedCount++;
  353. }
  354. });
  355. this.step++;
  356. }
  357. // Then play
  358. else if (this.step == 2) {
  359. window.clearInterval(this.timer);
  360. this.save(this.game.play(this.selectedCount));
  361. this.drawBoard();
  362. }
  363. },
  364. // Play opponent
  365. doOpponent: function(shot) {
  366. var that = this;
  367. enyo.forEach(this.$.box.getControls(), function(item) {
  368. if (that.selectedCount < shot) {
  369. item.setSelected(true);
  370. that.selectedCount++;
  371. }
  372. });
  373. window.setTimeout(function() {
  374. that.game.play(shot);
  375. that.drawBoard();
  376. }, 400);
  377. },
  378. // Start a new game
  379. doRenew: function() {
  380. this.level = this.getLevel();
  381. this.game = new LOLGame(this.count);
  382. this.init();
  383. this.drawBoard();
  384. if (presence&&isHost) {
  385. presence.sendMessage(presence.getSharedInfo().id, {
  386. user: presence.getUserInfo(),
  387. action: 'init',
  388. content: this.game.getLength()
  389. });
  390. }
  391. },
  392. // Load game from datastore
  393. load: function() {
  394. var datastoreObject = this.activity.getDatastoreObject();
  395. var currentthis = this;
  396. datastoreObject.loadAsText(function (error, metadata, data) {
  397. var data = JSON.parse(data);
  398. if (data == null)
  399. return;
  400. currentthis.size = data.size;
  401. currentthis.count = data.count;
  402. currentthis.level = data.level;
  403. currentthis.player = data.player;
  404. currentthis.init();
  405. });
  406. },
  407. // Save game in datastore
  408. save: function(count) {
  409. var datastoreObject = this.activity.getDatastoreObject();
  410. var jsonData = JSON.stringify({size: this.size, count: count, level: this.getLevel(), player: this.game.getPlayer()});
  411. datastoreObject.setDataAsText(jsonData);
  412. datastoreObject.save(function() {});
  413. }
  414. });
  415. // Class for an item
  416. enyo.kind({
  417. name: "LOLItem",
  418. kind: enyo.Control,
  419. classes: "lol-item",
  420. published: { selected: false },
  421. // Constructor
  422. create: function() {
  423. this.inherited(arguments);
  424. this.selectedChanged();
  425. },
  426. // Selection changed
  427. selectedChanged: function() {
  428. var className = "lol-item-selected";
  429. if (this.selected) {
  430. this.addClass(className);
  431. this.applyStyle("background-color", currentenv.user.colorvalue.stroke);
  432. }
  433. else {
  434. this.removeClass(className);
  435. this.applyStyle("background-color", currentenv.user.colorvalue.fill);
  436. }
  437. },
  438. });
  439. });