From abf944418eeca098090ff64f1ebbac09b1636b7a Mon Sep 17 00:00:00 2001 From: shmyga Date: Thu, 30 May 2019 15:24:26 +0300 Subject: [PATCH] [common] add PlayerControl presets --- .../haxe/ru/m/tankz/bundle/ConfigBundle.hx | 2 +- .../haxe/ru/m/tankz/control/NetworkControl.hx | 4 +- .../haxe/ru/m/tankz/game/NetworkGame.hx | 8 ++ src/client/haxe/ru/m/tankz/render/Render.hx | 2 +- src/client/haxe/ru/m/tankz/view/LevelFrame.hx | 6 +- .../ru/m/tankz/view/network/GameRoomFrame.hx | 4 +- .../ru/m/tankz/view/network/PlayerItemView.hx | 10 +-- .../haxe/ru/m/tankz/view/popup/LevelPopup.hx | 31 ++++++- .../ru/m/tankz/view/popup/LevelPopup.yaml | 9 ++ .../haxe/ru/m/tankz/bundle/IConfigBundle.hx | 11 --- src/common/haxe/ru/m/tankz/config/Config.hx | 30 +++++++ .../haxe/ru/m/tankz/game/EntityBuilder.hx | 5 +- src/common/haxe/ru/m/tankz/game/EventUtil.hx | 3 +- src/common/haxe/ru/m/tankz/game/Game.hx | 22 +++-- src/common/haxe/ru/m/tankz/game/GameEvent.hx | 2 + src/common/haxe/ru/m/tankz/game/GameRunner.hx | 90 ++++++++++--------- src/common/haxe/ru/m/tankz/game/GameState.hx | 5 +- src/common/proto/core.proto | 9 +- src/common/resources/classic/config.yaml | 19 +++- src/common/resources/death/config.yaml | 16 +++- src/common/resources/dota/config.yaml | 28 +++++- .../ru/m/tankz/editor/level/MapEditView.hx | 2 +- .../tankz/server/bundle/ServerConfigBundle.hx | 2 +- .../server/control/ServerControlFactory.hx | 7 ++ .../ru/m/tankz/server/game/GameManager.hx | 8 +- .../haxe/ru/m/tankz/server/game/ServerGame.hx | 21 +++++ 26 files changed, 264 insertions(+), 92 deletions(-) diff --git a/src/client/haxe/ru/m/tankz/bundle/ConfigBundle.hx b/src/client/haxe/ru/m/tankz/bundle/ConfigBundle.hx index 865510b..5689c89 100644 --- a/src/client/haxe/ru/m/tankz/bundle/ConfigBundle.hx +++ b/src/client/haxe/ru/m/tankz/bundle/ConfigBundle.hx @@ -16,7 +16,7 @@ class ConfigBundle implements IConfigBundle { public function get(type:GameType):Config { if (!_cache.exists(type)) { var source:ConfigSource = Yaml.parse(Assets.getText('resources/${type}/config.yaml'), Parser.options().useObjects()); - _cache.set(type, new Config(type, source.game, source.map, source.bricks, source.presets, source.points, source.tanks, source.bonuses)); + _cache.set(type, Config.fromSource(type, source)); } return _cache.get(type); } diff --git a/src/client/haxe/ru/m/tankz/control/NetworkControl.hx b/src/client/haxe/ru/m/tankz/control/NetworkControl.hx index 6a9200c..82e0fe6 100644 --- a/src/client/haxe/ru/m/tankz/control/NetworkControl.hx +++ b/src/client/haxe/ru/m/tankz/control/NetworkControl.hx @@ -8,6 +8,8 @@ class NetworkControl extends HumanControl { @:provide private var network:NetworkManager; override public function action(action:TankAction):Void { - network.action(tankId, action); + if (tankId > -1) { + network.action(tankId, action); + } } } diff --git a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx index 0ec7174..736b7b5 100644 --- a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx +++ b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx @@ -26,6 +26,14 @@ class NetworkGame extends Game { gameEventSignal.emit(event); } + override public function start():Void { + var player = Lambda.find(network.game.players, function(player) return player.user.uuid == network.user.uuid); + if (player != null) { + state.controls.push({playerId: [player.team, player.index], control: "human-0"}); + } + super.start(); + } + override public function dispose():Void { super.dispose(); network.gameEventSignal.disconnect(onGameEventProto); diff --git a/src/client/haxe/ru/m/tankz/render/Render.hx b/src/client/haxe/ru/m/tankz/render/Render.hx index fd5db66..aed3ef0 100755 --- a/src/client/haxe/ru/m/tankz/render/Render.hx +++ b/src/client/haxe/ru/m/tankz/render/Render.hx @@ -117,7 +117,7 @@ class Render extends SpriteView implements IRender { case SPAWN(TANK(id, rect, playerId, info)): var item = new TankRenderItem(rect); var tankConfig = config.getTank(info.type); - item.color = config.getColor(playerId); + item.color = info.color; item.skin = tankConfig.skin; item.hits = info.hits; item.bonus = info.bonus; diff --git a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx index 480c65c..cfbb039 100644 --- a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx @@ -33,9 +33,10 @@ import ru.m.tankz.view.popup.LevelPopup; levels.data = [for (i in 0...state.config.game.levels) i]; } - private function start(level:LevelConfig, preset:GamePreset):Void { + private function start(level:LevelConfig, preset:GamePreset, control:ControlPreset):Void { state.levelId = level.id; state.presetId = preset.id; + state.controls = control.values; game = new LocalGame(state); switcher.change(GameFrame.ID); } @@ -61,8 +62,9 @@ import ru.m.tankz.view.popup.LevelPopup; levelPopup.setData( level, state.config.presets, + state.config.controls, storage.get(state.type) ); - levelPopup.show().then(function(preset) preset != null ? start(level, preset) : {}); + levelPopup.show().then(function(result) result != null ? start(level, result.preset, result.control) : {}); } } diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx index 701458c..fc4cc5e 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx @@ -10,7 +10,7 @@ import ru.m.tankz.game.NetworkGame; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.proto.core.GameProto; import ru.m.tankz.proto.core.GameStateProto; -import ru.m.tankz.proto.core.UserProto; +import ru.m.tankz.proto.core.PlayerProto; @:template class GameRoomFrame extends VGroupView { @@ -18,7 +18,7 @@ import ru.m.tankz.proto.core.UserProto; @:view var start:ButtonView; @:view var info:TextView; - @:view var players:VListView; + @:view var players:VListView; @:provide var switcher:FrameSwitcher; @:provide var network:NetworkManager; diff --git a/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx b/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx index 0dba9c1..8e27971 100644 --- a/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx +++ b/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx @@ -3,18 +3,18 @@ package ru.m.tankz.view.network; import haxework.view.HGroupView; import haxework.view.LabelView; import haxework.view.list.ListView; -import ru.m.tankz.proto.core.UserProto; +import ru.m.tankz.proto.core.PlayerProto; -@:template class PlayerItemView extends HGroupView implements IListItemView { +@:template class PlayerItemView extends HGroupView implements IListItemView { public var item_index(default, default):Int; - public var data(default, set):UserProto; + public var data(default, set):PlayerProto; @:view var label:LabelView; - private function set_data(value:UserProto):UserProto { + private function set_data(value:PlayerProto):PlayerProto { data = value; - label.text = '${value.name}'; + label.text = '${value.user.name}'; return data; } diff --git a/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.hx b/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.hx index 87199a1..c7262d7 100644 --- a/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.hx +++ b/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.hx @@ -1,5 +1,6 @@ package ru.m.tankz.view.popup; +import haxework.view.ToggleButtonView; import haxework.view.ButtonView; import haxework.view.DataView; import haxework.view.LabelView; @@ -7,19 +8,28 @@ import haxework.view.popup.PopupView; import ru.m.tankz.config.Config; import ru.m.tankz.game.GameProgress; -@:template class LevelPopup extends PopupView { +typedef Result = { + var control:ControlPreset; + var preset:GamePreset; +} + +@:template class LevelPopup extends PopupView { private var level:LevelConfig; private var progress:GameProgress; @:view var name:LabelView; @:view("presets") var presetsView:DataView; + @:view("controls") var controlsView:DataView; + private var control:ControlPreset; - public function setData(level:LevelConfig, presets:Array, progress:GameProgress):Void { + public function setData(level:LevelConfig, presets:Array, controls:Array, progress:GameProgress):Void { this.level = level; this.progress = progress; name.text = '${level.id}. ${level.name != null ? level.name : "#"}'; presetsView.data = presets; + control = controls[0]; + controlsView.data = controls; } private function presetViewFactory(index:Int, value:GamePreset):ButtonView { @@ -32,7 +42,22 @@ import ru.m.tankz.game.GameProgress; private function onPresetSelect(value:GamePreset):Void { if (progress.isPresetAvailable(level.id, value.id)) { - close(value); + close({control: control, preset: value}); + } + } + + private function controlViewFactory(index:Int, value:ControlPreset):ToggleButtonView { + var result = new ToggleButtonView(); + result.skinId = 'button.simple.active'; + result.on = control == value; + result.text = value.name; + return result; + } + + private function onControlSelect(index:Int, value:ControlPreset, view:ToggleButtonView):Void { + control = value; + for (v in controlsView.dataViews) { + v.on = v == view; } } } diff --git a/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.yaml b/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.yaml index fc584c3..65fc273 100644 --- a/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.yaml +++ b/src/client/haxe/ru/m/tankz/view/popup/LevelPopup.yaml @@ -24,6 +24,15 @@ view: +onPress: $code:reject('close') - $type: haxework.view.SpriteView geometry.size.height: 100% + - id: controls + $type: haxework.view.DataView + factory: $this:controlViewFactory + +onItemSelect: $this:onControlSelect + layout: + $type: haxework.view.layout.HorizontalLayout + hAlign: center + margin: 5 + skinId: panel - id: presets $type: haxework.view.DataView factory: $this:presetViewFactory diff --git a/src/common/haxe/ru/m/tankz/bundle/IConfigBundle.hx b/src/common/haxe/ru/m/tankz/bundle/IConfigBundle.hx index 291c5d3..f6907c3 100644 --- a/src/common/haxe/ru/m/tankz/bundle/IConfigBundle.hx +++ b/src/common/haxe/ru/m/tankz/bundle/IConfigBundle.hx @@ -3,17 +3,6 @@ package ru.m.tankz.bundle; import ru.m.tankz.config.Config; import ru.m.tankz.Type; - -typedef ConfigSource = { - var game:GameConfig; - var map: MapConfig; - var bricks: Array; - var presets: Array; - var points: Array; - var tanks: Array; - var bonuses: Array; -} - interface IConfigBundle { public function get(type:GameType):Config; } diff --git a/src/common/haxe/ru/m/tankz/config/Config.hx b/src/common/haxe/ru/m/tankz/config/Config.hx index ad7e079..bddf56b 100644 --- a/src/common/haxe/ru/m/tankz/config/Config.hx +++ b/src/common/haxe/ru/m/tankz/config/Config.hx @@ -105,6 +105,29 @@ typedef LevelConfig = { @:optional var points:Array; } +typedef PlayerControl = { + var playerId:PlayerId; + var control:String; + @:optional var color:Color; +} + +typedef ControlPreset = { + var id:Int; + var name:String; + var values:Array; +}; + +typedef ConfigSource = { + var game:GameConfig; + var map: MapConfig; + var bricks: Array; + var presets: Array; + var controls: Array; + var points: Array; + var tanks: Array; + var bonuses: Array; +} + class Config { public var type(default, null):String; public var game(default, null):GameConfig; @@ -112,6 +135,7 @@ class Config { public var bricks(default, null):Array; public var tanks(default, null):Array; public var presets(default, null):Array; + public var controls(default, null):Array; public var points(default, null):Array; public var bonuses(default, null):Array; @@ -123,12 +147,17 @@ class Config { private var teamsMap:Map; private var playersMap:Map; + public static function fromSource(type:GameType, source:ConfigSource):Config { + return new Config(type, source.game, source.map, source.bricks, source.presets, source.controls, source.points, source.tanks, source.bonuses); + } + public function new( type:String, game:GameConfig, map:MapConfig, bricks:Array, presets:Array, + controls:Array, points:Array, tanks:Array, bonuses:Array @@ -138,6 +167,7 @@ class Config { this.map = map; this.bricks = bricks; this.presets = presets; + this.controls = controls; this.points = points; this.tanks = tanks; this.bonuses = bonuses; diff --git a/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx b/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx index 817e4c0..aff5b0a 100644 --- a/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx +++ b/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import haxework.color.Color; import ru.m.geom.Direction; import ru.m.geom.Point; import ru.m.geom.Rectangle; @@ -43,11 +44,11 @@ class EntityBuilder { return eagle; } - public function buildTank(point:EntityPoint, playerId:PlayerId, type:TankType, bonusOff:Bool = false):Tank { + public function buildTank(point:EntityPoint, playerId:PlayerId, type:TankType, color:Color, bonusOff:Bool = false):Tank { var playerConfig = config.getPlayer(playerId); var tankConfig = config.getTank(type); var tank = new Tank(++entityId, buildRect(point, tankConfig.width, tankConfig.height), playerId, tankConfig); - tank.color = config.getColor(playerId); + tank.color = color.zero ? config.getColor(playerId) : color; if (!bonusOff) { tank.bonus = Math.random() < playerConfig.bonus; } diff --git a/src/common/haxe/ru/m/tankz/game/EventUtil.hx b/src/common/haxe/ru/m/tankz/game/EventUtil.hx index 47e9eb7..78993c9 100644 --- a/src/common/haxe/ru/m/tankz/game/EventUtil.hx +++ b/src/common/haxe/ru/m/tankz/game/EventUtil.hx @@ -31,7 +31,8 @@ class EventUtil { return GameEvent.SPAWN(TANK(tank.id, tank.rect.clone(), tank.playerId, { type:tank.config.type, hits:tank.hits, - bonus:tank.bonus + bonus:tank.bonus, + color:tank.color, })); } diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx index ec1a679..8201a71 100644 --- a/src/common/haxe/ru/m/tankz/game/Game.hx +++ b/src/common/haxe/ru/m/tankz/game/Game.hx @@ -55,15 +55,15 @@ import ru.m.tankz.Type; public function onGameEvent(event:GameEvent):Void { switch event { - case GameEvent.START(state): + case START(state): this.state = state; - case GameEvent.COMPLETE(state, winnerId): + case COMPLETE(state, winnerId): this.state = state; this.winner = winnerId; - case GameEvent.SPAWN(EAGLE(id, rect, teamId)): + case SPAWN(EAGLE(id, rect, teamId)): var team = getTeam(teamId); team.eagleId = id; - case GameEvent.SPAWN(TANK(id, rect, playerId, info)): + case SPAWN(TANK(id, rect, playerId, info)): var player = getPlayer(playerId); player.tankId = id; player.state.tank = info.type; @@ -79,12 +79,24 @@ import ru.m.tankz.Type; var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]); teams[team.id] = team; } + var controlsById:Map = new Map(); + for (control in state.controls) { + controlsById[control.playerId] = control; + } for (team in teams.iterator()) { for (player in team.players.iterator()) { - var control = controlFactory.build(player.id, AController.fromString(player.config.control)); + var playerControl = controlsById.get(player.id); + if (playerControl != null && !playerControl.color.zero) { + player.state.color = playerControl.color; + } + var controlType:Controller = AController.fromString(playerControl != null ? playerControl.control : player.config.control); + var control = controlFactory.build(player.id, controlType); if (control != null) { player.control = control; player.control.bind(this, engine); + } else { + // ToDo: remove player + player.state.life = 0; } } } diff --git a/src/common/haxe/ru/m/tankz/game/GameEvent.hx b/src/common/haxe/ru/m/tankz/game/GameEvent.hx index 88e1d4c..f21a56c 100644 --- a/src/common/haxe/ru/m/tankz/game/GameEvent.hx +++ b/src/common/haxe/ru/m/tankz/game/GameEvent.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import haxework.color.Color; import ru.m.geom.Position; import ru.m.geom.Rectangle; import ru.m.tankz.control.Control; @@ -9,6 +10,7 @@ typedef TankInfo = { var type:TankType; var hits:Int; var bonus:Bool; + var color:Color; } typedef BrickInfo = { diff --git a/src/common/haxe/ru/m/tankz/game/GameRunner.hx b/src/common/haxe/ru/m/tankz/game/GameRunner.hx index 3ad6b05..ca73ca8 100644 --- a/src/common/haxe/ru/m/tankz/game/GameRunner.hx +++ b/src/common/haxe/ru/m/tankz/game/GameRunner.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import haxework.color.Color; import ru.m.geom.Line; import ru.m.geom.Point; import ru.m.tankz.control.Control; @@ -58,12 +59,13 @@ class GameRunner extends Game implements EngineListener { } } gameEventSignal.emit(EventUtil.buildBricksSpawn(engine.map)); - gameEventSignal.emit(GameEvent.START(state)); + gameEventSignal.emit(START(state)); //for (i in 0...10) spawnBonus(); } private function spawn(task:SpawnTask):Void { - var tank = builder.buildTank(task.point, task.playerId, task.tankType); + var player = getPlayer(task.playerId); + var tank = builder.buildTank(task.point, task.playerId, task.tankType, player.state.color); engine.spawn(tank); gameEventSignal.emit(EventUtil.buildTankSpawn(tank)); tank.protect.connect(onTankProtectChange); @@ -71,15 +73,15 @@ class GameRunner extends Game implements EngineListener { } private function onEagleProtectChange(id:Int, state:Bool):Void { - gameEventSignal.emit(GameEvent.CHANGE(EAGLE_PROTECT(id, state))); + gameEventSignal.emit(CHANGE(EAGLE_PROTECT(id, state))); } private function onTankProtectChange(id:Int, state:Bool):Void { - gameEventSignal.emit(GameEvent.CHANGE(TANK_PROTECT(id, state))); + gameEventSignal.emit(CHANGE(TANK_PROTECT(id, state))); } private function onTankFreezingChange(id:Int, state:Bool):Void { - gameEventSignal.emit(GameEvent.CHANGE(TANK_FREEZE(id, state))); + gameEventSignal.emit(CHANGE(TANK_FREEZE(id, state))); } private function checkComplete():Void { @@ -107,13 +109,13 @@ class GameRunner extends Game implements EngineListener { for (team in teams.iterator()) { for (player in team.players) { if (player.control != null) { - player.control.action(TankAction.STOP); + player.control.action(STOP); player.control.dispose(); } } } Timer.delay(function() { - gameEventSignal.emit(GameEvent.COMPLETE(state, winner)); + gameEventSignal.emit(COMPLETE(state, winner)); }, 3000); } @@ -129,11 +131,11 @@ class GameRunner extends Game implements EngineListener { } private inline function emitTankMove(tank:Tank):Void { - gameEventSignal.emit(GameEvent.MOVE(TANK(tank.id, {x:tank.rect.x, y:tank.rect.y, direction:tank.rect.direction}))); + gameEventSignal.emit(MOVE(TANK(tank.id, {x:tank.rect.x, y:tank.rect.y, direction:tank.rect.direction}))); } private inline function emitTankChange(tank:Tank):Void { - gameEventSignal.emit(GameEvent.CHANGE(TANK(tank.id, tank.config.type, tank.hits, tank.bonus))); + gameEventSignal.emit(CHANGE(TANK(tank.id, tank.config.type, tank.hits, tank.bonus))); } public function onCollision(entity:EntityType, with:EntityType):Void { @@ -154,14 +156,14 @@ class GameRunner extends Game implements EngineListener { tank.rect.lean(cell.rect); emitTankMove(tank); case [BULLET(bullet), BULLET(other_bullet)]: - gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id))); - gameEventSignal.emit(GameEvent.DESTROY(BULLET(other_bullet.id))); + gameEventSignal.emit(DESTROY(BULLET(bullet.id))); + gameEventSignal.emit(DESTROY(BULLET(other_bullet.id))); case [BULLET(bullet), CELL(cell)]: bullet.rect.lean(cell.rect); - gameEventSignal.emit(GameEvent.HIT(CELL(cell.cellX, cell.cellY, buildShot(bullet)))); - gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id))); + gameEventSignal.emit(HIT(CELL(cell.cellX, cell.cellY, buildShot(bullet)))); + gameEventSignal.emit(DESTROY(BULLET(bullet.id))); case [TANK(tank), BONUS(bonus)]: - gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus.id, {tankId: tank.id, score: bonus.config.score}))); + gameEventSignal.emit(DESTROY(BONUS(bonus.id, {tankId: tank.id, score: bonus.config.score}))); case [BULLET(bullet), TANK(tank)]/* | [TANK(tank), BULLET(bullet)]*/: if (bullet.tankId == tank.id || (!config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) { // Nothing @@ -173,27 +175,27 @@ class GameRunner extends Game implements EngineListener { tank.bonus = false; spawnBonus(); } - gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet)))); + gameEventSignal.emit(HIT(TANK(tank.id, buildShot(bullet)))); emitTankChange(tank); } else if (tank.config.downgrade != null) { tank.config = config.getTank(tank.config.downgrade); - gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet)))); + gameEventSignal.emit(HIT(TANK(tank.id, buildShot(bullet)))); emitTankChange(tank); } else { var score = tank.config.score; if (tank.playerId.team == bullet.playerId.team) { score = Math.round(score * -0.5); } - gameEventSignal.emit(GameEvent.DESTROY(TANK(tank.id, buildShot(bullet, score)))); + gameEventSignal.emit(DESTROY(TANK(tank.id, buildShot(bullet, score)))); } } - gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id))); + gameEventSignal.emit(DESTROY(BULLET(bullet.id))); } case [BULLET(bullet), EAGLE(eagle)]: if (!eagle.protect.active) { - gameEventSignal.emit(GameEvent.DESTROY(EAGLE(eagle.id, buildShot(bullet, eagle.score)))); + gameEventSignal.emit(DESTROY(EAGLE(eagle.id, buildShot(bullet, eagle.score)))); } - gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id))); + gameEventSignal.emit(DESTROY(BULLET(bullet.id))); case _: } } @@ -203,7 +205,7 @@ class GameRunner extends Game implements EngineListener { case TANK(tank): emitTankMove(tank); case BULLET(bullet): - gameEventSignal.emit(GameEvent.MOVE(BULLET(bullet.id, {x:bullet.rect.x, y:bullet.rect.y, direction:bullet.rect.direction}))); + gameEventSignal.emit(MOVE(BULLET(bullet.id, {x:bullet.rect.x, y:bullet.rect.y, direction:bullet.rect.direction}))); case _: } } @@ -220,7 +222,7 @@ class GameRunner extends Game implements EngineListener { } var bonus = builder.buildBonus(point, type); engine.spawn(bonus); - gameEventSignal.emit(GameEvent.SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type))); + gameEventSignal.emit(SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type))); } private inline function alienTank(team:TeamId):Tank->Bool { @@ -235,7 +237,7 @@ class GameRunner extends Game implements EngineListener { upgradeTank(tank); case "grenade": for (t in engine.iterTanks(alienTank(tank.playerId.team))) { - gameEventSignal.emit(GameEvent.DESTROY(TANK(t.id, {tankId: tank.id}))); + gameEventSignal.emit(DESTROY(TANK(t.id, {tankId: tank.id}))); } case "helmet": tank.protect.on(bonus.config.duration); @@ -243,7 +245,7 @@ class GameRunner extends Game implements EngineListener { for (t in engine.iterTanks(alienTank(tank.playerId.team))) { t.freezing.on(bonus.config.duration); t.stop(); - gameEventSignal.emit(GameEvent.STOP(TANK(t.id))); + gameEventSignal.emit(STOP(TANK(t.id))); } case "shovel": // ToDo: protect eagle/area @@ -255,7 +257,7 @@ class GameRunner extends Game implements EngineListener { case "gun": upgradeTank(tank, 5); case _: - gameEventSignal.emit(GameEvent.DESTROY(TANK(tank.id, {tankId: tank.id}))); // :-D + gameEventSignal.emit(DESTROY(TANK(tank.id, {tankId: tank.id}))); // :-D } } @@ -274,34 +276,34 @@ class GameRunner extends Game implements EngineListener { var player = getPlayer(playerId); var team = getTeam(playerId.team); player.state.score += score; - gameEventSignal.emit(GameEvent.CHANGE(PLAYER_SCORE(playerId, player.state.score))); - gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(playerId.team, state.getTeamScore(team.id)))); + gameEventSignal.emit(CHANGE(PLAYER_SCORE(playerId, player.state.score))); + gameEventSignal.emit(CHANGE(TEAM_SCORE(playerId.team, state.getTeamScore(team.id)))); } private function changeLife(playerId:PlayerId, life:Int):Void { var player = getPlayer(playerId); player.state.life += life; - gameEventSignal.emit(GameEvent.CHANGE(PLAYER_LIFE(playerId, player.state.life))); + gameEventSignal.emit(CHANGE(PLAYER_LIFE(playerId, player.state.life))); } private function changeTeamLife(teamId:TeamId, life:Int):Void { var team = getTeam(teamId); team.state.life += life; - gameEventSignal.emit(GameEvent.CHANGE(TEAM_LIFE(teamId, team.state.life))); + gameEventSignal.emit(CHANGE(TEAM_LIFE(teamId, team.state.life))); } override public function onGameEvent(event:GameEvent):Void { super.onGameEvent(event); switch event { - case GameEvent.START(_): + case START(_): timer = new Timer(30); timer.run = update; - case GameEvent.COMPLETE(_, _): + case COMPLETE(_, _): if (timer != null) { timer.stop(); timer = null; } - case GameEvent.ACTION(tankId, SHOT): + case ACTION(tankId, SHOT): var tank:Tank = cast engine.entities.get(tankId); var player = getPlayer(tank.playerId); if (!tank.freezing.active && player.bullets < tank.config.bullets) { @@ -311,21 +313,21 @@ class GameRunner extends Game implements EngineListener { bullet.tank = tank; bullet.move(bullet.rect.direction); engine.spawn(bullet); - gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing))); + gameEventSignal.emit(SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing))); } - case GameEvent.ACTION(tankId, MOVE(direction)): + case ACTION(tankId, MOVE(direction)): engine.move(tankId, direction); - case GameEvent.ACTION(tankId, STOP): - gameEventSignal.emit(GameEvent.STOP(TANK(tankId))); + case ACTION(tankId, STOP): + gameEventSignal.emit(STOP(TANK(tankId))); engine.stop(tankId); - case GameEvent.SPAWN(TANK(_, _, playerId, _)): + case SPAWN(TANK(_, _, playerId, _)): var control = getPlayer(playerId).control; if (control != null) { control.start(); } - case GameEvent.SPAWN(BULLET(_, _, playerId, _)): + case SPAWN(BULLET(_, _, playerId, _)): getPlayer(playerId).bullets++; - case GameEvent.DESTROY(EAGLE(id, shot)): + case DESTROY(EAGLE(id, shot)): var eagle:Eagle = engine.getEntity(id); eagle.death = true; if (shot.score != 0) { @@ -333,7 +335,7 @@ class GameRunner extends Game implements EngineListener { changeScore(tank.playerId, shot.score); } checkComplete(); - case GameEvent.DESTROY(TANK(id, shot)): + case DESTROY(TANK(id, shot)): var tank:Tank = engine.getEntity(id); var team = getTeam(tank.playerId.team); var player = getPlayer(tank.playerId); @@ -362,7 +364,7 @@ class GameRunner extends Game implements EngineListener { changeScore(shooterTank.playerId, shot.score); } engine.destroy(id); - case GameEvent.DESTROY(BONUS(id, shot)): + case DESTROY(BONUS(id, shot)): var bonus:Bonus = engine.getEntity(id); var tank:Tank = engine.getEntity(shot.tankId); applyBonus(tank, bonus); @@ -370,7 +372,7 @@ class GameRunner extends Game implements EngineListener { changeScore(tank.playerId, shot.score); } engine.destroy(id); - case GameEvent.DESTROY(BULLET(id)): + case DESTROY(BULLET(id)): var bullet:Bullet = engine.getEntity(id); var player = getPlayer(bullet.playerId); player.bullets--; @@ -385,13 +387,13 @@ class GameRunner extends Game implements EngineListener { if (cell.armor == bullet.config.piercing) { engine.destroyCell(cell.cellX, cell.cellY); var brick = engine.map.getBrick(cell.position); - gameEventSignal.emit(GameEvent.DESTROY(CELL(brick.id, cell.cellX - brick.cellX * 2, cell.cellY - brick.cellY * 2, shot))); + 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); for (cell in brick.cells) { engine.destroyCell(cell.cellX, cell.cellY); } - gameEventSignal.emit(GameEvent.DESTROY(BRICK(brick.id, shot))); + gameEventSignal.emit(DESTROY(BRICK(brick.id, shot))); } } } diff --git a/src/common/haxe/ru/m/tankz/game/GameState.hx b/src/common/haxe/ru/m/tankz/game/GameState.hx index 5b8ffba..70cd9bf 100644 --- a/src/common/haxe/ru/m/tankz/game/GameState.hx +++ b/src/common/haxe/ru/m/tankz/game/GameState.hx @@ -72,6 +72,7 @@ class GameState { public var type:GameType; public var presetId:PresetId; public var levelId:LevelId; + public var controls:Array; public var players:Map; public var teams:Map; public var preset(get, null):GamePreset; @@ -81,10 +82,12 @@ class GameState { @:provide static private var configBundle:IConfigBundle; @:provide static private var levelBundle:ILevelBundle; - public function new(type:GameType, presetId:PresetId = 0, levelId:Int = 0, state:GameState = null) { + public function new(type:GameType, presetId:PresetId = 0, levelId:Int = 0, state:GameState = null, controls:Array = null) { this.type = type; this.presetId = presetId; this.levelId = levelId; + //this.controls = controls == null ? config.controls[0].values : controls; + this.controls = controls == null ? [] : controls; if (state == null) { this.teams = new Map(); this.players = new Map(); diff --git a/src/common/proto/core.proto b/src/common/proto/core.proto index bbdba4d..6422cf0 100644 --- a/src/common/proto/core.proto +++ b/src/common/proto/core.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package ru.m.tankz.proto.core; - message UserProto { string uuid = 1; string name = 2; @@ -14,11 +13,17 @@ enum GameStateProto { ENDED = 2; } +message PlayerProto { + UserProto user = 1; + string team = 2; + int32 index = 3; +} + message GameProto { int32 id = 1; string type = 2; int32 level = 3; UserProto creator = 4; - repeated UserProto players = 5; + repeated PlayerProto players = 5; GameStateProto state = 6; } diff --git a/src/common/resources/classic/config.yaml b/src/common/resources/classic/config.yaml index 17d93dc..9cc513b 100644 --- a/src/common/resources/classic/config.yaml +++ b/src/common/resources/classic/config.yaml @@ -38,14 +38,15 @@ team: human: &team_human id: human players: - - {<<: *human, index: 0, color: 0xFFFF00, control: human-0} + - {<<: *human, index: 0, color: 0xFFFF00, control: 'null'} + - {<<: *human, index: 1, color: 0x15C040, control: 'null'} eagle: score: 0 points: - {team: human, type: eagle, index: -1, direction: right, x: 12, y: 24} - {team: human, type: tank, index: 0, direction: top, x: 8, y: 24} - #- {team: human, type: tank, index: 1, direction: top, x: 16, y: 24} + - {team: human, type: tank, index: 1, direction: top, x: 16, y: 24} - {team: bot, type: tank, index: -1, direction: bottom, x: 0, y: 0} - {team: bot, type: tank, index: -2, direction: bottom, x: 12, y: 0} - {team: bot, type: tank, index: -3, direction: bottom, x: 24, y: 0} @@ -195,3 +196,17 @@ presets: - {<<: *bot, index: 3, control: bot-hard} - {<<: *bot, index: 4, control: bot-hard} - {<<: *bot, index: 5, control: bot-hard} + +controls: + - id: 0 + name: 1 Player + values: + - playerId: [human, 0] + control: human-0 + - id: 1 + name: 2 Player + values: + - playerId: [human, 0] + control: human-0 + - playerId: [human, 1] + control: human-1 diff --git a/src/common/resources/death/config.yaml b/src/common/resources/death/config.yaml index 5d70f99..63af267 100644 --- a/src/common/resources/death/config.yaml +++ b/src/common/resources/death/config.yaml @@ -37,8 +37,6 @@ presets: teams: - id: alpha color: 0xFF4422 - players: - - {<<: *player, index: 0, control: human-0} <<: *team - id: beta color: 0xFFD000 @@ -91,3 +89,17 @@ tanks: skin: pc bonuses: [] + +controls: + - id: 0 + name: 1 Player + values: + - playerId: [alpha, 0] + control: human-0 + - id: 1 + name: 2 Player + values: + - playerId: [alpha, 0] + control: human-0 + - playerId: [beta, 0] + control: human-1 diff --git a/src/common/resources/dota/config.yaml b/src/common/resources/dota/config.yaml index 5fd3333..6e535c4 100644 --- a/src/common/resources/dota/config.yaml +++ b/src/common/resources/dota/config.yaml @@ -41,7 +41,7 @@ team: id: radiant color: 0xff4422 players: - - {<<: *player-slow, index: 0, control: human-0, color: 0xff8866} + - {<<: *player-slow, index: 0, control: bot-hard} - {<<: *player-fast, index: 1, control: bot-hard} - {<<: *player-slow, index: 2, control: bot-hard} - {<<: *player-fast, index: 3, control: bot-hard} @@ -114,3 +114,29 @@ bonuses: - {type: life} - {type: shovel, duration: 10} - {type: star} + +controls: + - id: 0 + name: 1 Player + values: + - playerId: [radiant, 0] + control: human-0 + color: 0xff8866 + - id: 1 + name: 2 Player Coop + values: + - playerId: [radiant, 0] + control: human-0 + color: 0xff8866 + - playerId: [radiant, 1] + control: human-1 + color: 0xff8866 + - id: 2 + name: 2 Player VS + values: + - playerId: [radiant, 0] + control: human-0 + color: 0xff8866 + - playerId: [dire, 0] + control: human-1 + color: 0x4294ff diff --git a/src/editor/haxe/ru/m/tankz/editor/level/MapEditView.hx b/src/editor/haxe/ru/m/tankz/editor/level/MapEditView.hx index 07d2fa9..b075710 100644 --- a/src/editor/haxe/ru/m/tankz/editor/level/MapEditView.hx +++ b/src/editor/haxe/ru/m/tankz/editor/level/MapEditView.hx @@ -117,7 +117,7 @@ enum Brush { var playerId = new PlayerId(point.team, point.index < 0 ? 0 : point.index); var player = config.getPlayer(playerId); var tankSpawn = player.tanks[0]; - var tank = builder.buildTank(point, playerId, tankSpawn.type, true); + var tank = builder.buildTank(point, playerId, tankSpawn.type, 0, true); pointEntities[pointKey(point)] = tank; gameEventSignal.emit(EventUtil.buildTankSpawn(tank)); } diff --git a/src/server/haxe/ru/m/tankz/server/bundle/ServerConfigBundle.hx b/src/server/haxe/ru/m/tankz/server/bundle/ServerConfigBundle.hx index cf1e67b..cb10d26 100644 --- a/src/server/haxe/ru/m/tankz/server/bundle/ServerConfigBundle.hx +++ b/src/server/haxe/ru/m/tankz/server/bundle/ServerConfigBundle.hx @@ -16,6 +16,6 @@ class ServerConfigBundle implements IConfigBundle { var path:String = FileSystem.absolutePath('./resources/${type}/config.yaml'); var data:String = File.getContent(path); var source:ConfigSource = Yaml.parse(data, Parser.options().useObjects()); - return new Config(type, source.game, source.map, source.bricks, source.presets, source.points, source.tanks, source.bonuses); + return Config.fromSource(type, source); } } diff --git a/src/server/haxe/ru/m/tankz/server/control/ServerControlFactory.hx b/src/server/haxe/ru/m/tankz/server/control/ServerControlFactory.hx index a4b4cda..ec842cc 100644 --- a/src/server/haxe/ru/m/tankz/server/control/ServerControlFactory.hx +++ b/src/server/haxe/ru/m/tankz/server/control/ServerControlFactory.hx @@ -1,7 +1,14 @@ package ru.m.tankz.server.control; +import ru.m.tankz.Type; +import ru.m.tankz.control.Control; import ru.m.tankz.control.BaseControlFactory; +class ClientControl extends Control {} + class ServerControlFactory extends BaseControlFactory { + override private function buildHuman(id:PlayerId, index:Int):Control { + return new ClientControl(id); + } } diff --git a/src/server/haxe/ru/m/tankz/server/game/GameManager.hx b/src/server/haxe/ru/m/tankz/server/game/GameManager.hx index f2bd359..02c572d 100644 --- a/src/server/haxe/ru/m/tankz/server/game/GameManager.hx +++ b/src/server/haxe/ru/m/tankz/server/game/GameManager.hx @@ -58,9 +58,9 @@ class _GameListener implements GameListener { .setId(++counter) .setCreator(user) .setType(type) - .setLevel(level) - .setPlayers([user]); + .setLevel(level); var game = new ServerGame(proto); + game.joinUser(user); games.push(game); gamesById[game.proto.id] = game; gamesByCreator[game.proto.creator.uuid] = game; @@ -71,7 +71,7 @@ class _GameListener implements GameListener { public function join(gameId:Int, user:UserProto):Void { if (gamesById.exists(gameId)) { var game = gamesById[gameId]; - game.proto.players.push(user); + game.joinUser(user); gamesByUser[user.uuid] = game; changeSignal.emit(game, JOIN(user)); } @@ -92,7 +92,7 @@ class _GameListener implements GameListener { delete(gamesByCreator[user.uuid].proto.id); } else if (gamesByUser.exists(user.uuid)) { var game = gamesByUser[user.uuid]; - game.proto.setPlayers(game.proto.players.filter(function(player) return player.uuid != user.uuid)); + game.leaveUser(user); changeSignal.emit(game, LEAVE(user)); } } diff --git a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx index aa9058f..51b8e5a 100644 --- a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx +++ b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx @@ -1,8 +1,11 @@ package ru.m.tankz.server.game; +import ru.m.tankz.config.Config; import ru.m.tankz.game.GameRunner; import ru.m.tankz.game.GameState; import ru.m.tankz.proto.core.GameProto; +import ru.m.tankz.proto.core.PlayerProto; +import ru.m.tankz.proto.core.UserProto; import ru.m.tankz.server.control.ServerControlFactory; class ServerGame extends GameRunner { @@ -15,4 +18,22 @@ class ServerGame extends GameRunner { this.controlFactory = new ServerControlFactory(); this.proto = proto; } + + public function joinUser(user:UserProto):Void { + var index = proto.players.length; + var teamId = "human"; // ToDo: + proto.players.push(new PlayerProto().setUser(user).setTeam(teamId).setIndex(index)); + } + + public function leaveUser(user:UserProto):Void { + proto.setPlayers(proto.players.filter(function(player) return player.user.uuid != user.uuid)); + } + + override public function start():Void { + state.controls = proto.players.map(function(player):PlayerControl return { + playerId: [player.team, player.index], + control: 'human-0' + }); + super.start(); + } }