[common] add ArmorEagleBonus

This commit is contained in:
2019-08-06 16:19:38 +03:00
parent db80c151bb
commit de64e2813e
28 changed files with 230 additions and 84 deletions

View File

@@ -0,0 +1,43 @@
package ru.m.tankz.bonus;
import ru.m.geom.Point;
import ru.m.tankz.core.Eagle;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.Team;
import ru.m.tankz.Type;
using ru.m.tankz.game.GameUtil;
class ArmorEagleBonus extends BaseBonus {
public static inline var CLASS = "armor.eagle";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var team:Team = game.getTeam(playerId.team);
if (team.eagleId > 0) {
var eagle:Eagle = cast(engine.entities[team.eagleId], Eagle);
var center = eagle.rect.center;
var cx:Int = Math.round(center.x / engine.map.cellWidth);
var cy:Int = Math.round(center.y / engine.map.cellHeight);
var bricks:Array<Int> = [];
for (x in cx - 2...cx + 2) {
for (y in cy - 2...cy + 2) {
var brick = engine.map.getBrick(new Point(x, y));
if (brick != null && brick.config.type != "none") {
bricks.push(brick.id);
}
}
}
for (brickId in bricks) {
game.gameEventSignal.emit(CHANGE(BRICK(brickId, "armor")));
}
game.ticker.emit(function() {
for (brickId in bricks) {
game.gameEventSignal.emit(CHANGE(BRICK(brickId, "brick")));
}
}, Std.int(config.duration * 1000), '$CLASS.${eagle.id}');
}
}
}

View File

@@ -0,0 +1,26 @@
package ru.m.tankz.bonus;
import ru.m.tankz.config.Config.BonusConfig;
class BonusFactory {
private var classes:Map<String, Class<IBonus>>;
public function new() {
classes = [
DestroyTeamBonus.CLASS => DestroyTeamBonus,
FreezeTeamBonus.CLASS => FreezeTeamBonus,
LifeBonus.CLASS => LifeBonus,
ArmorEagleBonus.CLASS => ArmorEagleBonus,
ProtectEagleBonus.CLASS => ProtectEagleBonus,
ProtectTankBonus.CLASS => ProtectTankBonus,
UpgradeTankBonus.CLASS => UpgradeTankBonus,
SuicideTankBonus.CLASS => SuicideTankBonus,
];
}
public function build(config:BonusConfig):IBonus {
var bonusClass = classes.exists(config.factory) ? classes[config.factory] : classes[SuicideTankBonus.CLASS];
return Type.createInstance(bonusClass, [config]);
}
}

View File

