// Play class
|
|
enyo.kind({
|
|
name: "TankOp.Play",
|
|
kind: enyo.Control,
|
|
classes: "board",
|
|
published: { level: 0 },
|
|
components: [
|
|
// Playing zone
|
|
{name: "gamebox", classes: "game-box", ontap: "gameClick", components: [
|
|
]},
|
|
|
|
// Status and score
|
|
{classes: "status-line", components: [
|
|
{name: "wavetext", classes: "wave-text no-select-content"},
|
|
{name: "wave", content: "1", classes: "wave-value no-select-content"},
|
|
{name: "scoretext", classes: "score-text no-select-content"},
|
|
{name: "score", content: "0000", classes: "score-value no-select-content"}
|
|
]},
|
|
|
|
// Home button
|
|
{kind: "Image", classes: "home-button no-select-content", src: "images/gohome.png", ontap: "goHome"},
|
|
|
|
// LCD counter and Keyboard
|
|
{name: "keyboard", classes: "keyboard-set no-select-content", components: [
|
|
{classes: "display-line", components: [
|
|
{name: "lcd", kind: "LcdDisplay", classes: "lcd-value", size: 3, value: ""}
|
|
]},
|
|
{classes: "keyboard-line", components: [
|
|
{kind: "Image", src: "images/key_1.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_2.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_3.svg", classes: "keyboard", ontap: "virtkeyPressed"}
|
|
]},
|
|
{classes: "keyboard_line", components: [
|
|
{kind: "Image", src: "images/key_4.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_5.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_6.svg", classes: "keyboard", ontap: "virtkeyPressed"}
|
|
]},
|
|
{classes: "keyboard_line", components: [
|
|
{kind: "Image", src: "images/key_7.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_8.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_9.svg", classes: "keyboard", ontap: "virtkeyPressed"}
|
|
]},
|
|
{classes: "keyboard_line", components: [
|
|
{kind: "Image", src: "images/key_0.svg", classes: "keyboard", ontap: "virtkeyPressed"},
|
|
{kind: "Image", src: "images/key_fire.svg", classes: "keyboard", ontap: "virtkeyPressed"}
|
|
]}
|
|
]},
|
|
|
|
// Key handling
|
|
{kind: "Signals", onkeypress: "keyPressed"},
|
|
|
|
// Image cache
|
|
{kind: "ImageCache", showing: false, onCacheLoaded: "cacheLoaded"}
|
|
],
|
|
|
|
// Constructor
|
|
create: function() {
|
|
this.inherited(arguments);
|
|
play = this;
|
|
this.imagesToLoad++;
|
|
this.endOfGame = false;
|
|
this.pausedGame = true;
|
|
this.initializedGame = false;
|
|
this.waitForClick = false;
|
|
|
|
// Init canvas
|
|
var wsize = document.body.clientWidth;
|
|
if (wsize <= 480) {
|
|
this.zoom = 0.4;
|
|
} else if (wsize <= 640) {
|
|
this.zoom = 0.55;
|
|
} else if (wsize <= 768) {
|
|
this.zoom = 0.62;
|
|
} else if (wsize <= 854) {
|
|
this.zoom = 0.65;
|
|
} else if (wsize <= 960) {
|
|
this.zoom = 0.75;
|
|
} else if (wsize <= 1024) {
|
|
this.zoom = 0.88;
|
|
} else {
|
|
this.zoom = 1;
|
|
}
|
|
|
|
this.$.gamebox.setStyle("max-height: "+(this.zoom*constant.areaHeight)+"px;");
|
|
this.canvas = this.$.gamebox.createComponent({kind: "Canvas", id: "acanvas", name: "canvas", attributes: {width: constant.areaWidth, height: constant.areaHeight}});
|
|
|
|
// Start game loop
|
|
this.loopTimer = window.setInterval(enyo.bind(this, "gameLoopTick"), constant.loopInterval);
|
|
},
|
|
|
|
// Init game
|
|
initGame: function() {
|
|
// Game init
|
|
var level = this.currentlevel = preferences.levels[this.level];
|
|
var settings_map = level.map;
|
|
var settings_hq = level.defense[0];
|
|
var settings_soldier = level.defense[1];
|
|
var settings_tank = level.defense[2];
|
|
var settings_canon = level.defense[3];
|
|
var settings_helo = level.defense[4];
|
|
|
|
// Init board
|
|
this.initializedGame = true;
|
|
this.game = util.createMap(preferences.gameMap(settings_map));
|
|
this.targetpos = {x: 7, y: 4};
|
|
this.$.wavetext.setContent(l10n.get("Wave"));
|
|
this.$.scoretext.setContent(l10n.get("Score"));
|
|
|
|
// Init units
|
|
var width = constant.boardWidth, height = constant.boardHeight;
|
|
var goodEngine = enyo.bind(this, "goodEngine");
|
|
this.units = []
|
|
|
|
// Set HQ
|
|
var step = constant.boardHeight/(settings_hq+1);
|
|
var hqs = [];
|
|
for (var i = 0 ; i < settings_hq ; i++) {
|
|
var hq = util.createUnit({type: "hq", color: "blue", x: 0, y: Math.floor((i+1)*step), engine: null});
|
|
this.units.push(hq);
|
|
hqs.push(hq);
|
|
}
|
|
|
|
// Create defending units
|
|
var defense = [];
|
|
for(var i = 0 ; i < settings_helo ; i++)
|
|
defense.push({type: "helo", color: "blue", engine: goodEngine});
|
|
for(var i = 0 ; i < settings_canon ; i++)
|
|
defense.push({type: "canon", color: "blue", engine: goodEngine});
|
|
for(var i = 0 ; i < settings_tank ; i++)
|
|
defense.push({type: "tank", color: "blue", engine: goodEngine});
|
|
for(var i = 0 ; i < settings_soldier ; i++)
|
|
defense.push({type: "soldier", color: "blue", engine: goodEngine});
|
|
|
|
// Set defense around hq
|
|
if (defense.length > 0) {
|
|
var hqindex = 0;
|
|
var defenselength = Math.min(defense.length, 1+hqs.length*2);
|
|
for (var i = 0 ; i < defenselength ; i++) {
|
|
var position = {};
|
|
do {
|
|
var arounds = [{dx: 1, dy: 0}, {dx: 0, dy: -1}, {dx: 0, dy: 1}];
|
|
for (j = 0 ; j < arounds.length ; j++) {
|
|
position = {x: hqs[hqindex].x+arounds[j].dx, y: hqs[hqindex].y+arounds[j].dy};
|
|
if (util.lookForUnit(position) == null)
|
|
break;
|
|
else
|
|
position = {x: -1, y: -1};
|
|
}
|
|
hqindex = (hqindex + 1) % hqs.length;
|
|
} while (position.x == -1);
|
|
defense[i].x = position.x;
|
|
defense[i].y = position.y;
|
|
this.units.push(util.createUnit(defense[i]));
|
|
}
|
|
}
|
|
|
|
// Prepare bad units arrival
|
|
this.score = 0;
|
|
this.wave = 1;
|
|
this.enemyCount = level.attack;
|
|
this.enemyWaveSize = constant.waveInitSize;
|
|
this.enemyNextWaveCount = constant.waveInitSize;
|
|
this.enemyWaveCount = 0;
|
|
this.enemyArrivalTurn = constant.startArrival;
|
|
|
|
// Let's Go !
|
|
this.pausedGame = false;
|
|
},
|
|
|
|
// Render
|
|
rendered: function() {
|
|
// Init game
|
|
if (!this.initializedGame) {
|
|
// Init context
|
|
this.initGame();
|
|
|
|
// Set zoom
|
|
this.canvas.hasNode().style.MozTransform = "scale("+this.zoom+")";
|
|
this.canvas.hasNode().style.MozTransformOrigin = "0 0";
|
|
this.canvas.hasNode().style.zoom = this.zoom;
|
|
}
|
|
},
|
|
|
|
cacheLoaded: function() {
|
|
},
|
|
|
|
// Draw
|
|
draw: function() {
|
|
// Clear all
|
|
var ctx = this.canvas.hasNode().getContext('2d');
|
|
ctx.clearRect(0, 0, this.canvas.attributes.width, this.canvas.attributes.height);
|
|
|
|
// Draw board
|
|
var grass = document.getElementById("grass");
|
|
var trees = document.getElementById("trees");
|
|
var mountain = document.getElementById("mountain");
|
|
var water = document.getElementById("water");
|
|
for (var i = 0 ; i < constant.boardHeight ; i++ ) {
|
|
for (var j = 0 ; j < constant.boardWidth ; j++ ) {
|
|
ctx.save();
|
|
ctx.translate(j*constant.tileSize, i*constant.tileSize);
|
|
ctx.drawImage(grass, 0, 0);
|
|
var tileType = this.game[i][j];
|
|
if (tileType == constant.tileTrees)
|
|
ctx.drawImage(trees, 0, 0);
|
|
else if (tileType == constant.tileMountain)
|
|
ctx.drawImage(mountain, 0, 0);
|
|
else if (tileType == constant.tileWater)
|
|
ctx.drawImage(water, 0, 0);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
|
|
// Draw tanks
|
|
if (!this.endOfGame) {
|
|
for (var i = 0 ; i < this.units.length ; i++)
|
|
this.units[i].draw(ctx);
|
|
|
|
// Draw target
|
|
var target = document.getElementById("target");
|
|
ctx.save();
|
|
ctx.translate(this.targetpos.x*constant.tileSize, this.targetpos.y*constant.tileSize);
|
|
ctx.drawImage(target, 0, 0);
|
|
ctx.restore();
|
|
}
|
|
|
|
// End of game
|
|
else {
|
|
// Draw end of game screen
|
|
var endscreen = this.win ? document.getElementById("endgame_victory") : document.getElementById("endgame_defeat");
|
|
ctx.save();
|
|
ctx.translate((constant.areaWidth-constant.endGameWidth)/2, (constant.areaHeight-constant.endGameHeight)/2);
|
|
ctx.drawImage(endscreen, 0, 0);
|
|
ctx.restore();
|
|
|
|
// Play end of game sound
|
|
if (!this.waitForClick) {
|
|
sound.play(this.win ? "audio/mission_completed" : "audio/mission_failed", true);
|
|
this.waitForClick = true;
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
// A key was pressed
|
|
keyPressed: function(s, e) {
|
|
var key = e.charCode;
|
|
if (this.endOfGame)
|
|
return;
|
|
|
|
// Digit key
|
|
if (key >= 48 && key <= 57) {
|
|
// Add digit to string
|
|
var value = this.$.lcd.getValue();
|
|
if (value.length == this.$.lcd.getSize())
|
|
value = value.substr(1);
|
|
value += String.fromCharCode(key);
|
|
this.$.lcd.setValue(value);
|
|
}
|
|
|
|
// Dash key
|
|
else if (key == 45) {
|
|
this.$.lcd.setValue("-");
|
|
}
|
|
|
|
// Fire key
|
|
else if (key == 32) {
|
|
// Look for unit with the value
|
|
var units = util.lookForValue(this.$.lcd.getValue().replace(/ /g,''));
|
|
if (units.length != 0) {
|
|
for (var i = 0 ; i < units.length ; i++) {
|
|
util.processFight(null, units[i], constant.userPower);
|
|
this.targetpos.x = units[i].x;
|
|
this.targetpos.y = units[i].y;
|
|
}
|
|
}
|
|
else
|
|
sound.play("audio/missed");
|
|
this.$.lcd.setValue("");
|
|
}
|
|
},
|
|
|
|
// A virtual key is pressed
|
|
virtkeyPressed: function(s) {
|
|
var classes = s.getSrc().replace(".svg", "");
|
|
var value = classes.substr("images/key_".length,classes.indexOf("key_"));
|
|
if (value == "fire")
|
|
this.keyPressed(null, {charCode: 32});
|
|
else
|
|
this.keyPressed(null, {charCode: 48+parseInt(value)});
|
|
},
|
|
|
|
goHome: function() {
|
|
// Click at the end of game
|
|
if (this.waitForClick) {
|
|
this.gameClick();
|
|
return;
|
|
}
|
|
|
|
// Stop game loop
|
|
window.clearInterval(this.loopTimer);
|
|
|
|
// Back to app
|
|
app.init();
|
|
app.playTheme()
|
|
app.renderInto(document.getElementById("board"));
|
|
},
|
|
|
|
// A tap occur on the game
|
|
gameClick: function() {
|
|
// At end of game, quit
|
|
if (this.endOfGame) {
|
|
// Stop game loop
|
|
window.clearInterval(this.loopTimer);
|
|
|
|
// Set mission result
|
|
if (this.win) {
|
|
preferences.levels[this.level].completed = true;
|
|
app.nextMission();
|
|
app.save();
|
|
}
|
|
app.init();
|
|
|
|
// Back to app
|
|
app.renderInto(document.getElementById("board"));
|
|
}
|
|
|
|
// Compute direction
|
|
var screen_width = document.documentElement.clientWidth;
|
|
var screen_height = document.documentElement.clientHeight;
|
|
var center_x = Math.floor(screen_width/2.0);
|
|
var center_y = Math.floor((screen_height+constant.pubHeight)/2.0);
|
|
var diffx = mouse.position.x-center_x, diffy = mouse.position.y-center_y;
|
|
var absdiffx = Math.abs(diffx);
|
|
var absdiffy = Math.abs(diffy);
|
|
if (absdiffx >= 0 && absdiffx < constant.fireZoneWidth && absdiffy >= 0 && absdiffy < constant.fireZoneHeight) {
|
|
var targetunit = util.lookForUnit(this.targetpos);
|
|
if (targetunit != null)
|
|
util.processFight(null, targetunit);
|
|
return;
|
|
} else if (absdiffx > absdiffy) {
|
|
dx = diffx > 0 ? 1 : -1;
|
|
dy = 0;
|
|
} else {
|
|
dx = 0;
|
|
dy = diffy > 0 ? 1 : -1;
|
|
}
|
|
|
|
// Move target
|
|
var newX = this.targetpos.x + dx;
|
|
var newY = this.targetpos.y + dy;
|
|
if (newX < 0 || newX == constant.boardWidth || newY < 0 || newY == constant.boardHeight)
|
|
return;
|
|
this.targetpos.x = newX;
|
|
this.targetpos.y = newY;
|
|
},
|
|
|
|
// Tick for game loop
|
|
gameLoopTick: function() {
|
|
if (this.pausedGame)
|
|
return;
|
|
|
|
// Sanitize: clean dead units and compute victory/defeat conditions
|
|
var alives = [];
|
|
var hqs = [];
|
|
var livingHq = 0;
|
|
var livingEnemy = 0;
|
|
for (var i = 0 ; i < this.units.length ; i++) {
|
|
var unit = this.units[i];
|
|
var isRed = unit.getCurrentImage().indexOf("red") != -1;
|
|
if (unit.power > 0) {
|
|
alives.push(unit);
|
|
} else {
|
|
if (isRed) {
|
|
this.enemyNextWaveCount--;
|
|
this.score += util.unitPowers[util.getUnitType(unit)];
|
|
}
|
|
continue;
|
|
}
|
|
if (util.getUnitType(unit) == 0) {
|
|
hqs[livingHq++] = unit;
|
|
}
|
|
if (isRed)
|
|
livingEnemy++;
|
|
}
|
|
this.units = alives;
|
|
this.endOfGame = (livingHq == 0 || (livingEnemy == 0 && this.enemyCount == 0));
|
|
this.win = (livingHq > 0);
|
|
|
|
// Game play
|
|
if (!this.endOfGame) {
|
|
// Next wave
|
|
if (this.enemyNextWaveCount == 0) {
|
|
this.wave++;
|
|
this.enemyWaveSize += 2;
|
|
this.enemyWaveCount = 0;
|
|
this.enemyNextWaveCount = this.enemyWaveSize;
|
|
this.enemyArrivalTurn = constant.startArrival;
|
|
}
|
|
|
|
// Enemy arrival
|
|
else if (this.enemyWaveCount != this.enemyWaveSize) {
|
|
if (this.enemyArrivalTurn == 0 && this.enemyCount > 0) {
|
|
var badEngine = enyo.bind(this, "badEngine");
|
|
var unit = util.createUnit({
|
|
type: util.randomUnit(this.currentlevel.stats),
|
|
color: "red",
|
|
heading: 0,
|
|
engine: badEngine,
|
|
x: constant.boardWidth-1,
|
|
y: util.random(constant.boardHeight)
|
|
});
|
|
unit.value = this.currentlevel.generator();
|
|
this.units.push(unit);
|
|
this.enemyCount = this.enemyCount-1;
|
|
this.enemyWaveCount++;
|
|
this.enemyArrivalTurn = constant.startArrival;
|
|
} else {
|
|
this.enemyArrivalTurn = this.enemyArrivalTurn - 1;
|
|
}
|
|
}
|
|
|
|
// Launch engine for each unit
|
|
for (var i = 0 ; i < this.units.length ; i++) {
|
|
var engine = this.units[i].engine;
|
|
if (engine != null)
|
|
engine(this.units[i], hqs);
|
|
}
|
|
}
|
|
|
|
// Draw
|
|
this.draw();
|
|
|
|
// HACK: On Android, force redraw of canvas
|
|
if (enyo.platform.android && document.location.protocol.substr(0,4) != "http") {
|
|
document.getElementById('acanvas').style.display='none';
|
|
document.getElementById('acanvas').offsetHeight;
|
|
document.getElementById('acanvas').style.display='block';
|
|
}
|
|
|
|
// Draw score
|
|
this.$.wave.setContent(String("0000"+this.wave).slice(-4))
|
|
this.$.score.setContent(String("0000"+this.score).slice(-4))
|
|
},
|
|
|
|
// Engine for good tank moves
|
|
goodEngine: function(that, hqs) {
|
|
// Look for enemy unit
|
|
var opponent = util.lookForOpponent(that);
|
|
if (opponent != null) {
|
|
// Change heading toward opponent
|
|
that.heading = opponent.heading;
|
|
|
|
// Fight
|
|
util.processFight(that, opponent.unit);
|
|
return;
|
|
}
|
|
},
|
|
|
|
// Engine for bad tank moves
|
|
badEngine: function(that, hqs) {
|
|
// Look for enemy unit around
|
|
var opponent = util.lookForOpponent(that);
|
|
if (opponent != null) {
|
|
// Change heading toward opponent
|
|
that.heading = opponent.heading;
|
|
|
|
// Fight
|
|
util.processFight(that, opponent.unit);
|
|
return;
|
|
}
|
|
|
|
// Change heading to go toward the nearest HQ
|
|
var nearestHQ = util.nearestUnit(that, hqs);
|
|
if (nearestHQ != null) {
|
|
var dx = that.x - nearestHQ.x;
|
|
var dy = that.y - nearestHQ.y;
|
|
if (Math.abs(dx) > Math.abs(dy))
|
|
that.heading = dx > 0 ? 0 : 2;
|
|
else
|
|
that.heading = dy > 0 ? 1 : 3;
|
|
}
|
|
|
|
// Is it a valid position ?
|
|
var next = util.nextPositionOnHeading(that);
|
|
while (!util.isValidPosition(next, that)) {
|
|
// No, try a random heading
|
|
that.heading = util.random(4);
|
|
next = util.nextPositionOnHeading(that);
|
|
}
|
|
next = util.nextPositionOnHeading(that);
|
|
that.x = next.x;
|
|
that.y = next.y;
|
|
}
|
|
});
|