diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.hx b/src/client/haxe/ru/m/tankz/view/ClientView.hx index 1dd9209..614cd86 100644 --- a/src/client/haxe/ru/m/tankz/view/ClientView.hx +++ b/src/client/haxe/ru/m/tankz/view/ClientView.hx @@ -1,6 +1,5 @@ package ru.m.tankz.view; -import ru.m.tankz.game.IGame; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import haxework.resources.IResources; @@ -8,6 +7,7 @@ import haxework.view.ButtonView; import haxework.view.frame.FrameSwitcher; import haxework.view.LabelView; import haxework.view.VGroupView; +import ru.m.tankz.game.IGame; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.sound.SoundManager; import ru.m.tankz.view.popup.LoginPopup; diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.yaml b/src/client/haxe/ru/m/tankz/view/ClientView.yaml index fdda0f4..8e9622e 100755 --- a/src/client/haxe/ru/m/tankz/view/ClientView.yaml +++ b/src/client/haxe/ru/m/tankz/view/ClientView.yaml @@ -4,23 +4,15 @@ views: id: switcher geometry.size.stretch: true skinId: dark - views: - - id: start - $type: ru.m.tankz.view.StartFrame - - id: level - $type: ru.m.tankz.view.LevelFrame - - id: game - $type: ru.m.tankz.view.GameFrame - - id: result - $type: ru.m.tankz.view.ResultFrame - - id: settings - $type: ru.m.tankz.view.SettingsFrame - - id: record - $type: ru.m.tankz.view.RecordFrame - - id: room_list - $type: ru.m.tankz.view.network.RoomListFrame - - id: room - $type: ru.m.tankz.view.network.RoomFrame + factory: + _start_: {$class: ru.m.tankz.view.StartFrame} + _level_: {$class: ru.m.tankz.view.LevelFrame} + _game_: {$class: ru.m.tankz.view.GameFrame} + _result_: {$class: ru.m.tankz.view.ResultFrame} + _settings_: {$class: ru.m.tankz.view.SettingsFrame} + _record_: {$class: ru.m.tankz.view.RecordFrame} + _room_list_: {$class: ru.m.tankz.view.network.RoomListFrame} + _room_: {$class: ru.m.tankz.view.network.RoomFrame} - $type: haxework.view.HGroupView skinId: panel layout.margin: 10 diff --git a/src/client/haxe/ru/m/tankz/view/GameFrame.hx b/src/client/haxe/ru/m/tankz/view/GameFrame.hx index 77710b6..ed32cbc 100644 --- a/src/client/haxe/ru/m/tankz/view/GameFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/GameFrame.hx @@ -1,7 +1,7 @@ package ru.m.tankz.view; import haxework.view.frame.FrameSwitcher; -import haxework.view.VGroupView; +import haxework.view.frame.FrameView; import ru.m.control.DeviceType; import ru.m.control.IControlBus; import ru.m.tankz.game.GameEvent; @@ -18,7 +18,7 @@ import ru.m.tankz.Type; import ru.m.tankz.view.game.GameView; import ru.m.tankz.view.GamepadView; -@:template class GameFrame extends VGroupView implements GameListener { +@:template class GameFrame extends FrameView implements GameListener { public static inline var ID = "game"; private static inline var TAG = "GameFrame"; @@ -31,18 +31,21 @@ import ru.m.tankz.view.GamepadView; @:provide static var gameStorage:GameStorage; @:provide static var settings:SettingsStorage; - @:provide var gameInit:GameInit; //@:provide var result:Result; @:provide static var bus:IControlBus; private var game:IGame; private var recorder:GameRecord; + public function new() { + super(id); + } + public function init():Void { bus.connect(gamepad); } - public function onShow():Void { + override public function onShow(data:GameInit):Void { gamepad.visible = false; // ToDo: for (i in 0...1) { @@ -55,7 +58,7 @@ import ru.m.tankz.view.GamepadView; } } } - game = switch gameInit { + game = switch data { case LOCAL(start): new LocalGame(start); case NETWORK(network): new NetworkGame(network); case RECORD(record): new GamePlayer(record); @@ -87,7 +90,7 @@ import ru.m.tankz.view.GamepadView; //this.result = result; updateProgress(game, result.winner); stop(); - switcher.change(ResultFrame.ID); + switcher.change(ResultFrame.ID, result); case _: } } @@ -107,12 +110,12 @@ import ru.m.tankz.view.GamepadView; } } - public function onHide():Void { + override public function onHide():Void { stop(); soundManager.stopAll(); } public function close():Void { - switcher.change(LevelFrame.ID); + switcher.change(StartFrame.ID); } } diff --git a/src/client/haxe/ru/m/tankz/view/GameFrame.yaml b/src/client/haxe/ru/m/tankz/view/GameFrame.yaml index 66b6706..efefc7c 100644 --- a/src/client/haxe/ru/m/tankz/view/GameFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/GameFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx index 492e63d..781721f 100644 --- a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx @@ -3,60 +3,55 @@ package ru.m.tankz.view; import haxework.view.ButtonView; import haxework.view.DataView; import haxework.view.frame.FrameSwitcher; +import haxework.view.frame.FrameView; import haxework.view.LabelView; -import haxework.view.VGroupView; -import ru.m.tankz.bundle.ILevelBundle; +import ru.m.tankz.bundle.IConfigBundle; import ru.m.tankz.config.Config; import ru.m.tankz.game.GameInit; import ru.m.tankz.game.GameState; import ru.m.tankz.storage.GameStorage; -import ru.m.tankz.Type; import ru.m.tankz.view.popup.LevelPopup; -@:template class LevelFrame extends VGroupView { +@:template class LevelFrame extends FrameView { public static inline var ID = "level"; @:view var header:LabelView; @:view var levels:DataView; - @:provide var gameInit:GameInit; - @:provide var switcher:FrameSwitcher; - @:provide var levelBundle:ILevelBundle; - @:provide var storage:GameStorage; + @:provide static var switcher:FrameSwitcher; + @:provide static var storage:GameStorage; + @:provide static var configBundle:IConfigBundle; private var pack:LevelPack; private var levelPopup:LevelPopup; + private var config(get, never):Config; - public function onShow():Void { - var state = getState(); - header.text = state.type; - pack = levelBundle.get(new PackId(state.type)); + public function new() { + super(ID); + } + + private function get_config():Config { + return configBundle.get(pack.id.type); + } + + override public function onShow(data:LevelPack):Void { + header.text = data.id.type; + pack = data; levels.data = pack.data; } - private function getState():GameState { - return switch gameInit { - case LOCAL(start): start.state; - case _: null; - } - } - private function start(level:LevelConfig, preset:GamePreset, control:ControlPreset):Void { - switch gameInit { - case LOCAL(start): - start.state.presetId = preset.id; - start.state.controls = control.values; - start.level = level; - case _: - } - switcher.change(GameFrame.ID); + switcher.change(GameFrame.ID, LOCAL({ + state: new GameState(pack.id.type, preset.id, control.values), + level: level, + })); } private function levelViewFactory(index:Int, level:LevelConfig):ButtonView { var progress = storage.get(pack.id); var result = new ButtonView(); result.skinId = "button.level"; - var presetsLine = [for (p in getState().config.presets) progress.isPresetCompleted(level.id, p.id) ? '*' : '_'].join(''); + var presetsLine = [for (p in config.presets) progress.isPresetCompleted(level.id, p.id) ? '*' : '_'].join(''); result.text = '${level.id}\n${presetsLine}'; result.disabled = !progress.isLevelAvailable(level.id); return result; @@ -69,11 +64,10 @@ import ru.m.tankz.view.popup.LevelPopup; if (levelPopup == null) { levelPopup = new LevelPopup(); } - var state = getState(); levelPopup.setData( level, - state.config.presets, - state.config.controls, + config.presets, + config.controls, storage.get(pack.id) ); levelPopup.show().then(function(result) result != null ? start(level, result.preset, result.control) : {}); diff --git a/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml b/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml index 1b22dc1..c9b4ff6 100644 --- a/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx index ee673a6..679cb3c 100644 --- a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx @@ -1,13 +1,12 @@ package ru.m.tankz.view; import haxework.view.frame.FrameSwitcher; -import haxework.view.list.ListView; +import haxework.view.frame.FrameView; import haxework.view.list.VListView; -import haxework.view.VGroupView; import ru.m.tankz.game.record.GameRecord; import ru.m.tankz.storage.RecordStorage; -@:template class RecordFrame extends VGroupView { +@:template class RecordFrame extends FrameView { public static var ID(default, never):String = "record"; @:view var data:VListView; @@ -15,13 +14,13 @@ import ru.m.tankz.storage.RecordStorage; @:provide var recordStorage:RecordStorage; @:provide var switcher:FrameSwitcher; - public function onShow():Void { + public function new() { + super(ID); + } + + override public function onShow(_:Dynamic):Void { var data = Lambda.array(recordStorage); data.sort(function(a:GameRecordInfo, b:GameRecordInfo) return Std.int(b.date.getTime() - a.date.getTime())); this.data.data = data; } - - private function onRecordSelect(item:IListItemView):Void { - - } } diff --git a/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml b/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml index 9608a14..86cfb9b 100644 --- a/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container @@ -10,7 +13,6 @@ views: - id: data $type: haxework.view.list.VListView factory: $code:function() return new ru.m.tankz.view.common.RecordView() - +onItemSelect: $this:onRecordSelect geometry.margin.top: 20 geometry.size.stretch: true scroll: diff --git a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx index 93ea5b6..e1deb36 100644 --- a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx @@ -2,44 +2,53 @@ package ru.m.tankz.view; import haxework.view.DataView; import haxework.view.frame.FrameSwitcher; +import haxework.view.frame.FrameView; import haxework.view.LabelView; -import haxework.view.VGroupView; +import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameState; -import ru.m.tankz.game.IGame; import ru.m.tankz.view.common.LifeView; -@:template class ResultFrame extends VGroupView { +@:template class ResultFrame extends FrameView { public static var ID(default, never):String = "result"; @:view("result") var resultView:DataView; @:view("level") var levelLabel:LabelView; @:provide var frames:FrameSwitcher; - @:provide var game:IGame; - private function playerViewFactory(index:Int, player:PlayerState) { + private var state:GameState; + + public function new() { + super(ID); + } + + private function playerViewFactory(index:Int, player:PlayerState):LifeView { var view = new LifeView(); - // ToDo: - /*var playerConfig = state.config.getPlayer(player.id); + var playerConfig = state.config.getPlayer(player.id); var tankType = playerConfig.tanks[0].type; var tankConfig = state.config.getTank(tankType); view.tank = tankConfig == null ? 'ba' : tankConfig.skin; view.color = state.getPlayerColor(player.id); view.life = player.frags; - view.score = player.score;*/ + view.score = player.score; return view; } - public function onShow() { - //resultView.data = Lambda.array(state.players); - //levelLabel.text = 'Level ${state.levelId}'; // ToDo: level? + override public function onShow(data:Result):Void { + state = data.state; + resultView.data = Lambda.array(data.state.players); + var label = '${data.state.type} Level ${data.level.id}'; + if (data.level.name != null) { + label += '\n${data.level.name}'; + } + levelLabel.text = label; } - private function next() { + private function next():Void { //ToDo: next level? } - private function close() { - frames.change(LevelFrame.ID); + private function close():Void { + frames.change(StartFrame.ID); } } diff --git a/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml b/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml index 64a0b04..4eed01f 100644 --- a/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container @@ -6,6 +9,7 @@ views: - id: level $type: haxework.view.LabelView skinId: text.header + align: center - id: result $type: haxework.view.DataView factory: $this:playerViewFactory diff --git a/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx b/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx index 8d143de..d93670a 100644 --- a/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx @@ -1,7 +1,11 @@ package ru.m.tankz.view; -import haxework.view.VGroupView; +import haxework.view.frame.FrameView; -@:template class SettingsFrame extends VGroupView { +@:template class SettingsFrame extends FrameView { public static var ID(default, never):String = "settings"; + + public function new() { + super(ID); + } } diff --git a/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml b/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml index c771dae..661f7eb 100644 --- a/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/client/haxe/ru/m/tankz/view/StartFrame.hx b/src/client/haxe/ru/m/tankz/view/StartFrame.hx index 27d7cf6..972a02c 100644 --- a/src/client/haxe/ru/m/tankz/view/StartFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/StartFrame.hx @@ -1,36 +1,42 @@ package ru.m.tankz.view; import haxework.view.frame.FrameSwitcher; -import haxework.view.VGroupView; +import haxework.view.frame.FrameView; +import ru.m.tankz.bundle.ILevelBundle; import ru.m.tankz.game.GameInit; import ru.m.tankz.game.GameState; import ru.m.tankz.network.NetworkManager; -import ru.m.tankz.Type.GameType; +import ru.m.tankz.Type; import ru.m.tankz.view.network.RoomFrame; import ru.m.tankz.view.network.RoomListFrame; import ru.m.tankz.view.popup.FontPopup; import ru.m.tankz.view.popup.LoginPopup; -@:template class StartFrame extends VGroupView { +@:template class StartFrame extends FrameView { public static var ID(default, never):String = "start"; @:provide var gameInit:GameInit; @:provide var switcher:FrameSwitcher; @:provide var network:NetworkManager; + @:provide var levelBundle:ILevelBundle; private var fontPopup:FontPopup; + public function new() { + super(ID); + } + private function startGame(type:GameType):Void { gameInit = LOCAL({state: new GameState(type), level: null}); - switcher.change(LevelFrame.ID); + switcher.change(LevelFrame.ID, levelBundle.get(new PackId(type))); } private function startNetwork():Void { switch network.state { case ONLINE(user): if (network.room != null) { - switcher.change(RoomFrame.ID); + switcher.change(RoomFrame.ID, network.room); network.joinGame(network.room.game.id, true); } else { switcher.change(RoomListFrame.ID); diff --git a/src/client/haxe/ru/m/tankz/view/StartFrame.yaml b/src/client/haxe/ru/m/tankz/view/StartFrame.yaml index 1a65708..51113b0 100644 --- a/src/client/haxe/ru/m/tankz/view/StartFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/StartFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx index 1bc6988..df6115b 100644 --- a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx +++ b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx @@ -19,7 +19,6 @@ import ru.m.tankz.storage.RecordStorage; @:provide var recordStorage:RecordStorage; @:provide var switcher:FrameSwitcher; - @:provide var gameInit:GameInit; private function set_data(value:GameRecordInfo):GameRecordInfo { if (data != value) { @@ -34,8 +33,7 @@ import ru.m.tankz.storage.RecordStorage; private function play():Void { var record = recordStorage.read(data.id); - gameInit = RECORD(record); - switcher.change(GameFrame.ID); + switcher.change(GameFrame.ID, RECORD(record)); } private function delete():Void { diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx index e2aff67..4ad29aa 100644 --- a/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx @@ -2,15 +2,15 @@ package ru.m.tankz.view.network; import haxework.view.ButtonView; import haxework.view.frame.FrameSwitcher; +import haxework.view.frame.FrameView; import haxework.view.list.VListView; import haxework.view.TextView; -import haxework.view.VGroupView; import ru.m.tankz.game.GameInit; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.proto.room.RoomProto; import ru.m.tankz.proto.room.RoomSlotProto; -@:template class RoomFrame extends VGroupView { +@:template class RoomFrame extends FrameView { public static inline var ID = "room"; @@ -20,7 +20,10 @@ import ru.m.tankz.proto.room.RoomSlotProto; @:provide var switcher:FrameSwitcher; @:provide var network:NetworkManager; - @:provide var gameInit:GameInit; + + public function new() { + super(ID); + } private function refresh(room:RoomProto):Void { if (room != null) { @@ -28,20 +31,19 @@ import ru.m.tankz.proto.room.RoomSlotProto; info.text = '${room.game.type} #${room.game.level}'; slots.data = room.slots; if (room.game.started) { - gameInit = NETWORK(network); - switcher.change(GameFrame.ID); + switcher.change(GameFrame.ID, NETWORK(network)); } } else { Timer.delay(function() switcher.change(RoomListFrame.ID), 1); } } - public function onShow():Void { - refresh(network.room); + override public function onShow(data:RoomProto):Void { + refresh(data); network.roomSignal.connect(refresh); } - public function onHide():Void { + override public function onHide():Void { network.roomSignal.disconnect(refresh); } } diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml index b35a110..c04d463 100644 --- a/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx index 106399a..bddcb82 100644 --- a/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx @@ -1,13 +1,13 @@ package ru.m.tankz.view.network; import haxework.view.frame.FrameSwitcher; +import haxework.view.frame.FrameView; import haxework.view.list.VListView; -import haxework.view.VGroupView; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.proto.room.RoomProto; import ru.m.tankz.view.popup.CreateGamePopup; -@:template class RoomListFrame extends VGroupView { +@:template class RoomListFrame extends FrameView { public static inline var ID = "room_list"; @:view var games:VListView; @@ -15,13 +15,17 @@ import ru.m.tankz.view.popup.CreateGamePopup; @:provide var switcher:FrameSwitcher; @:provide var network:NetworkManager; - public function onShow():Void { + public function new() { + super(ID); + } + + override public function onShow(_:Dynamic):Void { network.listRoomSignal.connect(onRoomList); network.roomSignal.connect(onRoom); network.listGame(true); } - public function onHide():Void { + override public function onHide():Void { network.listRoomSignal.disconnect(onRoomList); network.roomSignal.disconnect(onRoom); network.listGame(false); @@ -41,7 +45,7 @@ import ru.m.tankz.view.popup.CreateGamePopup; private function onRoom(room:RoomProto):Void { if (room != null) { - switcher.change(RoomFrame.ID); + switcher.change(RoomFrame.ID, room); } } } diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml index 8e56d58..ec41009 100644 --- a/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml @@ -1,4 +1,7 @@ --- +geometry.size.stretch: true +layout: + $type: haxework.view.layout.VerticalLayout views: - $type: haxework.view.VGroupView skinId: container diff --git a/src/common/haxe/ru/m/tankz/game/GameEvent.hx b/src/common/haxe/ru/m/tankz/game/GameEvent.hx index 9b3f5eb..316cfda 100644 --- a/src/common/haxe/ru/m/tankz/game/GameEvent.hx +++ b/src/common/haxe/ru/m/tankz/game/GameEvent.hx @@ -14,6 +14,7 @@ typedef Start = { typedef Result = { var state:GameState; + var level:LevelConfig; var winner:TeamId; } diff --git a/src/common/haxe/ru/m/tankz/game/GameRunner.hx b/src/common/haxe/ru/m/tankz/game/GameRunner.hx index a40f636..15f6285 100644 --- a/src/common/haxe/ru/m/tankz/game/GameRunner.hx +++ b/src/common/haxe/ru/m/tankz/game/GameRunner.hx @@ -160,7 +160,7 @@ class GameRunner extends Game implements EngineListener { private function complete(winner:TeamId):Void { Timer.delay(function() { - gameEventSignal.emit(COMPLETE({state: state, winner: winner})); + gameEventSignal.emit(COMPLETE({state: state, level: level, winner: winner})); }, 3000); }