@@ -10,6 +10,8 @@ using ru.m.tankz.game.GameUtil;
class DestroyTeamBonus extends BaseBonus {
public static inline var CLASS = "destroy.team";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var tank:Tank = engine.getEntity(game.getPlayer(playerId).tankId);
if (tank != null) {

View File

@@ -8,6 +8,8 @@ using ru.m.tankz.game.GameUtil;
class FreezeTeamBonus extends BaseBonus {
public static inline var CLASS = "freeze.team";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
for (team in game.teams) {
if (team.id != playerId.team) {

View File

@@ -8,6 +8,8 @@ using ru.m.tankz.game.GameUtil;
class LifeBonus extends BaseBonus {
public static inline var CLASS = "life";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
game.changeLife(playerId, 1);
}

View File

@@ -10,6 +10,8 @@ using ru.m.tankz.game.GameUtil;
class ProtectEagleBonus extends BaseBonus {
public static inline var CLASS = "protect.eagle";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var team:Team = game.getTeam(playerId.team);
if (team.eagleId > 0) {

View File

@@ -9,6 +9,8 @@ using ru.m.tankz.game.GameUtil;
class ProtectTankBonus extends BaseBonus {
public static inline var CLASS = "protect.tank";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var tank:Tank = engine.getEntity(game.getPlayer(playerId).tankId);
if (tank != null) {

View File

@@ -0,0 +1,21 @@
package ru.m.tankz.bonus;
import ru.m.tankz.core.Tank;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.Type;
using ru.m.tankz.game.GameUtil;
class SuicideTankBonus extends BaseBonus {
public static inline var CLASS = "suicide.tank";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var tank:Tank = engine.getEntity(game.getPlayer(playerId).tankId);
if (tank != null) {
game.gameEventSignal.emit(DESTROY(TANK(tank.id, {tankId: tank.id})));
}
}
}

View File

@@ -9,6 +9,8 @@ using ru.m.tankz.game.GameUtil;
class UpgradeTankBonus extends BaseBonus {
public static inline var CLASS = "upgrade.tank";
override public function apply(playerId:PlayerId, game:IGame, engine:IEngine):Void {
var tank:Tank = engine.getEntity(game.getPlayer(playerId).tankId);
if (tank != null) {

View File

@@ -63,6 +63,7 @@ typedef TankConfig = {
typedef BonusConfig = {
var type:BonusType;
var factory:String;
@:optional var duration:Null<Int>;
@:optional var value:Null<Int>;
@:optinal var score:Null<Int>;

View File

@@ -7,5 +7,6 @@ interface ITicker {
public function start():Void;
public function stop():Void;
public function tick():Int;
public function emit(f:Void->Void, delay:Int):Void;
public function emit(f:Void->Void, delay:Int, ?key:String):Void;
public function cancel(key:String):Void;
}

View File

@@ -13,6 +13,7 @@ class Ticker implements ITicker {
private var passed:Int;
private var last_tick:Int;
private var actions:Array<Action>;
private var actionsByKey:Map<String, Action>;
private var actionId = 0;
private static var TIME = Timer.stamp();
@@ -26,6 +27,7 @@ class Ticker implements ITicker {
last_tick = 0;
running = false;
actions = [];
actionsByKey = new Map();
}
private function get_time():Int {
@@ -73,10 +75,21 @@ class Ticker implements ITicker {
}
}
public function emit(fun:Void->Void, delay:Int):Void {
public function emit(fun:Void->Void, delay:Int, ?key:String):Void {
var action:Action = {action:fun, time:time+delay, id:++actionId};
//L.d("Ticker", 'emit: ${action.id} ${action.time}');
if (key != null) {
cancel(key);
actionsByKey[key] = action;
}
actions.push(action);
actions.sort(function(a, b) return a.time - b.time);
}
public function cancel(key:String):Void {
if (actionsByKey.exists(key)) {
actions.remove(actionsByKey[key]);
actionsByKey.remove(key);
}
}
}

View File

@@ -2,13 +2,7 @@ package ru.m.tankz.game;
import ru.m.geom.Line;
import ru.m.geom.Point;
import ru.m.tankz.bonus.DestroyTeamBonus;
import ru.m.tankz.bonus.FreezeTeamBonus;
import ru.m.tankz.bonus.IBonus;
import ru.m.tankz.bonus.LifeBonus;
import ru.m.tankz.bonus.ProtectEagleBonus;
import ru.m.tankz.bonus.ProtectTankBonus;
import ru.m.tankz.bonus.UpgradeTankBonus;
import ru.m.tankz.bonus.BonusFactory;
import ru.m.tankz.control.Control;
import ru.m.tankz.core.Bonus;
import ru.m.tankz.core.Bullet;
@@ -18,7 +12,7 @@ import ru.m.tankz.core.Tank;
import ru.m.tankz.engine.Engine;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState.FragTarget;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.Spawner;
import ru.m.tankz.Type;
import ru.m.Timer;
@@ -28,34 +22,19 @@ using ru.m.tankz.game.GameUtil;
class GameRunner extends Game implements EngineListener {
private var timer:Timer;
private var builder:EntityBuilder;
private var bonuses:Map<String, IBonus>;
private var bonuses:BonusFactory;
public function new(start:Start) {
super(start.state.type);
this.level = start.level;
this.state = start.state;
builder = new EntityBuilder(config);
bonuses = new Map();
for (bonus in buildBonuses()) {
bonuses[bonus.type] = bonus;
}
bonuses = new BonusFactory();
engine = new Engine(config, level.size);
ticker = engine.ticker;
engine.connect(this);
}
private function buildBonuses():Array<IBonus> {
return [
new ProtectEagleBonus(config.getBonus("shovel")),
new ProtectTankBonus(config.getBonus("helmet")),
new LifeBonus(config.getBonus("life")),
new UpgradeTankBonus(config.getBonus("star")),
new UpgradeTankBonus(config.getBonus("gun")),
new DestroyTeamBonus(config.getBonus("grenade")),
new FreezeTeamBonus(config.getBonus("clock")),
];
}
override function changePause(value:Bool):Void {
if (engine != null) {
if (value) {
@@ -254,11 +233,8 @@ class GameRunner extends Game implements EngineListener {
}
private function applyBonus(tank:Tank, bonus:Bonus):Void {
if (bonuses.exists(bonus.config.type)) {
bonuses[bonus.config.type].apply(tank.playerId, this, engine);
} else {
gameEventSignal.emit(DESTROY(TANK(tank.id, {tankId: tank.id}))); // :-D
}
var bonus = bonuses.build(bonus.config);
bonus.apply(tank.playerId, this, engine);
}
override public function onGameEvent(event:GameEvent):Void {
@@ -306,6 +282,8 @@ class GameRunner extends Game implements EngineListener {
player.state.tank = info;
case SPAWN(BULLET(_, _, playerId, _)):
getPlayer(playerId).bullets++;
case CHANGE(BRICK(id, type)):
engine.map.bricksById[id].config = config.getBrick(type);
case DESTROY(EAGLE(id, shot)):
var eagle:Eagle = engine.getEntity(id);
eagle.death = true;
@@ -355,6 +333,12 @@ class GameRunner extends Game implements EngineListener {
var bonus:Bonus = engine.getEntity(id);
var tank:Tank = engine.getEntity(shot.tankId);
applyBonus(tank, bonus);
var shooter = getPlayer(tank.playerId);
shooter.state.frags.push({
playerId: shooter.id,
target: BONUS(bonus.config.type),
score: shot.score,
});
if (shot.score != null) {
changeScore(tank.playerId, shot.score);
}
@@ -373,10 +357,10 @@ class GameRunner extends Game implements EngineListener {
var shot = buildShot(bullet);
if (cell.armor == bullet.config.piercing) {
engine.destroyCell(cell.cellX, cell.cellY);
var brick = engine.map.getBrick(cell.position);
var brick = engine.map.getCellBrick(cell.position);
gameEventSignal.emit(DESTROY(CELL(brick.id, cell.cellX - brick.cellX * 2, cell.cellY - brick.cellY * 2, shot)));
} else if (cell.armor < bullet.config.piercing) {
var brick = engine.map.getBrick(cell.position);
var brick = engine.map.getCellBrick(cell.position);
for (cell in brick.cells) {
engine.destroyCell(cell.cellX, cell.cellY);
}

View File

@@ -11,6 +11,7 @@ import ru.m.tankz.Type;
enum FragTarget {
TANK(tank:TankInfo);
EAGLE(color:Color);
BONUS(type:BonusType);
}
typedef Frag = {

View File

@@ -33,7 +33,7 @@ class GameUtil {
game.ticker.emit(function() {
tank.protect = false;
game.gameEventSignal.emit(CHANGE(TANK_PROTECT(tank.id, tank.protect)));
}, Std.int(duration * 1000));
}, Std.int(duration * 1000), 'protect.tank.${tank.id}');
}
public static function protectEagle(game:IGame, eagle:Eagle, duration:Float):Void {
@@ -42,7 +42,7 @@ class GameUtil {
game.ticker.emit(function() {
eagle.protect = false;
game.gameEventSignal.emit(CHANGE(EAGLE_PROTECT(eagle.id, eagle.protect)));
}, Std.int(duration * 1000));
}, Std.int(duration * 1000), 'protect.eagle.${eagle.id}');
}
public static function freezeTank(game:IGame, tank:Tank, duration:Float):Void {
@@ -53,7 +53,7 @@ class GameUtil {
game.ticker.emit(function() {
tank.freezing = false;
game.gameEventSignal.emit(CHANGE(TANK_FREEZE(tank.id, tank.freezing)));
}, Std.int(duration * 1000));
}, Std.int(duration * 1000), 'freeze.tank.${tank.id}');
}
public static function freezeTeam(game:IGame, engine:IEngine, teamId:TeamId, duration:Float):Void {
@@ -70,7 +70,7 @@ class GameUtil {
tank.freezing = false;
game.gameEventSignal.emit(CHANGE(TANK_FREEZE(tank.id, tank.freezing)));
}
}, Std.int(duration * 1000));
}, Std.int(duration * 1000), 'freeze.team.${teamId}');
}
public static function changeLife(game:IGame, playerId:PlayerId, life:Int):Void {

View File

@@ -13,7 +13,7 @@ class Brick {
public var cellY(default, null):Int;
public var mapConfig(default, null):MapConfig;
public var config(default, default):BrickConfig;
public var config(default, set):BrickConfig;
public var rect(default, null):Rectangle;
public var cells(default, null):HashMap<Point, GridCell>;
@@ -34,7 +34,17 @@ class Brick {
);
}
public function get_broken():Int {
private function set_config(value:BrickConfig):BrickConfig {
config = value;
for (cell in cells) {
cell.layer = config.layer;
cell.armor = config.armor;
cell.destroyed = false;
}
return config;
}
private function get_broken():Int {
var i:Int = 0;
for (c in cells.iterator()) {
if (c.destroyed) {
@@ -44,7 +54,7 @@ class Brick {
return i;
}
public function get_destroyed():Bool {
private function get_destroyed():Bool {
var i = 0;
var result:Bool = false;
for (c in cells.iterator()) {
@@ -57,7 +67,7 @@ class Brick {
return result;
}
public function set_destroyed(value:Bool):Bool {
private function set_destroyed(value:Bool):Bool {
if (value) {
for (c in cells.iterator()) {
c.destroyed = true;
@@ -66,7 +76,7 @@ class Brick {
return value;
}
public function get_id():Int {
private function get_id():Int {
return -((cellX * 1000) + cellY);
}

View File

@@ -18,6 +18,7 @@ class LevelMap {
public var height(get, null):Float;
public var bricks(default, null):Array<Brick>;
public var bricksById(default, null):Map<Int, Brick>;
public var grid(default, null):Grid;
@@ -31,6 +32,7 @@ class LevelMap {
gridHeight = size != null ? size.height : config.grid.height;
bricksMap = new HashMap();
bricks = [];
bricksById = new Map();
grid = new Grid(
Std.int(cellWidth / 2),
Std.int(cellHeight / 2),
@@ -57,11 +59,16 @@ class LevelMap {
for (cell in brick.cells.iterator()) {
bricksMap.set(cell.position, brick);
}
bricksById.set(brick.id, brick);
return brick;
}));
}
public function getBrick(position:Point):Brick {
return bricks[Std.int(position.x + position.y * gridWidth)];
}
public function getCellBrick(position:Point):Brick {
return bricksMap.get(position);
}

View File

@@ -147,13 +147,13 @@ tanks:
skin: bd
bonuses:
- {score: 500, type: clock, duration: 10}
- {score: 500, type: grenade}
- {score: 500, type: helmet, duration: 20}
- {score: 500, type: life}
- {score: 500, type: shovel, duration: 10}
- {score: 500, type: star, value: 1}
- {score: 500, type: gun, value: 5}
- {score: 500, factory: freeze.team, type: clock, duration: 10}
- {score: 500, factory: destroy.team, type: grenade}
- {score: 500, factory: protect.tank, type: helmet, duration: 15}
- {score: 500, factory: life, type: life}
- {score: 500, factory: armor.eagle, type: shovel, duration: 10}
- {score: 500, factory: upgrade.tank, type: star, value: 1}
- {score: 500, factory: upgrade.tank, type: gun, value: 5}
presets:
- id: 0

View File

@@ -107,9 +107,8 @@ tanks:
skin: bb
bonuses:
- {type: clock, duration: 10}
- {type: grenade}
- {type: helmet, duration: 20}
- {type: life}
- {type: shovel, duration: 10}
- {type: star}
- {score: 100, factory: freeze.team, type: clock, duration: 10}
- {score: 100, factory: destroy.team, type: grenade}
- {score: 100, factory: protect.tank, type: helmet, duration: 15}
- {score: 100, factory: life, type: life}
- {score: 100, factory: protect.eagle, type: shovel, duration: 10}