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.

495 lines
14 KiB

  1. // Play class
  2. enyo.kind({
  3. name: "TankOp.Play",
  4. kind: enyo.Control,
  5. classes: "board",
  6. published: { level: 0 },
  7. components: [
  8. // Playing zone
  9. {name: "gamebox", classes: "game-box", ontap: "gameClick", components: [
  10. ]},
  11. // Status and score
  12. {classes: "status-line", components: [
  13. {name: "wavetext", classes: "wave-text no-select-content"},
  14. {name: "wave", content: "1", classes: "wave-value no-select-content"},
  15. {name: "scoretext", classes: "score-text no-select-content"},
  16. {name: "score", content: "0000", classes: "score-value no-select-content"}
  17. ]},
  18. // Home button
  19. {kind: "Image", classes: "home-button no-select-content", src: "images/gohome.png", ontap: "goHome"},
  20. // LCD counter and Keyboard
  21. {name: "keyboard", classes: "keyboard-set no-select-content", components: [
  22. {classes: "display-line", components: [
  23. {name: "lcd", kind: "LcdDisplay", classes: "lcd-value", size: 3, value: ""}
  24. ]},
  25. {classes: "keyboard-line", components: [
  26. {kind: "Image", src: "images/key_1.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  27. {kind: "Image", src: "images/key_2.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  28. {kind: "Image", src: "images/key_3.svg", classes: "keyboard", ontap: "virtkeyPressed"}
  29. ]},
  30. {classes: "keyboard_line", components: [
  31. {kind: "Image", src: "images/key_4.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  32. {kind: "Image", src: "images/key_5.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  33. {kind: "Image", src: "images/key_6.svg", classes: "keyboard", ontap: "virtkeyPressed"}
  34. ]},
  35. {classes: "keyboard_line", components: [
  36. {kind: "Image", src: "images/key_7.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  37. {kind: "Image", src: "images/key_8.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  38. {kind: "Image", src: "images/key_9.svg", classes: "keyboard", ontap: "virtkeyPressed"}
  39. ]},
  40. {classes: "keyboard_line", components: [
  41. {kind: "Image", src: "images/key_0.svg", classes: "keyboard", ontap: "virtkeyPressed"},
  42. {kind: "Image", src: "images/key_fire.svg", classes: "keyboard", ontap: "virtkeyPressed"}
  43. ]}
  44. ]},
  45. // Key handling
  46. {kind: "Signals", onkeypress: "keyPressed"},
  47. // Image cache
  48. {kind: "ImageCache", showing: false, onCacheLoaded: "cacheLoaded"}
  49. ],
  50. // Constructor
  51. create: function() {
  52. this.inherited(arguments);
  53. play = this;
  54. this.imagesToLoad++;
  55. this.endOfGame = false;
  56. this.pausedGame = true;
  57. this.initializedGame = false;
  58. this.waitForClick = false;
  59. // Init canvas
  60. var wsize = document.body.clientWidth;
  61. if (wsize <= 480) {
  62. this.zoom = 0.4;
  63. } else if (wsize <= 640) {
  64. this.zoom = 0.55;
  65. } else if (wsize <= 768) {
  66. this.zoom = 0.62;
  67. } else if (wsize <= 854) {
  68. this.zoom = 0.65;
  69. } else if (wsize <= 960) {
  70. this.zoom = 0.75;
  71. } else if (wsize <= 1024) {
  72. this.zoom = 0.88;
  73. } else {
  74. this.zoom = 1;
  75. }
  76. this.$.gamebox.setStyle("max-height: "+(this.zoom*constant.areaHeight)+"px;");
  77. this.canvas = this.$.gamebox.createComponent({kind: "Canvas", id: "acanvas", name: "canvas", attributes: {width: constant.areaWidth, height: constant.areaHeight}});
  78. // Start game loop
  79. this.loopTimer = window.setInterval(enyo.bind(this, "gameLoopTick"), constant.loopInterval);
  80. },
  81. // Init game
  82. initGame: function() {
  83. // Game init
  84. var level = this.currentlevel = preferences.levels[this.level];
  85. var settings_map = level.map;
  86. var settings_hq = level.defense[0];
  87. var settings_soldier = level.defense[1];
  88. var settings_tank = level.defense[2];
  89. var settings_canon = level.defense[3];
  90. var settings_helo = level.defense[4];
  91. // Init board
  92. this.initializedGame = true;
  93. this.game = util.createMap(preferences.gameMap(settings_map));
  94. this.targetpos = {x: 7, y: 4};
  95. this.$.wavetext.setContent(l10n.get("Wave"));
  96. this.$.scoretext.setContent(l10n.get("Score"));
  97. // Init units
  98. var width = constant.boardWidth, height = constant.boardHeight;
  99. var goodEngine = enyo.bind(this, "goodEngine");
  100. this.units = []
  101. // Set HQ
  102. var step = constant.boardHeight/(settings_hq+1);
  103. var hqs = [];
  104. for (var i = 0 ; i < settings_hq ; i++) {
  105. var hq = util.createUnit({type: "hq", color: "blue", x: 0, y: Math.floor((i+1)*step), engine: null});
  106. this.units.push(hq);
  107. hqs.push(hq);
  108. }
  109. // Create defending units
  110. var defense = [];
  111. for(var i = 0 ; i < settings_helo ; i++)
  112. defense.push({type: "helo", color: "blue", engine: goodEngine});
  113. for(var i = 0 ; i < settings_canon ; i++)
  114. defense.push({type: "canon", color: "blue", engine: goodEngine});
  115. for(var i = 0 ; i < settings_tank ; i++)
  116. defense.push({type: "tank", color: "blue", engine: goodEngine});
  117. for(var i = 0 ; i < settings_soldier ; i++)
  118. defense.push({type: "soldier", color: "blue", engine: goodEngine});
  119. // Set defense around hq
  120. if (defense.length > 0) {
  121. var hqindex = 0;
  122. var defenselength = Math.min(defense.length, 1+hqs.length*2);
  123. for (var i = 0 ; i < defenselength ; i++) {
  124. var position = {};
  125. do {
  126. var arounds = [{dx: 1, dy: 0}, {dx: 0, dy: -1}, {dx: 0, dy: 1}];
  127. for (j = 0 ; j < arounds.length ; j++) {
  128. position = {x: hqs[hqindex].x+arounds[j].dx, y: hqs[hqindex].y+arounds[j].dy};
  129. if (util.lookForUnit(position) == null)
  130. break;
  131. else
  132. position = {x: -1, y: -1};
  133. }
  134. hqindex = (hqindex + 1) % hqs.length;
  135. } while (position.x == -1);
  136. defense[i].x = position.x;
  137. defense[i].y = position.y;
  138. this.units.push(util.createUnit(defense[i]));
  139. }
  140. }
  141. // Prepare bad units arrival
  142. this.score = 0;
  143. this.wave = 1;
  144. this.enemyCount = level.attack;
  145. this.enemyWaveSize = constant.waveInitSize;
  146. this.enemyNextWaveCount = constant.waveInitSize;
  147. this.enemyWaveCount = 0;
  148. this.enemyArrivalTurn = constant.startArrival;
  149. // Let's Go !
  150. this.pausedGame = false;
  151. },
  152. // Render
  153. rendered: function() {
  154. // Init game
  155. if (!this.initializedGame) {
  156. // Init context
  157. this.initGame();
  158. // Set zoom
  159. this.canvas.hasNode().style.MozTransform = "scale("+this.zoom+")";
  160. this.canvas.hasNode().style.MozTransformOrigin = "0 0";
  161. this.canvas.hasNode().style.zoom = this.zoom;
  162. }
  163. },
  164. cacheLoaded: function() {
  165. },
  166. // Draw
  167. draw: function() {
  168. // Clear all
  169. var ctx = this.canvas.hasNode().getContext('2d');
  170. ctx.clearRect(0, 0, this.canvas.attributes.width, this.canvas.attributes.height);
  171. // Draw board
  172. var grass = document.getElementById("grass");
  173. var trees = document.getElementById("trees");
  174. var mountain = document.getElementById("mountain");
  175. var water = document.getElementById("water");
  176. for (var i = 0 ; i < constant.boardHeight ; i++ ) {
  177. for (var j = 0 ; j < constant.boardWidth ; j++ ) {
  178. ctx.save();
  179. ctx.translate(j*constant.tileSize, i*constant.tileSize);
  180. ctx.drawImage(grass, 0, 0);
  181. var tileType = this.game[i][j];
  182. if (tileType == constant.tileTrees)
  183. ctx.drawImage(trees, 0, 0);
  184. else if (tileType == constant.tileMountain)
  185. ctx.drawImage(mountain, 0, 0);
  186. else if (tileType == constant.tileWater)
  187. ctx.drawImage(water, 0, 0);
  188. ctx.restore();
  189. }
  190. }
  191. // Draw tanks
  192. if (!this.endOfGame) {
  193. for (var i = 0 ; i < this.units.length ; i++)
  194. this.units[i].draw(ctx);
  195. // Draw target
  196. var target = document.getElementById("target");
  197. ctx.save();
  198. ctx.translate(this.targetpos.x*constant.tileSize, this.targetpos.y*constant.tileSize);
  199. ctx.drawImage(target, 0, 0);
  200. ctx.restore();
  201. }
  202. // End of game
  203. else {
  204. // Draw end of game screen
  205. var endscreen = this.win ? document.getElementById("endgame_victory") : document.getElementById("endgame_defeat");
  206. ctx.save();
  207. ctx.translate((constant.areaWidth-constant.endGameWidth)/2, (constant.areaHeight-constant.endGameHeight)/2);
  208. ctx.drawImage(endscreen, 0, 0);
  209. ctx.restore();
  210. // Play end of game sound
  211. if (!this.waitForClick) {
  212. sound.play(this.win ? "audio/mission_completed" : "audio/mission_failed", true);
  213. this.waitForClick = true;
  214. }
  215. }
  216. },
  217. // A key was pressed
  218. keyPressed: function(s, e) {
  219. var key = e.charCode;
  220. if (this.endOfGame)
  221. return;
  222. // Digit key
  223. if (key >= 48 && key <= 57) {
  224. // Add digit to string
  225. var value = this.$.lcd.getValue();
  226. if (value.length == this.$.lcd.getSize())
  227. value = value.substr(1);
  228. value += String.fromCharCode(key);
  229. this.$.lcd.setValue(value);
  230. }
  231. // Dash key
  232. else if (key == 45) {
  233. this.$.lcd.setValue("-");
  234. }
  235. // Fire key
  236. else if (key == 32) {
  237. // Look for unit with the value
  238. var units = util.lookForValue(this.$.lcd.getValue().replace(/ /g,''));
  239. if (units.length != 0) {
  240. for (var i = 0 ; i < units.length ; i++) {
  241. util.processFight(null, units[i], constant.userPower);
  242. this.targetpos.x = units[i].x;
  243. this.targetpos.y = units[i].y;
  244. }
  245. }
  246. else
  247. sound.play("audio/missed");
  248. this.$.lcd.setValue("");
  249. }
  250. },
  251. // A virtual key is pressed
  252. virtkeyPressed: function(s) {
  253. var classes = s.getSrc().replace(".svg", "");
  254. var value = classes.substr("images/key_".length,classes.indexOf("key_"));
  255. if (value == "fire")
  256. this.keyPressed(null, {charCode: 32});
  257. else
  258. this.keyPressed(null, {charCode: 48+parseInt(value)});
  259. },
  260. goHome: function() {
  261. // Click at the end of game
  262. if (this.waitForClick) {
  263. this.gameClick();
  264. return;
  265. }
  266. // Stop game loop
  267. window.clearInterval(this.loopTimer);
  268. // Back to app
  269. app.init();
  270. app.playTheme()
  271. app.renderInto(document.getElementById("board"));
  272. },
  273. // A tap occur on the game
  274. gameClick: function() {
  275. // At end of game, quit
  276. if (this.endOfGame) {
  277. // Stop game loop
  278. window.clearInterval(this.loopTimer);
  279. // Set mission result
  280. if (this.win) {
  281. preferences.levels[this.level].completed = true;
  282. app.nextMission();
  283. app.save();
  284. }
  285. app.init();
  286. // Back to app
  287. app.renderInto(document.getElementById("board"));
  288. }
  289. // Compute direction
  290. var screen_width = document.documentElement.clientWidth;
  291. var screen_height = document.documentElement.clientHeight;
  292. var center_x = Math.floor(screen_width/2.0);
  293. var center_y = Math.floor((screen_height+constant.pubHeight)/2.0);
  294. var diffx = mouse.position.x-center_x, diffy = mouse.position.y-center_y;
  295. var absdiffx = Math.abs(diffx);
  296. var absdiffy = Math.abs(diffy);
  297. if (absdiffx >= 0 && absdiffx < constant.fireZoneWidth && absdiffy >= 0 && absdiffy < constant.fireZoneHeight) {
  298. var targetunit = util.lookForUnit(this.targetpos);
  299. if (targetunit != null)
  300. util.processFight(null, targetunit);
  301. return;
  302. } else if (absdiffx > absdiffy) {
  303. dx = diffx > 0 ? 1 : -1;
  304. dy = 0;
  305. } else {
  306. dx = 0;
  307. dy = diffy > 0 ? 1 : -1;
  308. }
  309. // Move target
  310. var newX = this.targetpos.x + dx;
  311. var newY = this.targetpos.y + dy;
  312. if (newX < 0 || newX == constant.boardWidth || newY < 0 || newY == constant.boardHeight)
  313. return;
  314. this.targetpos.x = newX;
  315. this.targetpos.y = newY;
  316. },
  317. // Tick for game loop
  318. gameLoopTick: function() {
  319. if (this.pausedGame)
  320. return;
  321. // Sanitize: clean dead units and compute victory/defeat conditions
  322. var alives = [];
  323. var hqs = [];
  324. var livingHq = 0;
  325. var livingEnemy = 0;
  326. for (var i = 0 ; i < this.units.length ; i++) {
  327. var unit = this.units[i];
  328. var isRed = unit.getCurrentImage().indexOf("red") != -1;
  329. if (unit.power > 0) {
  330. alives.push(unit);
  331. } else {
  332. if (isRed) {
  333. this.enemyNextWaveCount--;
  334. this.score += util.unitPowers[util.getUnitType(unit)];
  335. }
  336. continue;
  337. }
  338. if (util.getUnitType(unit) == 0) {
  339. hqs[livingHq++] = unit;
  340. }
  341. if (isRed)
  342. livingEnemy++;
  343. }
  344. this.units = alives;
  345. this.endOfGame = (livingHq == 0 || (livingEnemy == 0 && this.enemyCount == 0));
  346. this.win = (livingHq > 0);
  347. // Game play
  348. if (!this.endOfGame) {
  349. // Next wave
  350. if (this.enemyNextWaveCount == 0) {
  351. this.wave++;
  352. this.enemyWaveSize += 2;
  353. this.enemyWaveCount = 0;
  354. this.enemyNextWaveCount = this.enemyWaveSize;
  355. this.enemyArrivalTurn = constant.startArrival;
  356. }
  357. // Enemy arrival
  358. else if (this.enemyWaveCount != this.enemyWaveSize) {
  359. if (this.enemyArrivalTurn == 0 && this.enemyCount > 0) {
  360. var badEngine = enyo.bind(this, "badEngine");
  361. var unit = util.createUnit({
  362. type: util.randomUnit(this.currentlevel.stats),
  363. color: "red",
  364. heading: 0,
  365. engine: badEngine,
  366. x: constant.boardWidth-1,
  367. y: util.random(constant.boardHeight)
  368. });
  369. unit.value = this.currentlevel.generator();
  370. this.units.push(unit);
  371. this.enemyCount = this.enemyCount-1;
  372. this.enemyWaveCount++;
  373. this.enemyArrivalTurn = constant.startArrival;
  374. } else {
  375. this.enemyArrivalTurn = this.enemyArrivalTurn - 1;
  376. }
  377. }
  378. // Launch engine for each unit
  379. for (var i = 0 ; i < this.units.length ; i++) {
  380. var engine = this.units[i].engine;
  381. if (engine != null)
  382. engine(this.units[i], hqs);
  383. }
  384. }
  385. // Draw
  386. this.draw();
  387. // HACK: On Android, force redraw of canvas
  388. if (enyo.platform.android && document.location.protocol.substr(0,4) != "http") {
  389. document.getElementById('acanvas').style.display='none';
  390. document.getElementById('acanvas').offsetHeight;
  391. document.getElementById('acanvas').style.display='block';
  392. }
  393. // Draw score
  394. this.$.wave.setContent(String("0000"+this.wave).slice(-4))
  395. this.$.score.setContent(String("0000"+this.score).slice(-4))
  396. },
  397. // Engine for good tank moves
  398. goodEngine: function(that, hqs) {
  399. // Look for enemy unit
  400. var opponent = util.lookForOpponent(that);
  401. if (opponent != null) {
  402. // Change heading toward opponent
  403. that.heading = opponent.heading;
  404. // Fight
  405. util.processFight(that, opponent.unit);
  406. return;
  407. }
  408. },
  409. // Engine for bad tank moves
  410. badEngine: function(that, hqs) {
  411. // Look for enemy unit around
  412. var opponent = util.lookForOpponent(that);
  413. if (opponent != null) {
  414. // Change heading toward opponent
  415. that.heading = opponent.heading;
  416. // Fight
  417. util.processFight(that, opponent.unit);
  418. return;
  419. }
  420. // Change heading to go toward the nearest HQ
  421. var nearestHQ = util.nearestUnit(that, hqs);
  422. if (nearestHQ != null) {
  423. var dx = that.x - nearestHQ.x;
  424. var dy = that.y - nearestHQ.y;
  425. if (Math.abs(dx) > Math.abs(dy))
  426. that.heading = dx > 0 ? 0 : 2;
  427. else
  428. that.heading = dy > 0 ? 1 : 3;
  429. }
  430. // Is it a valid position ?
  431. var next = util.nextPositionOnHeading(that);
  432. while (!util.isValidPosition(next, that)) {
  433. // No, try a random heading
  434. that.heading = util.random(4);
  435. next = util.nextPositionOnHeading(that);
  436. }
  437. next = util.nextPositionOnHeading(that);
  438. that.x = next.x;
  439. that.y = next.y;
  440. }
  441. });