[common] added LevelPack

This commit is contained in:
2019-06-14 16:06:22 +03:00
parent 4c3f1ca0fc
commit e39de4467d
82 changed files with 1321 additions and 1149 deletions

View File

@@ -1,4 +1,6 @@
const gulp = require('gulp'); const gulp = require('gulp');
const zip = require('gulp-zip');
const foreach = require('gulp-foreach');
const gulpClean = require('gulp-clean'); const gulpClean = require('gulp-clean');
const Config = require('./config.json'); const Config = require('./config.json');
const packageInfo = require('./package.json'); const packageInfo = require('./package.json');
@@ -25,6 +27,19 @@ exports.generate = function generate() {
}); });
}; };
exports.levels = function () {
return gulp.src("./src/common/level/*").pipe(foreach(function (stream, file) {
const type = file.path.substr(file.path.lastIndexOf("/") + 1);
gulp.src("./src/common/level/" + type + "/*").pipe(foreach(function (stream, file) {
const name = file.path.substr(file.path.lastIndexOf("/") + 1);
gulp.src("./src/common/level/" + type + "/" + name + "/*")
.pipe(zip(`${type}_${name}.zip`))
.pipe(gulp.dest("./target/levels"));
}));
return stream;
}));
};
/** /**
* ToDo: * ToDo:
* windows target * windows target
@@ -46,7 +61,8 @@ const config = new Project.Config({
'src-gen/haxe', 'src-gen/haxe',
], ],
assets: [ assets: [
'src/common/resources' 'src/common/resources',
'target/levels'
], ],
flags: [ flags: [
//'proto_debug', //'proto_debug',

2303
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,9 @@
"gulp": "^4.0.0", "gulp": "^4.0.0",
"gulp-add": "0.0.2", "gulp-add": "0.0.2",
"gulp-clean": "^0.4.0", "gulp-clean": "^0.4.0",
"gulp-foreach": "^0.1.0",
"gulp-haxetool": "^0.0.19", "gulp-haxetool": "^0.0.19",
"gulp-zip": "^5.0.0",
"yargs": "^13.2.4" "yargs": "^13.2.4"
}, },
"haxeDependencies": { "haxeDependencies": {

View File

@@ -15,7 +15,7 @@ class ConfigBundle implements IConfigBundle {
public function get(type:GameType):Config { public function get(type:GameType):Config {
if (!_cache.exists(type)) { if (!_cache.exists(type)) {
var source:ConfigSource = Yaml.parse(Assets.getText('resources/${type}/config.yaml'), Parser.options().useObjects()); var source:ConfigSource = Yaml.parse(Assets.getText('resources/config/${type}.yaml'), Parser.options().useObjects());
_cache.set(type, Config.fromSource(type, source)); _cache.set(type, Config.fromSource(type, source));
} }
return _cache.get(type); return _cache.get(type);

View File

@@ -1,5 +1,10 @@
package ru.m.tankz.bundle; package ru.m.tankz.bundle;
import haxe.io.BytesInput;
import haxe.zip.Entry;
import haxe.zip.Reader;
import lime.utils.Bytes;
import lime.utils.CompressionAlgorithm;
import openfl.Assets; import openfl.Assets;
import ru.m.tankz.config.Config; import ru.m.tankz.config.Config;
import ru.m.tankz.Type; import ru.m.tankz.Type;
@@ -7,17 +12,27 @@ import ru.m.tankz.util.LevelUtil;
class LevelBundle implements ILevelBundle { class LevelBundle implements ILevelBundle {
private var cache:Map<String, LevelConfig> = new Map();
public function new() {} public function new() {}
public function get(type:GameType, config:Config, levelId:LevelId):LevelConfig { private function extract(entry:Entry):LevelConfig {
var key = '${type}:${levelId}'; var bytes:Bytes = entry.data;
if (!cache.exists(key)) { if (entry.compressed) {
var data:String = Assets.getText('resources/${type}/levels/level${LevelUtil.formatLevel(levelId)}.txt'); bytes = bytes.decompress(CompressionAlgorithm.DEFLATE);
cache[key] = LevelUtil.loads(config, data);
cache[key].id = levelId;
} }
return cache[key]; var level = LevelUtil.loads(bytes.toString());
if (level.id == null) {
level.id = Std.parseInt(entry.fileName.split("level").pop());
}
return level;
}
public function get(type:GameType, name:String):LevelPack {
var data = Assets.getBytes('levels/${type}_${name}.zip');
var files = Reader.readZip(new BytesInput(data));
return {
type: type,
name: name,
data: Lambda.array(files.map(extract)),
};
} }
} }

View File

@@ -14,7 +14,7 @@ class NetworkGame extends Game {
private var network:NetworkManager; private var network:NetworkManager;
public function new(network:NetworkManager) { public function new(network:NetworkManager) {
super(new GameState(network.room.game.type, 0, network.room.game.level)); super(new GameState(network.room.game.type, 0));
this.network = network; this.network = network;
this.controlFactory = new NetworkControlFactory(); this.controlFactory = new NetworkControlFactory();
network.gameEventSignal.connect(onGameEventProto); network.gameEventSignal.connect(onGameEventProto);

View File

@@ -1,6 +1,5 @@
package ru.m.tankz.view; package ru.m.tankz.view;
import haxe.ds.Option;
import haxework.view.frame.FrameSwitcher; import haxework.view.frame.FrameSwitcher;
import haxework.view.VGroupView; import haxework.view.VGroupView;
import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameEvent;
@@ -10,7 +9,6 @@ import ru.m.tankz.game.record.GameRecord;
import ru.m.tankz.network.NetworkManager; import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.sound.SoundManager; import ru.m.tankz.sound.SoundManager;
import ru.m.tankz.storage.GameStorage; import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.Type;
import ru.m.tankz.view.game.GameView; import ru.m.tankz.view.game.GameView;
@:template class GameFrame extends VGroupView implements GameListener { @:template class GameFrame extends VGroupView implements GameListener {
@@ -24,7 +22,6 @@ import ru.m.tankz.view.game.GameView;
@:provide var soundManager:SoundManager; @:provide var soundManager:SoundManager;
@:provide var state:GameState; @:provide var state:GameState;
@:provide var record:GameRecord; @:provide var record:GameRecord;
@:provide("next") var nextState:GameState;
@:provide var switcher:FrameSwitcher; @:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage; @:provide var gameStorage:GameStorage;
@@ -56,34 +53,12 @@ import ru.m.tankz.view.game.GameView;
switch event { switch event {
case GameEvent.COMPLETE(state, winner): case GameEvent.COMPLETE(state, winner):
this.state = state; this.state = state;
nextState = switch next(winner) {
case Some(s):
// ToDo:
var progress = gameStorage.get(game.type);
progress.completeLevel(state.levelId, state.presetId);
gameStorage.set(progress);
s;
case None:
null;
}
stop(); stop();
switcher.change(ResultFrame.ID); switcher.change(ResultFrame.ID);
case _: case _:
} }
} }
// ToDo:
private function next(winner:TeamId):Option<GameState> {
for (rule in game.config.game.complete) {
if (rule.team != null && rule.team != winner) {
return Option.None;
}
}
var level = state.levelId + 1;
if (level >= game.config.game.levels) level = 0;
return Option.Some(new GameState(game.type, state.presetId, level, state));
}
public function onHide():Void { public function onHide():Void {
stop(); stop();
soundManager.stopAll(); soundManager.stopAll();

View File

@@ -11,14 +11,13 @@ import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame; import ru.m.tankz.game.IGame;
import ru.m.tankz.local.LocalGame; import ru.m.tankz.local.LocalGame;
import ru.m.tankz.storage.GameStorage; import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.Type;
import ru.m.tankz.view.popup.LevelPopup; import ru.m.tankz.view.popup.LevelPopup;
@:template class LevelFrame extends VGroupView { @:template class LevelFrame extends VGroupView {
public static inline var ID = "level"; public static inline var ID = "level";
@:view var header:LabelView; @:view var header:LabelView;
@:view var levels:DataView<LevelId, ButtonView>; @:view var levels:DataView<LevelConfig, ButtonView>;
@:provide var state:GameState; @:provide var state:GameState;
@:provide var game:IGame; @:provide var game:IGame;
@@ -30,35 +29,35 @@ import ru.m.tankz.view.popup.LevelPopup;
public function onShow():Void { public function onShow():Void {
header.text = state.type; header.text = state.type;
levels.data = [for (i in 0...state.config.game.levels) i]; var pack = levelBundle.get(state.type, "standard");
levels.data = pack.data;
} }
private function start(level:LevelConfig, preset:GamePreset, control:ControlPreset):Void { private function start(level:LevelConfig, preset:GamePreset, control:ControlPreset):Void {
state.levelId = level.id; state.level = level;
state.presetId = preset.id; state.presetId = preset.id;
state.controls = control.values; state.controls = control.values;
game = new LocalGame(state); game = new LocalGame(state);
switcher.change(GameFrame.ID); switcher.change(GameFrame.ID);
} }
private function levelViewFactory(index:Int, levelId:LevelId):ButtonView { private function levelViewFactory(index:Int, level:LevelConfig):ButtonView {
var progress = storage.get(state.type); var progress = storage.get(state.type);
var result = new ButtonView(); var result = new ButtonView();
result.skinId = "button.level"; result.skinId = "button.level";
var presetsLine = [for (p in state.config.presets) progress.isPresetCompleted(levelId, p.id) ? '*' : '_'].join(''); var presetsLine = [for (p in state.config.presets) progress.isPresetCompleted(level.id, p.id) ? '*' : '_'].join('');
result.text = '${levelId}\n${presetsLine}'; result.text = '${level.id}\n${presetsLine}';
result.disabled = !progress.isLevelAvailable(levelId); result.disabled = !progress.isLevelAvailable(level.id);
return result; return result;
} }
private function onLevelSelect(index:Int, levelId:LevelId, view:ButtonView):Void { private function onLevelSelect(index:Int, level:LevelConfig, view:ButtonView):Void {
if (!storage.get(state.type).isLevelAvailable(levelId)) { if (!storage.get(state.type).isLevelAvailable(level.id)) {
return; return;
} }
if (levelPopup == null) { if (levelPopup == null) {
levelPopup = new LevelPopup(); levelPopup = new LevelPopup();
} }
var level = levelBundle.get(state.type, state.config, levelId);
levelPopup.setData( levelPopup.setData(
level, level,
state.config.presets, state.config.presets,

View File

@@ -8,6 +8,8 @@ typedef TeamId = String;
typedef BrickType = String; typedef BrickType = String;
typedef BrickIndex = Int;
typedef TankType = String; typedef TankType = String;
typedef BonusType = String; typedef BonusType = String;

View File

@@ -4,5 +4,5 @@ import ru.m.tankz.config.Config;
import ru.m.tankz.Type; import ru.m.tankz.Type;
interface ILevelBundle { interface ILevelBundle {
public function get(type:GameType, config:Config, levelId:LevelId):LevelConfig; public function get(type:GameType, name:String):LevelPack;
} }

View File

@@ -108,12 +108,18 @@ typedef GamePreset = {
typedef LevelConfig = { typedef LevelConfig = {
@:optional var id:LevelId; @:optional var id:LevelId;
var data:Array<BrickConfig>; var data:Array<BrickIndex>;
@:optional var name:String; @:optional var name:String;
@:optional var points:Array<SpawnPoint>; @:optional var points:Array<SpawnPoint>;
@:optional var size:{width:Int, height:Int}; @:optional var size:{width:Int, height:Int};
} }
typedef LevelPack = {
var type:GameType;
var name:String;
var data:Array<LevelConfig>;
}
typedef PlayerControl = { typedef PlayerControl = {
var playerId:PlayerId; var playerId:PlayerId;
var control:String; var control:String;

View File

@@ -51,7 +51,8 @@ class GameRunner extends Game implements EngineListener {
override public function start():Void { override public function start():Void {
super.start(); super.start();
engine.map.setData(state.level.data); var mapData = state.level.data.map(function(index:BrickIndex) return config.getBrickByIndex(index));
engine.map.setData(mapData);
for (team in teams.iterator()) { for (team in teams.iterator()) {
team.spawner.runner = spawn; team.spawner.runner = spawn;
for (player in team.players.iterator()) { for (player in team.players.iterator()) {
@@ -135,7 +136,8 @@ class GameRunner extends Game implements EngineListener {
for (team in teams.iterator()) { for (team in teams.iterator()) {
if (team.isAlive) { if (team.isAlive) {
if (team.eagleId > -1) { if (team.eagleId > -1) {
if (!cast(engine.entities[team.eagleId], Eagle).death) { var eagle:Eagle = engine.getEntity(team.eagleId);
if (!eagle.death) {
actives.push(team.id); actives.push(team.id);
} }
} else { } else {
@@ -148,12 +150,6 @@ class GameRunner extends Game implements EngineListener {
case []: complete(null); case []: complete(null);
case _: case _:
} }
/*if (actives.length == 1) {
complete(actives[0]);
}
if (actives.length == 0) {
complete(null);
}*/
} }
private function complete(winner:TeamId):Void { private function complete(winner:TeamId):Void {

View File

@@ -72,21 +72,20 @@ class GameState {
public var type:GameType; public var type:GameType;
public var presetId:PresetId; public var presetId:PresetId;
public var levelId:LevelId; public var levelId(get, null):LevelId;
public var controls:Array<PlayerControl>; public var controls:Array<PlayerControl>;
public var players:Map<String, PlayerState>; public var players:Map<String, PlayerState>;
public var teams:Map<TeamId, TeamState>; public var teams:Map<TeamId, TeamState>;
public var preset(get, null):GamePreset; public var preset(get, null):GamePreset;
public var config(get, null):Config; public var config(get, null):Config;
public var level(get, null):LevelConfig; public var level(default, default):LevelConfig;
@:provide static private var configBundle:IConfigBundle; @: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, controls:Array<PlayerControl> = null) { public function new(type:GameType, presetId:PresetId = 0, level:LevelConfig = null, state:GameState = null, controls:Array<PlayerControl> = null) {
this.type = type; this.type = type;
this.presetId = presetId; this.presetId = presetId;
this.levelId = levelId; this.level = level;
//this.controls = controls == null ? config.controls[0].values : controls; //this.controls = controls == null ? config.controls[0].values : controls;
this.controls = controls == null ? [] : controls; this.controls = controls == null ? [] : controls;
if (state == null) { if (state == null) {
@@ -118,8 +117,8 @@ class GameState {
return configBundle.get(type); return configBundle.get(type);
} }
private function get_level():LevelConfig { private function get_levelId():LevelId {
return levelBundle.get(type, config, levelId); return level == null ? 0 : level.id;
} }
public function getTeamLife(id:TeamId):Int { public function getTeamLife(id:TeamId):Int {

View File

@@ -32,7 +32,7 @@ class GameRecord {
} }
private inline function get_state():GameState { private inline function get_state():GameState {
return new GameState(info.type, info.presetId, info.levelId); return new GameState(info.type, info.presetId);
} }
public function toString():String { public function toString():String {

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.map; package ru.m.tankz.map;
import ru.m.tankz.Type.BrickType;
import haxe.ds.HashMap; import haxe.ds.HashMap;
import ru.m.tankz.map.Grid; import ru.m.tankz.map.Grid;
import ru.m.geom.Point; import ru.m.geom.Point;

View File

@@ -1,6 +1,7 @@
package ru.m.tankz.util; package ru.m.tankz.util;
import ru.m.tankz.config.Config; import ru.m.tankz.config.Config;
import ru.m.tankz.Type;
import yaml.Parser; import yaml.Parser;
import yaml.Renderer; import yaml.Renderer;
import yaml.Yaml; import yaml.Yaml;
@@ -20,12 +21,12 @@ class LevelUtil {
return result; return result;
} }
public static function loadsOld(config:Config, data:String):LevelConfig { public static function loadsOld(data:String):LevelConfig {
var bricks:Array<BrickConfig> = []; var bricks:Array<BrickIndex> = [];
for (line in ~/\s+/g.split(data)) { for (line in ~/\s+/g.split(data)) {
for (c in line.split('')) { for (c in line.split('')) {
if (c.length > 0) { if (c.length > 0) {
bricks.push(config.getBrickByIndex(Std.parseInt(c))); bricks.push(Std.parseInt(c));
} }
} }
} }
@@ -34,22 +35,22 @@ class LevelUtil {
} }
} }
public static function loads(config:Config, data:String):LevelConfig { public static function loads(data:String):LevelConfig {
if (config.type == 'classic') { try {
return loadsOld(config, data);
} else {
var obj:LevelSource = Yaml.parse(data, Parser.options().useObjects()); var obj:LevelSource = Yaml.parse(data, Parser.options().useObjects());
return { return {
data: obj.data.split('').map(function(c) return config.getBrickByIndex(Std.parseInt(c))), data: obj.data.split('').map(function(c) return Std.parseInt(c)),
points: obj.points, points: obj.points,
name: obj.name, name: obj.name,
size: obj.size, size: obj.size,
} }
} catch (error:Dynamic) {
return loadsOld(data);
} }
} }
public static function dumps(config:Config, level:LevelConfig):String { public static function dumps(config:Config, level:LevelConfig):String {
var bricksStr = level.data.map(function(brick:BrickConfig) return Std.string(brick.index)).join(''); var bricksStr = level.data.join('');
return Yaml.render({ return Yaml.render({
data: bricksStr, data: bricksStr,
points: level.points, points: level.points,
@@ -58,7 +59,7 @@ class LevelUtil {
}, Renderer.options().setFlowLevel(1)); }, Renderer.options().setFlowLevel(1));
} }
public static function empty(size:GridSize, filler:BrickConfig):LevelConfig { public static function empty(size:GridSize, filler:BrickIndex):LevelConfig {
return { return {
data: [for (i in 0...size.width * size.height) filler], data: [for (i in 0...size.width * size.height) filler],
size: size, size: size,

View File

@@ -1,5 +1,4 @@
game: game:
levels: 36
friendlyFire: false friendlyFire: false
complete: complete:
- team: human - team: human

View File

@@ -1,5 +1,4 @@
game: game:
levels: 4
friendlyFire: true friendlyFire: true
complete: complete:
- team: alpha - team: alpha

View File

@@ -1,5 +1,4 @@
game: game:
levels: 23
friendlyFire: true friendlyFire: true
complete: complete:
- team: radiant - team: radiant