[common] bonuses implemented

This commit is contained in:
2018-02-15 17:11:41 +03:00
parent 032fa0c0ad
commit 1ae84cf5a8
14 changed files with 187 additions and 67 deletions

View File

@@ -59,6 +59,7 @@ typedef TankSpawn = {
var type:TankType;
var rate:Float;
@:optional var bonus:Float;
@:optional var protect:Float;
}
typedef PlayerConfig = {

View File

@@ -25,4 +25,19 @@ class EntityTypeResolver {
case x: null;
}
}
public static function as<T>(entity:Entity, type:Class<T>):Null<T> {
if (Std.is(entity, type)) {
return cast entity;
}
return null;
}
public static function asCall<T, R>(entity:Entity, type:Class<T>, fun:T->R, ?defaultResult:R):R {
var e:T = as(entity, type);
if (e != null) {
return fun(e);
}
return defaultResult;
}
}

View File

@@ -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;
}
}

View File

@@ -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<Bullet> {
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));

View File

@@ -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<Tank> {
for (entity in entities) {
if (Std.is(entity, Tank) && filter(entity)) {
@yield return entity;
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}