diff --git a/WORK.md b/WORK.md
index baa9473..fca9f3e 100644
--- a/WORK.md
+++ b/WORK.md
@@ -10,7 +10,7 @@
* ui
* auth frame 0%
- * select game frame 30% (classic 1/2 player, dota singe/coop/vs)
+ * select game frame 100% (classic 1/2 player, dota singe/coop/vs)
* select level frame 10%
* game frame 50%
@@ -21,21 +21,29 @@
* bullets 100%
* boxes 100%
* map changes 100%
- * bonuses 0%
+ * bonuses 100%
* eagle 100%
* game
* classic
* state 50%
* bot 50%
- * player: 50%
+ * human 100%
* dota
* state 50%
* bot 10%
- * player 0%
+ * human 100%
+
+* bonus
+ * star 50%
+ * grenade 0%
+ * helm 0%
+ * clock 0%
+ * shovel 0%
* state
* score 0%
+ * human tank 0%
* save/load 0%
* export/import 0%
@@ -47,16 +55,19 @@
* animations
* tank spawn 0%
* tank move 100%
- * map water 0%
+ * map water 100%
* bullet boom 90%
* tank boom 90%
- * bonuses 0%
+ * bonuses 100%
* html5 50%
* proto
...
* editor
- * open 0%
- * edit 0%
- * save 0%
\ No newline at end of file
+ * level
+ * open 100%
+ * edit 50%
+ * save 100%
+ * tank
+ * color 10%
\ No newline at end of file
diff --git a/package.json b/package.json
index 8ed5999..7a5dc50 100755
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"protohx": "0.4.6",
"yaml": "1.3.0",
"haxework": "git@bitbucket.org:shmyga/haxework.git",
- "orm": "2.1.0"
+ "orm": "2.1.0",
+ "yield": "1.1.2"
}
}
diff --git a/project.xml b/project.xml
index fcc9e10..a684dfc 100755
--- a/project.xml
+++ b/project.xml
@@ -12,6 +12,7 @@
+
diff --git a/src/client/haxe/ru/m/tankz/render/RenderItem.hx b/src/client/haxe/ru/m/tankz/render/RenderItem.hx
index 460e931..6cb305a 100644
--- a/src/client/haxe/ru/m/tankz/render/RenderItem.hx
+++ b/src/client/haxe/ru/m/tankz/render/RenderItem.hx
@@ -182,14 +182,23 @@ class TankItem extends RenderItem {
private var type:String;
private var hits:Int;
+ private var protected:Bool;
+ private var frozen:Bool;
private var tankView:Animate;
+ private var protectView:Animate;
public function new(value:Tank) {
super(value);
view = new Sprite();
tankView = new Animate();
view.addChild(tankView);
+ protectView = new Animate(
+ [for (i in 0...5) Assets.getBitmapData('resources/images/tank/protect/protect-0.png')].concat(
+ [for (i in 0...5) Assets.getBitmapData('resources/images/tank/protect/protect-1.png')])
+ );
+ protectView.visible = false;
+ view.addChild(protectView);
redraw();
}
@@ -200,6 +209,15 @@ class TankItem extends RenderItem {
frames[0], frames[0], frames[0],
frames[1], frames[1], frames[1],
];
+ if (value.protect.active) {
+ protectView.x = (tankView.frames[0].width - protectView.frames[0].width) / 2;
+ protectView.y = (tankView.frames[0].height - protectView.frames[0].height) / 2;
+ protectView.playing = true;
+ protectView.visible = true;
+ } else {
+ protectView.playing = false;
+ protectView.visible = false;
+ }
}
private function getFrames():Array {
@@ -212,12 +230,16 @@ class TankItem extends RenderItem {
super.update();
var t = value.config.type;
var h = value.hits;
- if (t != this.type || h != this.hits) {
+ var p = value.protect.active;
+ var f = value.freezing.active;
+ if (t != type || h != hits || p != protected || f != frozen) {
this.type = t;
this.hits = h;
+ this.protected = p;
+ this.frozen = f;
redraw();
}
- tankView.playing = (value.mx !=0 || value.my != 0);
+ tankView.playing = !value.freezing.active && (value.mx !=0 || value.my != 0);
}
override public function dispose():Void {
diff --git a/src/client/resources/classic/config.yaml b/src/client/resources/classic/config.yaml
index bbc6ca8..2912337 100644
--- a/src/client/resources/classic/config.yaml
+++ b/src/client/resources/classic/config.yaml
@@ -22,7 +22,7 @@ player:
control: human
life: 3
tanks:
- - {type: human0, rate: 1}
+ - {type: human0, rate: 1, protect: 5}
bot: &bot
control: bot
life: -1
diff --git a/src/client/resources/dota/config.yaml b/src/client/resources/dota/config.yaml
index 13b41a4..9b7c1cc 100644
--- a/src/client/resources/dota/config.yaml
+++ b/src/client/resources/dota/config.yaml
@@ -31,15 +31,25 @@ player: &player
life: -1
control: bot
tanks:
- - {type: slow, rate: 0.5}
- - {type: fast, rate: 0.5}
+ - {type: slow, rate: 0.5, protect: 3, bonus: 0}
+ - {type: fast, rate: 0.5, protect: 3, bonus: 0}
+
+human1: &human1
+ <<: *player
+ control: human
+ color: 0xf055a0
+
+human2: &human2
+ <<: *player
+ control: human
+ color: 0xa055f0
presets:
- id: player1
teams:
- <<: *radiant
players:
- - {<<: *player, index: 0, control: human, color: 0xf055a0}
+ - {<<: *human1, index: 0}
- {<<: *player, index: 1}
- {<<: *player, index: 2}
- {<<: *player, index: 3}
@@ -55,8 +65,8 @@ presets:
teams:
- <<: *radiant
players:
- - {<<: *player, index: 0, control: human, color: 0xf055a0}
- - {<<: *player, index: 1, control: human, color: 0xf055a0}
+ - {<<: *human1, index: 0}
+ - {<<: *human1, index: 1}
- {<<: *player, index: 2}
- {<<: *player, index: 3}
- {<<: *player, index: 4}
@@ -71,14 +81,14 @@ presets:
teams:
- <<: *radiant
players:
- - {<<: *player, index: 0, control: human, color: 0xf055a0}
+ - {<<: *human1, index: 0}
- {<<: *player, index: 1}
- {<<: *player, index: 2}
- {<<: *player, index: 3}
- {<<: *player, index: 4}
- <<: *dire
players:
- - {<<: *player, index: 0, control: human, color: 0xa055f0}
+ - {<<: *human2, index: 0}
- {<<: *player, index: 1}
- {<<: *player, index: 2}
- {<<: *player, index: 3}
diff --git a/src/common/haxe/ru/m/tankz/config/Config.hx b/src/common/haxe/ru/m/tankz/config/Config.hx
index d247251..bf4e3b0 100644
--- a/src/common/haxe/ru/m/tankz/config/Config.hx
+++ b/src/common/haxe/ru/m/tankz/config/Config.hx
@@ -59,6 +59,7 @@ typedef TankSpawn = {
var type:TankType;
var rate:Float;
@:optional var bonus:Float;
+ @:optional var protect:Float;
}
typedef PlayerConfig = {
diff --git a/src/common/haxe/ru/m/tankz/core/EntityType.hx b/src/common/haxe/ru/m/tankz/core/EntityType.hx
index ad301a0..b76f752 100644
--- a/src/common/haxe/ru/m/tankz/core/EntityType.hx
+++ b/src/common/haxe/ru/m/tankz/core/EntityType.hx
@@ -25,4 +25,19 @@ class EntityTypeResolver {
case x: null;
}
}
+
+ public static function as(entity:Entity, type:Class):Null {
+ if (Std.is(entity, type)) {
+ return cast entity;
+ }
+ return null;
+ }
+
+ public static function asCall(entity:Entity, type:Class, fun:T->R, ?defaultResult:R):R {
+ var e:T = as(entity, type);
+ if (e != null) {
+ return fun(e);
+ }
+ return defaultResult;
+ }
}
\ No newline at end of file
diff --git a/src/common/haxe/ru/m/tankz/core/Modificator.hx b/src/common/haxe/ru/m/tankz/core/Modificator.hx
new file mode 100644
index 0000000..01f05f5
--- /dev/null
+++ b/src/common/haxe/ru/m/tankz/core/Modificator.hx
@@ -0,0 +1,27 @@
+package ru.m.tankz.core;
+
+import haxe.Timer;
+
+class Modificator {
+
+ public var active(default, default):Bool;
+ private var timer:Timer;
+
+ public function new() {
+ active = false;
+ }
+
+ public function on(seconds:Float):Void {
+ off();
+ active = true;
+ timer = Timer.delay(off, Std.int(seconds * 1000));
+ }
+
+ public function off():Void {
+ if (timer != null) {
+ timer.stop();
+ timer = null;
+ }
+ active = false;
+ }
+}
diff --git a/src/common/haxe/ru/m/tankz/core/Tank.hx b/src/common/haxe/ru/m/tankz/core/Tank.hx
index 7f0fd60..1a0c6a3 100755
--- a/src/common/haxe/ru/m/tankz/core/Tank.hx
+++ b/src/common/haxe/ru/m/tankz/core/Tank.hx
@@ -15,11 +15,15 @@ class Tank extends MobileEntity {
public var color(default, default):Color;
public var hits(default, default):Int;
public var bonus(default, default):Bool;
+ public var protect(default, null):Modificator;
+ public var freezing(default, null):Modificator;
private var bulletsCounter:Int = 0;
public function new(playerId:PlayerId, config:TankConfig) {
super(new Rectangle(0, 0, config.width, config.height), config.speed, Direction.RIGHT);
+ this.protect = new Modificator();
+ this.freezing = new Modificator();
this.playerId = playerId;
this.config = config;
this.hits = config.hits;
@@ -35,7 +39,14 @@ class Tank extends MobileEntity {
return value;
}
+ override public function move(direction:Direction):Void {
+ if (!freezing.active) {
+ super.move(direction);
+ }
+ }
+
public function shot():Null {
+ if (freezing.active) return null;
if (bulletsCounter >= config.bullets) return null;
var bullet = new Bullet(this);
bullet.rect.center = rect.center.add(new Point(rect.width / 4 * rect.direction.x, rect.height / 4 * rect.direction.y));
diff --git a/src/common/haxe/ru/m/tankz/engine/Engine.hx b/src/common/haxe/ru/m/tankz/engine/Engine.hx
index 1c6355f..daa1ad7 100755
--- a/src/common/haxe/ru/m/tankz/engine/Engine.hx
+++ b/src/common/haxe/ru/m/tankz/engine/Engine.hx
@@ -28,19 +28,6 @@ class CollisionProcessor implements EngineListener {
public function onSpawn(entity:EntityType):Void {}
- private function checkTankBullet(tank:Tank, bullet:Bullet):Bool {
- if (bullet.tankId == tank.id) return false;
- return engine.config.game.friendlyFire || tank.playerId.team != bullet.playerId.team;
- }
-
- private function hitTank(tank:Tank):Void {
- if (tank.hits > 0) {
- tank.hits--;
- } else {
- engine.destroy(tank);
- }
- }
-
public function onCollision(entity:EntityType, with:EntityType):Void {
switch [entity, with] {
case [EntityType.TANK(tank), EntityType.TANK(other_tank)]:
@@ -51,8 +38,16 @@ class CollisionProcessor implements EngineListener {
engine.destroy(bonus);
case [EntityType.TANK(tank), EntityType.BULLET(bullet)] |
[EntityType.BULLET(bullet), EntityType.TANK(tank)]:
- if (checkTankBullet(tank, bullet)) {
- hitTank(tank);
+ if (bullet.tankId == tank.id || (!engine.config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) {
+ // Nothing
+ } else {
+ if (!tank.protect.active) {
+ if (tank.hits > 0) {
+ tank.hits--;
+ } else {
+ engine.destroy(tank);
+ }
+ }
engine.destroy(bullet);
}
case [EntityType.BULLET(bullet), EntityType.BULLET(other_bullet)]:
@@ -70,6 +65,7 @@ class CollisionProcessor implements EngineListener {
public function onDestroy(entity:EntityType):Void { }
}
+@:yield
class Engine implements ControlHandler {
public var config(default, default):Config;
@@ -132,8 +128,6 @@ class Engine implements ControlHandler {
}
}
-
-
public function update():Void {
var newTime:Float = Date.now().getTime();
var d:Float = newTime - time;
@@ -153,6 +147,15 @@ class Engine implements ControlHandler {
}*/
if (entity.mx != 0 || entity.my != 0) {
+ var asTank:Tank = EntityTypeResolver.as(entity, Tank);
+ var asBullet:Bullet = EntityTypeResolver.as(entity, Bullet);
+
+ if (asTank != null) {
+ if (asTank.freezing.active) {
+ continue;
+ }
+ }
+
var side:Line = entity.rect.getSide(entity.rect.direction.reverse());
var step:Point = new Point(entity.rect.direction.x * map.cellWidth / 4, entity.rect.direction.y * map.cellHeight / 4);
var end:Point = side.center.add(new Point(entity.mx * (d / 30), entity.my * (d / 30)));
@@ -186,15 +189,14 @@ class Engine implements ControlHandler {
}
}
- if (Std.is(entity, Bullet)) {
- var bullet:Bullet = cast ent;
+ if (asBullet != null) {
if (collision) {
cells = map.grid.getCells(side.setLength(map.grid.cellWidth * 3));
for (cell in cells) {
if (cell.armor > 0) {
- if (cell.armor == bullet.config.piercing) {
+ if (cell.armor == asBullet.config.piercing) {
cell.destroyed = true;
- } else if (cell.armor < bullet.config.piercing) {
+ } else if (cell.armor < asBullet.config.piercing) {
var brick = map.getBrick(cell);
brick.destroyed = true;
}
@@ -218,4 +220,12 @@ class Engine implements ControlHandler {
listeners = [];
entities = new Map();
}
+
+ public function iterTanks(filter:Tank->Bool):Iterator {
+ for (entity in entities) {
+ if (Std.is(entity, Tank) && filter(entity)) {
+ @yield return entity;
+ }
+ }
+ }
}
diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx
index 82e4694..04e99de 100644
--- a/src/common/haxe/ru/m/tankz/game/Game.hx
+++ b/src/common/haxe/ru/m/tankz/game/Game.hx
@@ -62,6 +62,9 @@ class Game implements EngineListener {
tank.color = player.config.color.zero ? teams[playerId.team].config.color : player.config.color;
tank.bonus = Math.random() < spawn.bonus;
applyPoint(tank, point);
+ if (spawn.protect > 0) {
+ tank.protect.on(spawn.protect);
+ }
return tank;
}
@@ -126,7 +129,7 @@ class Game implements EngineListener {
if (getTeam(task.playerId.team).trySpawn(task.playerId, true)) {
var tank = buildTank(task.playerId, task.point);
player.tankId = tank.id;
- Timer.delay(function() engine.spawn(tank), 1500);
+ engine.spawn(tank);
} else if (!team.isAlive) {
lose(team.id);
}
@@ -155,10 +158,13 @@ class Game implements EngineListener {
}
public function onCollision(entity:EntityType, with:EntityType):Void {
- switch [entity, with] {
- case [EntityType.TANK(tank), _]:
+ switch entity {
+ case EntityType.TANK(tank):
var control = getPlayer(tank.playerId).control;
if (control != null) control.onCollision(with);
+ case _:
+ }
+ switch [entity, with] {
case [EntityType.TANK(tank), EntityType.BONUS(bonus)]:
applyBonus(tank, bonus);
case [EntityType.BULLET(_), EntityType.EAGLE(eagle)]:
@@ -208,17 +214,20 @@ class Game implements EngineListener {
engine.dispose();
}
-
- private function spawnBonus():Void {
- var bonusConfig = config.bonuses[Math.floor(Math.random() * config.bonuses.length)];
- L.d(TAG, 'Spawn Bonus(${bonusConfig}');
+ private function spawnBonus(?type:BonusType):Void {
+ var bonusConfig:BonusConfig = type != null ? config.getBonus(type) : config.bonuses[Math.floor(Math.random() * config.bonuses.length)];
var bonus = new Bonus(bonusConfig.type);
bonus.rect.x = Math.random() * engine.map.width;
bonus.rect.y = Math.random() * engine.map.height;
engine.spawn(bonus);
}
+ inline private function alienTank(team:TeamId):Tank->Bool {
+ return function(tank:Tank):Bool return team != tank.playerId.team;
+ }
+
private function applyBonus(tank:Tank, bonus:Bonus):Void {
+ L.e('XXX', 'applyBonus: ${bonus.bonusType}');
switch (bonus.bonusType) {
case 'life':
getPlayer(tank.playerId).life++;
@@ -229,19 +238,18 @@ class Game implements EngineListener {
tank.hits++;
}
case 'grenade':
- for (entity in engine.entities.iterator()) {
- switch (EntityTypeResolver.of(entity)) {
- case EntityType.TANK(t):
- if (t.playerId.team != tank.playerId.team) {
- engine.destroy(t);
- }
- case x:
- }
+ for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
+ engine.destroy(t);
}
case 'helmet':
+ tank.protect.on(20);
case 'clock':
+ for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
+ t.freezing.on(10);
+ }
case 'shovel':
- case x:
+ // ToDo: protect eagle/area
+ case _:
engine.destroy(tank); // :-D
}
}
diff --git a/src/common/haxe/ru/m/tankz/game/Player.hx b/src/common/haxe/ru/m/tankz/game/Player.hx
index a1d8a8c..3270a21 100644
--- a/src/common/haxe/ru/m/tankz/game/Player.hx
+++ b/src/common/haxe/ru/m/tankz/game/Player.hx
@@ -12,6 +12,7 @@ class Player {
public var tankId(default, set):Int;
public var control(default, set):Control;
public var life(default, default):Int;
+ public var isAlive(get, null):Bool;
public function new(teamId:TeamId, config:PlayerConfig) {
this.config = config;
@@ -20,7 +21,7 @@ class Player {
this.life = config.life;
}
- public function set_tankId(value:Int):Int {
+ private function set_tankId(value:Int):Int {
tankId = value;
if (control != null) {
control.tankId = tankId;
@@ -28,7 +29,7 @@ class Player {
return tankId;
}
- public function set_control(value:Control):Control {
+ private function set_control(value:Control):Control {
if (control != null) control.dispose();
control = value;
if (control != null) {
@@ -36,4 +37,8 @@ class Player {
}
return control;
}
+
+ private function get_isAlive():Bool {
+ return tankId > 0 || life > 0;
+ }
}
diff --git a/src/common/haxe/ru/m/tankz/game/Team.hx b/src/common/haxe/ru/m/tankz/game/Team.hx
index 70be402..b9e00dc 100644
--- a/src/common/haxe/ru/m/tankz/game/Team.hx
+++ b/src/common/haxe/ru/m/tankz/game/Team.hx
@@ -43,16 +43,14 @@ class Team {
// ToDo: eagle state?
private function get_isAlive():Bool {
- var life:Int = Lambda.fold(players, function(p:Player, t:Int) return t + p.life, life);
if (life > 0) {
return true;
- } else {
- for (player in players) {
- if (player.tankId > 0) {
- return true;
- }
- }
- if (spawner.active) {
+ }
+ if (spawner.active) {
+ return true;
+ }
+ for (player in players) {
+ if (player.isAlive) {
return true;
}
}