├── .gitignore ├── LICENSE ├── Nesbox.as3proj ├── README.md ├── bin ├── Nesbox.swf ├── gb.swf ├── gba.swf ├── nes.swf ├── sega.swf └── snes.swf ├── lib ├── as3corelib.swc ├── as3crypto.swc └── fzip.swc └── src ├── Analytics.as ├── EmulatorState.as ├── Focus.as ├── GameData.as ├── GamepadButton.as ├── ICoreModule.as ├── IGameDataHandler.as ├── IGamepadModule.as ├── JSProxy.as ├── Locale.as ├── Nesbox.as ├── Text.as ├── Tools.as ├── Variables.as ├── assets ├── en.json ├── facebook.png ├── favorite.png ├── fullscreen.png ├── gamepad.png ├── github.png ├── google.png ├── load.png ├── mute.png ├── save.png ├── setup.png ├── twitter.png ├── upload.png └── vkontakte.png ├── core ├── CorePlayerBase.as ├── CorePlayerContest.as ├── CorePlayerNetwork.as ├── CorePlayerOwnServer.as ├── CorePlayerSingle.as ├── CorePlayerWalk.as ├── ICoreHandler.as ├── ICorePlayer.as └── ICorePlayerHandler.as ├── mode ├── Base.as ├── Contest.as ├── Network.as ├── Own.as ├── OwnServer.as ├── Single.as └── Walk.as ├── model ├── Gamepad.as ├── ServerSettings.as └── Settings.as ├── network ├── INetworkSessionHandler.as ├── IOwnServerSessionHandler.as ├── NetworkSession.as └── OwnServerSession.as ├── server ├── Api.as └── IApiHandler.as └── ui ├── ActionAsset.as ├── Actions.as ├── ActionsMode.as ├── Button.as ├── FullscreenMessage.as ├── IActionsHandler.as ├── IBaseSetup.as ├── IOwnServerSetupHandler.as ├── ISetupHandler.as ├── ISignHandler.as ├── Keyboard.as ├── Message.as ├── OwnServerSetup.as ├── Setup.as ├── SetupBuilder.as ├── SetupTutorial.as └── TextInput.as /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin-debug/ 3 | 4 | # Other files and folders 5 | .settings/ 6 | 7 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 8 | # should NOT be excluded as they contain compiler settings and other important 9 | # information for Eclipse / Flash Builder. 10 | obj/ 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Vadim Grigoruk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Nesbox.as3proj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nesbox Emulator 2 | ======== 3 | 4 | NESbox is an emulator of NES, Super Nintendo, Sega Mega Drive and GameBoy video consoles, built on Adobe Flash technology and it can only be run directly in your browser's window. 5 | 6 | How to embed the emulator to your webpage? 7 | -------- 8 | 9 | Get all .swf files in /bin folder and upload to your server (for example to /flash folder). 10 | Add the following html to page where you want to place the emulator. 11 | 12 | ```html 13 | 14 |
15 |
16 |

To play this game, please, download the latest Flash player!

17 |
18 | 19 | Get Adobe Flash player 20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 63 | 64 | ``` 65 | 66 | Supported systems: nes, snes, sega, gb, gba 67 | 68 | License 69 | ---- 70 | 71 | MIT 72 | -------------------------------------------------------------------------------- /bin/Nesbox.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/Nesbox.swf -------------------------------------------------------------------------------- /bin/gb.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/gb.swf -------------------------------------------------------------------------------- /bin/gba.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/gba.swf -------------------------------------------------------------------------------- /bin/nes.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/nes.swf -------------------------------------------------------------------------------- /bin/sega.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/sega.swf -------------------------------------------------------------------------------- /bin/snes.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/bin/snes.swf -------------------------------------------------------------------------------- /lib/as3corelib.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/lib/as3corelib.swc -------------------------------------------------------------------------------- /lib/as3crypto.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/lib/as3crypto.swc -------------------------------------------------------------------------------- /lib/fzip.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/lib/fzip.swc -------------------------------------------------------------------------------- /src/Analytics.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.external.ExternalInterface; 4 | 5 | public final class Analytics 6 | { 7 | private static function trackEvent(action:String, label:String):void 8 | { 9 | 10 | } 11 | 12 | private static function trackStartEvent(label:String):void 13 | { 14 | trackEvent('start', label); 15 | } 16 | 17 | public static function trackStartSingleEvent():void 18 | { 19 | trackStartEvent('single'); 20 | } 21 | 22 | public static function trackOwnRomEvent():void 23 | { 24 | trackStartEvent('own'); 25 | } 26 | 27 | public static function trackStartSocialSingleEvent():void 28 | { 29 | trackStartEvent('social-single'); 30 | } 31 | 32 | public static function trackStartSocialNetworkEvent():void 33 | { 34 | trackStartEvent('social-network'); 35 | } 36 | 37 | public static function trackStartNetworkEvent():void 38 | { 39 | trackStartEvent('network'); 40 | } 41 | 42 | public static function trackOwnServerEvent():void 43 | { 44 | trackStartEvent('own-server'); 45 | } 46 | 47 | public static function trackStartWalkEvent():void 48 | { 49 | trackStartEvent('walk'); 50 | } 51 | 52 | public static function trackStartContestEvent():void 53 | { 54 | trackStartEvent('contest'); 55 | } 56 | 57 | private static function trackActionEvent(label:String):void 58 | { 59 | trackEvent('action', label); 60 | } 61 | 62 | public static function trackActionMuteEvent():void 63 | { 64 | trackActionEvent('mute'); 65 | } 66 | 67 | public static function trackActionFullscreenEvent():void 68 | { 69 | trackActionEvent('fullscreen'); 70 | } 71 | 72 | public static function trackActionLoadEvent():void 73 | { 74 | trackActionEvent('load'); 75 | } 76 | 77 | public static function trackActionSaveEvent():void 78 | { 79 | trackActionEvent('save'); 80 | } 81 | 82 | public static function trackActionSetupEvent():void 83 | { 84 | trackActionEvent('setup'); 85 | } 86 | 87 | public static function trackActionUploadEvent():void 88 | { 89 | trackActionEvent('upload'); 90 | } 91 | 92 | public static function trackActionGamepadEvent():void 93 | { 94 | trackActionEvent('gamepad'); 95 | } 96 | 97 | public static function trackActionFavoriteEvent():void 98 | { 99 | trackActionEvent('favorite'); 100 | } 101 | 102 | private static function trackShareEvent(label:String):void 103 | { 104 | trackEvent('share', label); 105 | } 106 | 107 | public static function trackShareFacebookEvent():void 108 | { 109 | trackShareEvent('facebook'); 110 | } 111 | 112 | public static function trackShareGoogleEvent():void 113 | { 114 | trackShareEvent('google'); 115 | } 116 | 117 | public static function trackShareTwitterEvent():void 118 | { 119 | trackShareEvent('twitter'); 120 | } 121 | 122 | public static function trackShareVkontakteEvent():void 123 | { 124 | trackShareEvent('vkontakte'); 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /src/EmulatorState.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | public final class EmulatorState 4 | { 5 | public static const Playing:EmulatorState = new EmulatorState; 6 | public static const Loading:EmulatorState = new EmulatorState; 7 | public static const Saving:EmulatorState = new EmulatorState; 8 | public static const Uploadig:EmulatorState = new EmulatorState; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Focus.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Stage; 4 | import flash.events.Event; 5 | 6 | public class Focus 7 | { 8 | public static var activated:Boolean = false; 9 | 10 | public static function init(stage:Stage):void 11 | { 12 | stage.addEventListener(Event.ACTIVATE, function():void 13 | { 14 | activated = true; 15 | }); 16 | 17 | stage.addEventListener(Event.DEACTIVATE, function():void 18 | { 19 | activated = false; 20 | }); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/GameData.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import deng.fzip.FZip; 4 | import deng.fzip.FZipFile; 5 | import flash.display.Loader; 6 | import flash.events.Event; 7 | import flash.events.ProgressEvent; 8 | import flash.net.URLLoader; 9 | import flash.net.URLLoaderDataFormat; 10 | import flash.net.URLRequest; 11 | import flash.utils.ByteArray; 12 | 13 | public class GameData 14 | { 15 | public var domain:String; 16 | public var rom:String; 17 | public var game:String; 18 | public var action:String; 19 | public var value:String; 20 | public var data:ByteArray; 21 | public var ntsc:Boolean; 22 | public var region:String; 23 | public var locale:String; 24 | public var core:ICoreModule; 25 | public var module:String; 26 | public var system:String; 27 | public var baseUrl:String; 28 | public var url:String; 29 | 30 | private var handler:IGameDataHandler; 31 | 32 | public static const One:String = 'one'; 33 | public static const Arena:String = 'arena'; 34 | public static const Walk:String = 'walk'; 35 | public static const Save:String = 'save'; 36 | public static const Own:String = 'own'; 37 | public static const Room:String = 'room'; 38 | 39 | private static const ZipExt:String = '.zip'; 40 | 41 | public function GameData(handler:IGameDataHandler, loaderUrl:String) 42 | { 43 | this.handler = handler; 44 | 45 | this.ntsc = true; 46 | this.region = 'u'; 47 | 48 | var swfUrl:String = loaderUrl.substring(0, loaderUrl.indexOf('.swf')); 49 | this.baseUrl = swfUrl.split('/').slice(0,-1).join('/'); 50 | } 51 | 52 | public function loadParams(parameters:Object):void 53 | { 54 | this.system = parameters['system']; 55 | this.game = parameters['game']; 56 | this.rom = parameters['rom']; 57 | this.url = parameters['url']; 58 | this.locale = parameters['locale'] || 'en'; 59 | this.action = parameters['action'] || Own; 60 | 61 | this.module = this.system + '.swf'; 62 | } 63 | 64 | private function parseLocale(json:String):void 65 | { 66 | var locale:Locale = Locale.instance; 67 | var data:Object = JSON.parse(json); 68 | 69 | for(var key:String in data) 70 | { 71 | if(locale.hasOwnProperty(key)) 72 | { 73 | locale[key] = data[key]; 74 | } 75 | } 76 | } 77 | 78 | public function loadLocale():void 79 | { 80 | if (this.locale == 'en') 81 | { 82 | [Embed(source='/assets/en.json', mimeType="application/octet-stream")] 83 | const LocaleJson:Class; 84 | 85 | parseLocale(new LocaleJson()); 86 | 87 | handler.onLoadLocale(); 88 | } 89 | else 90 | { 91 | var localeLoader:URLLoader = new URLLoader(); 92 | localeLoader.dataFormat = URLLoaderDataFormat.TEXT; 93 | 94 | localeLoader.addEventListener(Event.COMPLETE, function():void 95 | { 96 | parseLocale(localeLoader.data); 97 | 98 | handler.onLoadLocale(); 99 | }); 100 | 101 | localeLoader.load(new URLRequest(this.locale + '.json')); 102 | } 103 | } 104 | 105 | public function parseOwnRomName(name:String):void 106 | { 107 | if (name.indexOf(ZipExt) != -1) 108 | { 109 | var zip:FZip = new FZip(); 110 | 111 | zip.addEventListener(Event.COMPLETE, function():void 112 | { 113 | var romFile:FZipFile = zip.getFileAt(0); 114 | 115 | data = romFile.content; 116 | 117 | parseOwnRomName(romFile.filename); 118 | }); 119 | 120 | zip.loadBytes(data); 121 | 122 | return; 123 | } 124 | 125 | const Modules:Object = 126 | { 127 | 'nes':'nes.swf', 128 | 'smc':'snes.swf', 129 | 'gen':'sega.swf', 130 | 'gb':'gb.swf', 131 | 'gbc':'gb.swf', 132 | 'gba':'gba.swf' 133 | }; 134 | 135 | const Regions:Array = ['E', 'U', 'J']; 136 | 137 | for(var ext:String in Modules) 138 | { 139 | var length:int = (name.length - ext.length - 1); 140 | if(name.indexOf('.' + ext) == length) 141 | { 142 | this.rom = name.substr(0, length); 143 | this.module = Modules[ext]; 144 | this.system = module.split('.swf')[0]; 145 | break; 146 | } 147 | } 148 | 149 | for each(var region:String in Regions) 150 | { 151 | if(name.indexOf('('+region+')') != -1) 152 | { 153 | this.ntsc = region != 'E'; 154 | this.region = region.toLowerCase(); 155 | break; 156 | } 157 | } 158 | } 159 | 160 | public function init():void 161 | { 162 | var self:GameData = this; 163 | 164 | var request:URLRequest = new URLRequest([self.baseUrl, self.module].join('/')); 165 | var moduleLoader:Loader = new Loader; 166 | 167 | moduleLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void 168 | { 169 | self.core = moduleLoader.content as ICoreModule; 170 | 171 | Variables.Width = self.core.getWidth(); 172 | Variables.Height = self.core.getHeight(); 173 | 174 | if (self.action == Own) 175 | { 176 | if (self.url == null) 177 | handler.onLoadRom(); 178 | else 179 | loadRom(); 180 | } 181 | 182 | }); 183 | 184 | moduleLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, function(event:ProgressEvent):void 185 | { 186 | handler.onInfoShow('

' + 187 | Locale.instance.loading_emulator + 188 | ' ' + int(event.bytesLoaded * 100 / event.bytesTotal) + '%

'); 189 | }); 190 | 191 | moduleLoader.load(request); 192 | } 193 | 194 | private function loadRom():void 195 | { 196 | rom = rom || url.split('/').pop(); 197 | 198 | var romLoader:URLLoader = new URLLoader(); 199 | romLoader.dataFormat = URLLoaderDataFormat.BINARY; 200 | 201 | romLoader.addEventListener(Event.COMPLETE, function():void 202 | { 203 | if (rom.indexOf(ZipExt) != -1) 204 | { 205 | var zip:FZip = new FZip(); 206 | 207 | zip.addEventListener(Event.COMPLETE, function():void 208 | { 209 | var romFile:FZipFile = zip.getFileAt(0); 210 | 211 | data = romFile.content; 212 | }); 213 | 214 | zip.loadBytes(romLoader.data); 215 | } 216 | else 217 | { 218 | data = romLoader.data; 219 | } 220 | 221 | handler.onLoadRom(); 222 | }); 223 | 224 | romLoader.addEventListener(ProgressEvent.PROGRESS, function(event:ProgressEvent):void 225 | { 226 | handler.onInfoShow('

' + 227 | Locale.instance.loading_game + 228 | ' ' + int(event.bytesLoaded * 100 / event.bytesTotal) + '%

'); 229 | }); 230 | 231 | romLoader.load(new URLRequest(url)); 232 | } 233 | } 234 | } -------------------------------------------------------------------------------- /src/GamepadButton.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Bitmap; 4 | 5 | public class GamepadButton 6 | { 7 | public var bitmap:Bitmap; 8 | public var name:String; 9 | public var x:int; 10 | public var y:int; 11 | 12 | public function GamepadButton() 13 | { 14 | 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ICoreModule.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.BitmapData; 4 | import flash.utils.ByteArray; 5 | 6 | public interface ICoreModule extends IGamepadModule 7 | { 8 | function init(ntsc:Boolean, rom:ByteArray, region:String):void; 9 | function tick(input:uint, data:BitmapData):void; 10 | function sound(data:ByteArray):void; 11 | function save():ByteArray; 12 | function load(data:ByteArray):void; 13 | 14 | function set muted(value:Boolean):void; 15 | function get muted():Boolean; 16 | 17 | function getWidth():int; 18 | function getHeight():int; 19 | } 20 | } -------------------------------------------------------------------------------- /src/IGameDataHandler.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | public interface IGameDataHandler 4 | { 5 | function onInfoShow(value:String):void; 6 | function onLoadRom():void; 7 | function onLoadLocale():void; 8 | } 9 | } -------------------------------------------------------------------------------- /src/IGamepadModule.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Bitmap; 4 | 5 | public interface IGamepadModule 6 | { 7 | function getGamepadKeysNames():Array; 8 | function getGamepadImage():Bitmap; 9 | function getGamepadButton(name:String):GamepadButton; 10 | function getGamepadDefaultKeys():Array; 11 | function getSettingsUid():String; 12 | } 13 | } -------------------------------------------------------------------------------- /src/JSProxy.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.external.ExternalInterface; 4 | 5 | public class JSProxy 6 | { 7 | public static function windowOpen(url:String, title:String, width:int = 800, height:int = 400):void 8 | { 9 | if(ExternalInterface.available) 10 | { 11 | ExternalInterface.call('function(){window.open("' + url + 12 | '", "' + title + '", "width=' + width + ',height=' + 300 + '");}'); 13 | } 14 | } 15 | 16 | public static function showSignInModal():void 17 | { 18 | if(ExternalInterface.available) 19 | { 20 | ExternalInterface.call('function(){$("#signin").modal("show");}'); 21 | } 22 | } 23 | 24 | public static function showSignUpModal():void 25 | { 26 | if(ExternalInterface.available) 27 | { 28 | ExternalInterface.call('function(){$("#signup").modal("show");}'); 29 | } 30 | } 31 | 32 | public static function onNetworkInit(peer:String = null):void 33 | { 34 | if(ExternalInterface.available) 35 | { 36 | ExternalInterface.call(peer && peer.length == 64 37 | ? 'function(){Client.onNetworkInit("'+peer+'");}' 38 | : 'function(){Client.onNetworkInit();}'); 39 | } 40 | } 41 | 42 | public static function addCallback(name:String, callback:Function):void 43 | { 44 | if(ExternalInterface.available) 45 | { 46 | ExternalInterface.addCallback(name, callback); 47 | } 48 | } 49 | 50 | public static function showDefaultKeyboard():void 51 | { 52 | if(ExternalInterface.available) 53 | { 54 | ExternalInterface.call('function(){Client.showDefaultKeyboard();}'); 55 | } 56 | } 57 | 58 | public static function resizeOwnEmulator(width:int, height:int):void 59 | { 60 | if(ExternalInterface.available) 61 | { 62 | ExternalInterface.call('function(){resizeOwnEmulator("'+width+'px", "'+height+'px");}'); 63 | } 64 | } 65 | 66 | public static function initSigningCallback(callback:Function):void 67 | { 68 | if(ExternalInterface.available) 69 | { 70 | ExternalInterface.addCallback('onUserSigned', function(signed:Boolean):void 71 | { 72 | callback(signed); 73 | }); 74 | } 75 | } 76 | 77 | public static function log(value:String):void 78 | { 79 | trace(value); 80 | 81 | if(ExternalInterface.available) 82 | { 83 | ExternalInterface.call('function(){console.log("'+value+'");}'); 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/Locale.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | public class Locale 4 | { 5 | private static var instanceValue:Locale; 6 | 7 | public function Locale() 8 | { 9 | 10 | } 11 | 12 | public static function get instance():Locale 13 | { 14 | if(!instanceValue) 15 | { 16 | instanceValue = new Locale; 17 | instanceValue.init(); 18 | } 19 | 20 | return instanceValue; 21 | } 22 | 23 | private function init():void 24 | { 25 | 26 | } 27 | 28 | public var click_here_to_play_the_game:String; 29 | public var error_occured:String; 30 | public var close:String; 31 | public var cancel:String; 32 | public var click_allow_button:String; 33 | public var now_connect_gamepad:String; 34 | public var configure:String; 35 | public var or:String; 36 | public var press:String; 37 | public var button:String; 38 | public var connecting_please_wait:String; 39 | public var if_you_want_to_use_gamepad:String; 40 | public var user_name:String; 41 | public var email:String; 42 | public var password:String; 43 | public var forgot_password:String; 44 | public var sign_in:String; 45 | public var sign_up:String; 46 | public var to_save_load_game_you_need:String; 47 | public var keyboard_setup:String; 48 | public var select_joystick_button:String; 49 | public var load_defaults:String; 50 | public var save:String; 51 | public var select_mode:String; 52 | public var one_player:String; 53 | public var two_players_via_internet:String; 54 | public var game_walkthrough:String; 55 | public var your_own_server:String; 56 | public var supported_rom_formats:String; 57 | public var click_here_to_load_your_own_rom:String; 58 | public var loading_module:String; 59 | public var loading_game:String; 60 | public var loading_emulator:String; 61 | public var uploading_walkthrough:String; 62 | public var please_wait:String; 63 | public var you_already_have_saved_walkthrough:String; 64 | public var yes:String; 65 | public var no:String; 66 | public var you_need_to_be_signed_in_to_upload_walk:String; 67 | public var waiting_for_connection:String; 68 | public var if_you_cannot_connect:String; 69 | public var connecting_to_server:String; 70 | public var new_send_copied_url:String; 71 | public var also_you_can_find_partner:String; 72 | public var public_chat:String; 73 | public var remote_url:String; 74 | public var click_here_to_copy_url_to_clipboard:String; 75 | public var then_send_it_to_friend:String; 76 | public var connected_to_server:String; 77 | public var connection_error:String; 78 | public var testing_connection:String; 79 | public var ping_is:String; 80 | public var the_game_will_be_uncomfortable:String; 81 | public var saving_game:String; 82 | public var you_have_saved_state:String; 83 | public var do_you_want_to_load_state:String; 84 | public var you_need_to_be_signed_in_to_save:String; 85 | public var loading_walkthrough:String; 86 | 87 | public var gamepad_app_info:String; 88 | public var gamepad_app_downloaded:String; 89 | public var click_here_to_save_it:String; 90 | 91 | public var hint_pause:String; 92 | public var hint_setup:String; 93 | public var hint_mute:String; 94 | public var hint_load:String; 95 | public var hint_save:String; 96 | public var hint_fullscreen:String; 97 | public var hint_share:String; 98 | public var hint_upload:String; 99 | public var hint_gamepad:String; 100 | public var hint_favorite:String; 101 | public var server_setup:String; 102 | public var server_port:String; 103 | public var server_frameskip:String; 104 | public var connect:String; 105 | public var server_connection_error:String; 106 | public var make_sure_entered_correct_ip:String; 107 | public var try_again:String; 108 | public var you_are_connected:String; 109 | public var and_send_to_friend:String; 110 | public var remote_url_is:String; 111 | public var connection_has_closed:String; 112 | 113 | public var please_read:String; 114 | public var how_start_own_server:String; 115 | 116 | public function sprintf(buffer:String, ...args):String 117 | { 118 | for(var index:int = 0; index < args.length; index++) 119 | buffer = buffer.split('%'+(index+1)+'%').join(args[index]); 120 | 121 | return buffer; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Nesbox.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.DisplayObject; 4 | import flash.display.Sprite; 5 | import flash.display.StageAlign; 6 | import flash.display.StageScaleMode; 7 | import flash.events.ContextMenuEvent; 8 | import flash.events.Event; 9 | import flash.net.FileFilter; 10 | import flash.net.FileReference; 11 | import flash.net.navigateToURL; 12 | import flash.net.URLRequest; 13 | import flash.ui.ContextMenu; 14 | import flash.ui.ContextMenuItem; 15 | 16 | import mode.Contest; 17 | import mode.Network; 18 | import mode.Own; 19 | import mode.OwnServer; 20 | import mode.Single; 21 | import mode.Walk; 22 | 23 | import ui.Message; 24 | 25 | [SWF(width='640', height='480', backgroundColor='0x000000')] 26 | 27 | public class Nesbox extends Sprite implements IGameDataHandler 28 | { 29 | private var gameData:GameData; 30 | private var info:Message; 31 | private var message:Message; 32 | private var emulator:DisplayObject; 33 | private var locale:Locale; 34 | 35 | public function Nesbox() 36 | { 37 | if(stage) 38 | { 39 | init(); 40 | } 41 | else 42 | { 43 | addEventListener(Event.ADDED_TO_STAGE, function():void 44 | { 45 | init(); 46 | }); 47 | } 48 | } 49 | 50 | public function setSize(width:int, height:int):void 51 | { 52 | Variables.Width = width; 53 | Variables.Height = height; 54 | } 55 | 56 | public function onInfoShow(value:String):void 57 | { 58 | info.show(value); 59 | } 60 | 61 | private function createContextMenu():void 62 | { 63 | var customMenu:ContextMenu = new ContextMenu(); 64 | customMenu.hideBuiltInItems(); 65 | 66 | var emulatorItem:ContextMenuItem = new ContextMenuItem(locale.hint_share); 67 | emulatorItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function():void 68 | { 69 | Tools.gotoNesboxPage(); 70 | }); 71 | 72 | customMenu.customItems.push(emulatorItem); 73 | 74 | contextMenu = customMenu; 75 | 76 | } 77 | 78 | private function init():void 79 | { 80 | setSize(stage.stageWidth / 2, stage.stageHeight / 2); 81 | 82 | scaleX = scaleY = 2; 83 | 84 | Focus.init(stage); 85 | 86 | stage.scaleMode = StageScaleMode.NO_SCALE; 87 | stage.align = StageAlign.TOP_LEFT; 88 | 89 | locale = Locale.instance; 90 | gameData = new GameData(this, stage.loaderInfo.loaderURL); 91 | 92 | gameData.loadParams(stage.loaderInfo.parameters); 93 | 94 | addChild(info = new Message); 95 | 96 | gameData.loadLocale(); 97 | } 98 | 99 | public function onLoadLocale():void 100 | { 101 | createContextMenu(); 102 | 103 | if (gameData.action == GameData.Own 104 | && gameData.url == null) 105 | { 106 | initOwnRomMode(); 107 | } 108 | else 109 | gameData.init(); 110 | } 111 | 112 | public function onLoadRom():void 113 | { 114 | removeChild(info); 115 | 116 | if(gameData.action) 117 | { 118 | switch(gameData.action) 119 | { 120 | case GameData.One: 121 | startSingleMode(); 122 | break; 123 | case GameData.Arena: 124 | startNetworkMode(); 125 | break; 126 | case GameData.Save: 127 | startSingleMode(); 128 | break; 129 | case GameData.Walk: 130 | gameData.value ? startWalkMode() : startContestMode(); 131 | break; 132 | case GameData.Own: 133 | startOwnRomMode(); 134 | break; 135 | case GameData.Room: 136 | startOwnServerMode(); 137 | break; 138 | default: 139 | selectMode(); 140 | } 141 | } 142 | else 143 | { 144 | selectMode(); 145 | } 146 | } 147 | 148 | private function selectMode():void 149 | { 150 | message = new Message(); 151 | addChild(message); 152 | 153 | var callbacks:Object = 154 | { 155 | single:startSingleMode, 156 | network:startNetworkMode, 157 | contest:startContestMode, 158 | own:startOwnServerMode 159 | }; 160 | 161 | message.show('

' + locale.select_mode.toUpperCase() + ':
' + 162 | '

1 - '+locale.one_player+'' + 163 | '

2 - '+locale.game_walkthrough+''+ 164 | '

3 - '+locale.two_players_via_internet+'' + 165 | '

4 - '+locale.your_own_server+' (beta)' + 166 | '

' 167 | , callbacks); 168 | } 169 | 170 | private function startSingleMode():void 171 | { 172 | Analytics.trackStartSingleEvent(); 173 | addEmulator(new Single(gameData)); 174 | } 175 | 176 | private function startOwnRomMode():void 177 | { 178 | Analytics.trackOwnRomEvent(); 179 | JSProxy.resizeOwnEmulator(Variables.Width*2, Variables.Height*2); 180 | addEmulator(new Own(gameData)); 181 | } 182 | 183 | private function initOwnRomMode():void 184 | { 185 | var callbacks:Object = 186 | { 187 | own:function():void 188 | { 189 | Analytics.trackOwnRomEvent(); 190 | 191 | var romsFilter:FileFilter = new FileFilter("Supported roms", "*.nes;*.smc;*.gen;*.gb;*.gbc;*.gba;*.zip"); 192 | var ref:FileReference = new FileReference(); 193 | ref.addEventListener(Event.SELECT, function():void 194 | { 195 | ref.load(); 196 | }); 197 | ref.addEventListener(Event.COMPLETE, function():void 198 | { 199 | gameData.data = ref.data; 200 | 201 | gameData.parseOwnRomName(ref.name); 202 | 203 | gameData.init(); 204 | }); 205 | ref.browse([romsFilter]); 206 | } 207 | }; 208 | 209 | info.show('

'+locale.supported_rom_formats+':

NES (*.nes), SNES (*.smc), SEGA (*.gen),
GAMEBOY/COLOR/ADVANCE (*.gb, *.gbc, *.gba)


' + 210 | ''+ 211 | locale.click_here_to_load_your_own_rom + 212 | '...

', callbacks); 213 | } 214 | 215 | private function startNetworkMode():void 216 | { 217 | Analytics.trackStartNetworkEvent(); 218 | addEmulator(new Network(gameData)); 219 | } 220 | 221 | private function startOwnServerMode():void 222 | { 223 | Analytics.trackOwnServerEvent(); 224 | addEmulator(new OwnServer(gameData)); 225 | } 226 | 227 | private function startWalkMode():void 228 | { 229 | Analytics.trackStartWalkEvent(); 230 | addEmulator(new Walk(gameData)); 231 | } 232 | 233 | private function startContestMode():void 234 | { 235 | Analytics.trackStartContestEvent(); 236 | addEmulator(new Contest(gameData)); 237 | } 238 | 239 | private function addEmulator(emulator:DisplayObject):void 240 | { 241 | if(message && contains(message)) 242 | { 243 | this.removeChild(message); 244 | message = null; 245 | } 246 | 247 | this.emulator = emulator; 248 | addChild(emulator); 249 | } 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/Text.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.text.StyleSheet; 4 | import flash.text.TextField; 5 | import flash.text.TextFieldAutoSize; 6 | 7 | public class Text extends TextField 8 | { 9 | public function Text(color:String = '#ffffff') 10 | { 11 | selectable = false; 12 | autoSize = TextFieldAutoSize.LEFT; 13 | 14 | var style:StyleSheet = new StyleSheet(); 15 | 16 | style.setStyle('p', 17 | { 18 | color: color, 19 | fontFamily: 'verdana', 20 | fontSize: 8 21 | }); 22 | 23 | style.setStyle('a', 24 | { 25 | textDecoration : 'underline' 26 | }); 27 | 28 | styleSheet = style; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Tools.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.events.Event; 4 | import flash.events.IOErrorEvent; 5 | import flash.external.ExternalInterface; 6 | import flash.net.navigateToURL; 7 | import flash.net.URLLoader; 8 | import flash.net.URLLoaderDataFormat; 9 | import flash.net.URLRequest; 10 | import flash.system.Capabilities; 11 | import flash.system.System; 12 | 13 | public final class Tools 14 | { 15 | public static function get currentUrl():String 16 | { 17 | if (ExternalInterface.available) 18 | { 19 | return ExternalInterface.call('function(){return window.location.href}'); 20 | } 21 | 22 | return null; 23 | } 24 | 25 | public static function isInteractiveFullscreenSupported():Boolean 26 | { 27 | var parts:Array = Capabilities.version.split(' ')[1].split(','); 28 | var major:int = parts[0]; 29 | var minor:int = parts[1]; 30 | 31 | return (major > 11) || (major == 11 && minor > 2); 32 | } 33 | 34 | public static function shortLink(url:String, done:Function):void 35 | { 36 | var bitly:String = 'http://api.bitly.com/v3/shorten?login=nesbox&apiKey=R_6933c0180c526715fb29e12176373e46&format=json&longUrl=' + escape(url); 37 | var loader:URLLoader = new URLLoader; 38 | 39 | loader.dataFormat = URLLoaderDataFormat.TEXT; 40 | loader.addEventListener(Event.COMPLETE, function(event:Event):void 41 | { 42 | var result:Object = JSON.parse(loader.data); 43 | 44 | if(result.status_code == 200 45 | && result.data 46 | && result.data.url) 47 | { 48 | done(result.data.url); 49 | return; 50 | } 51 | 52 | done(null); 53 | }); 54 | 55 | loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent):void 56 | { 57 | done(null); 58 | }); 59 | 60 | loader.load(new URLRequest(bitly)); 61 | } 62 | 63 | public static function gotoNesboxPage():void 64 | { 65 | navigateToURL(new URLRequest('http://nesbox.github.io/emulator/'), '_blank'); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/Variables.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.geom.Rectangle; 4 | 5 | public final class Variables 6 | { 7 | public static const NtscFramerate:int = 60; 8 | public static const PalFramerate:int = 50; 9 | 10 | public static var Width:int = 320; 11 | public static var Height:int = 240; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_title" : "NESbox - play NES, SNES, SEGA games online!", 3 | "homepage_hero_description" : "NESbox is an emulator of NES, Super Nintendo, Sega Mega Drive video consoles, built on Adobe Flash technology and it can only be run directly in your browser's window.", 4 | "homepage_hero_title" : "What is %1%?", 5 | "homepage_learn_more" : "Learn more", 6 | "home" : "Home", 7 | "about_us" : "About Us", 8 | "search" : "Search", 9 | "games" : "Games", 10 | "roms" : "Roms", 11 | "alphabet" : "Alphabet", 12 | "players" : "Players", 13 | "walkthroughs" : "Walkthroughs", 14 | "play" : "Play", 15 | "view_details" : "View details", 16 | "support" : "support", 17 | "close_the_chat" : "Close the chat", 18 | "not_found_error" : "Sorry, that page doesn't exist", 19 | "popular_games" : "Popular games", 20 | "name" : "Name", 21 | "country" : "Country", 22 | "translation" : "Translation", 23 | "information" : "Information", 24 | "screenshots" : "Screenshots", 25 | "load_game" : "Load saved state", 26 | "user_name" : "Player name", 27 | "password" : "Password", 28 | "heads_up" : "Heads Up", 29 | "close" : "close", 30 | "help_us_to_translate" : "Help Us translate the website", 31 | "click_here_to_sign_in" : "Click here to Sign In", 32 | "you_signed_in_as" : "Signed in as", 33 | "sign_out" : "Sign Out", 34 | "forgot_password" : "Forgot password", 35 | "password_recovery_label" : "Enter your email address", 36 | "password_recovery_tip_title" : "We've sent instructions to your email address.", 37 | "password_recovery_tip" : "If you didn't receive an email within a minute or two, check your spam and junk filters.", 38 | "submit" : "Submit", 39 | "about_games_info" : "We have a collection of %1% games and %2% roms.", 40 | "about_how_to_use" : "How to use", 41 | "about_to_start_game" : "To start a game just click on the 'Play' button or choose a rom on the game details page.", 42 | "about_after_start" : "You can select the game type after the emulator loads", 43 | "about_gamepad_config" : "You can customise the joystick keys to suit your preferences or play with the default keys", 44 | "about_one_player_info" : "You play alone and you have access to the following menu items", 45 | "about_show_joystick_setup" : "show gamepad setup dialog", 46 | "about_mute" : "mute on/off", 47 | "about_load" : "load saved game", 48 | "about_save" : "save current game", 49 | "about_two_players_info" : "After connecting to the server we'll create a link that you will to send to a second player. The P2P game will start after the link has been opened and the game has loaded. Here you have only two menu items", 50 | "about_walkthrough_info" : "You play alone and you cannot save your progress. You can upload your walkthrough to our server and participate in the ranking. You have access to the following menu items", 51 | "about_upload" : "upload game walkthrough to our server", 52 | "about_signup_signin" : "Sign Up or Sign In", 53 | "about_signup_signin_info" : "Registration is necessary to save the state of games on our server and load it later. You need to enter login by providing your email address or username and your password. You can view all your saved games in your profile. Click in the upper right corner of the screen.", 54 | "about_subscribe" : "If you want to be in touch, follow Us on", 55 | "about_author" : "Author of the website", 56 | "about_built" : "Website built with", 57 | "saved_games" : "Saved games", 58 | "popular_walkthroughs" : "Popular walkthorughs", 59 | "player" : "Player", 60 | "time" : "Time", 61 | "top_games" : "Top games", 62 | "top_players" : "Top players", 63 | "top_walkthroughs" : "Top walkthroughs", 64 | "view_all" : "Show all", 65 | "view_all_games" : "Show all games", 66 | "menu" : "Menu", 67 | "choose_a_video_game_console" : "Choose a video game console", 68 | "play_together" : "Play Together", 69 | "public_chat" : "Public Chat", 70 | "public_chat_tip" : "Here, you can agree on a network game", 71 | "powered_by" : "Powered by", 72 | "online_users" : "Online users", 73 | "one_player" : "One Player", 74 | "two_players_via_internet" : "Two Players via Internet", 75 | "game_walkthrough" : "Game Walkthrough", 76 | "your_own_server" : "Your own server", 77 | "public_chat_faq_1" : "When you are playing through the network, the further away you are from the second player, the more likely the game is to slow down. Therefore, if you think this can affect your experience, try to play with someone as geografically close to you as possible, such as a neighbour", 78 | "public_chat_faq_2" : "To start a network game, you need to select 'Two Players via Internet', copy the link and send it to the second player, or put it in the 'Public Chat' and agree to play", 79 | "public_chat_faq_3" : "If you see the message 'Waiting for connection...', and the game doesn't start after a long time has passed, the second player may have prematurely closed the game page or the configuration of your network doesn't allow P2P connections. You can test your network at ", 80 | "default_controls" : "Default controls", 81 | "load_own_rom" : "Load own ROM", 82 | "click_here_to_play_the_game" : "Click here to play the game", 83 | "error_occured" : "An error has occurred. Refresh the page. If the error persists, try again later, please.", 84 | "click_allow_button" : "Click the 'Allow' button on the top of the screen to allow using the keyboard in fullscreen mode. If you don't see this button try to update Flash Player.", 85 | "now_connect_gamepad" : "Now, connect your gamepad and configure it", 86 | "configure" : "configure", 87 | "or" : "or", 88 | "press" : "press", 89 | "button" : "button", 90 | "connecting_please_wait" : "Connecting. Please wait.", 91 | "if_you_want_to_use_gamepad" : "If you want to use a gamepad, save %1% application and run it", 92 | "email" : "email", 93 | "sign_in" : "sign in", 94 | "sign_up" : "sign up", 95 | "to_save_load_game_you_need" : "to save/load game you need to", 96 | "cancel" : "cancel", 97 | "keyboard_setup" : "keyboard setup", 98 | "select_joystick_button" : "select a joystick button, then press a key", 99 | "load_defaults" : "load defaults", 100 | "save" : "save", 101 | "select_mode" : "select mode", 102 | "supported_rom_formats" : "Supported ROM formats", 103 | "click_here_to_load_your_own_rom" : "Click here to load your own ROM", 104 | "loading_module" : "loading module", 105 | "loading_game" : "loading game", 106 | "loading_emulator" : "loading emulator", 107 | "uploading_walkthrough" : "uploading walkthrough", 108 | "please_wait" : "please wait", 109 | "you_already_have_saved_walkthrough" : "You have already saved your progress for this game. Do you want to overwrite it?", 110 | "yes" : "yes", 111 | "no" : "no", 112 | "you_need_to_be_signed_in_to_upload_walk" : "You need to be signed in to upload your game walkthrough.", 113 | "waiting_for_connection" : "Waiting for connection", 114 | "if_you_cannot_connect" : "If you cannot connect to the second player, try to test your connection at %1%. If you see red circles, please, contact your internet provider.", 115 | "connecting_to_server" : "Connecting to server", 116 | "new_send_copied_url" : "Now send the URL you copied to the second player.", 117 | "also_you_can_find_partner" : "Also you can find a partner to play in a %1%.", 118 | "connected_to_server" : "Connected to server", 119 | "remote_url" : "Remote url", 120 | "click_here_to_copy_url_to_clipboard" : "Click here to copy this url to clipboard", 121 | "then_send_it_to_friend" : "then send it to the second player", 122 | "connection_error" : "Connection error. Refresh the page or try again later", 123 | "testing_connection" : "Testing the connection. Please wait", 124 | "ping_is" : "Ping is %1% ms.", 125 | "the_game_will_be_uncomfortable" : "The game will be uncomfortable.", 126 | "saving_game" : "saving game", 127 | "you_have_saved_state" : "You already have a save file state for this game. Do you want to overwrite it?", 128 | "do_you_want_to_load_state" : "Do you want to load the save file ?", 129 | "you_need_to_be_signed_in_to_save" : "You need to be signed in to save/load the game.", 130 | "loading_walkthrough" : "loading walkthrough", 131 | "hint_pause" : "pause game", 132 | "hint_setup" : "setup keyboard", 133 | "hint_mute" : "mute sound", 134 | "hint_load" : "load state [F8]", 135 | "hint_save" : "save state [F5]", 136 | "hint_fullscreen" : "enable fullscreen [F11]", 137 | "hint_share" : "About Nesbox Emulator", 138 | "hint_upload" : "save walkthrough [F2]", 139 | "hint_gamepad" : "setup gamepad", 140 | "hint_favorite" : "add to favorites", 141 | "from_language" : "From language", 142 | "to_language" : "to language", 143 | "submit_translation" : "Submit translation", 144 | "email_for_feedback" : "Email for feedback", 145 | "name_for_crediting" : "Name for crediting in 'About Us'", 146 | "thank_you" : "Thank you", 147 | "sorry_please_try_again_later" : "Sorry. Try again later, please", 148 | "translation_submited" : "The translation has been submited", 149 | "translators" : "Translators", 150 | "open_in_windows_8" : "Open in Nesbox for Windows 8", 151 | "labs" : "Labs", 152 | "password_reset" : "Password reset", 153 | "submiting" : "Submiting", 154 | "password_has_reset" : "Your password has successfully reset. Try to Sign In.", 155 | "password_reset_email" : "Hello, to reset your password, please visit the following link", 156 | "enter_with" : "Enter with", 157 | "favorites" : "Favorites", 158 | "user_profile" : "User profile", 159 | "history" : "History", 160 | "own_roms" : "Own ROMs", 161 | "gamepad_app_info" : "To use gamepad with the emulator, please download and install Adobe Air and Nesbox Companion application ", 162 | "gamepad_app_downloaded" : "Nesbox Companion downloaded", 163 | "click_here_to_save_it" : "Click here to save it", 164 | "server_setup" : "server setup", 165 | "server_port" : "Port", 166 | "server_frameskip" : "Skip frames", 167 | "connect" : "connect", 168 | "server_connection_error" : "Connection error", 169 | "make_sure_entered_correct_ip" : "please make sure you entered the correct IP address", 170 | "try_again" : "try again", 171 | "you_are_connected" : "You are connected", 172 | "and_send_to_friend" : "and then send it to your friend", 173 | "remote_url_is" : "Remote URL is", 174 | "connection_has_closed" : "Connection to the server has been closed", 175 | "please_read" : "Please read", 176 | "how_start_own_server" : "How to run your own server", 177 | "nothing_found" : "Nothing Found. Please, try again with some different keywords" 178 | } -------------------------------------------------------------------------------- /src/assets/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/facebook.png -------------------------------------------------------------------------------- /src/assets/favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/favorite.png -------------------------------------------------------------------------------- /src/assets/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/fullscreen.png -------------------------------------------------------------------------------- /src/assets/gamepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/gamepad.png -------------------------------------------------------------------------------- /src/assets/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/github.png -------------------------------------------------------------------------------- /src/assets/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/google.png -------------------------------------------------------------------------------- /src/assets/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/load.png -------------------------------------------------------------------------------- /src/assets/mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/mute.png -------------------------------------------------------------------------------- /src/assets/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/save.png -------------------------------------------------------------------------------- /src/assets/setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/setup.png -------------------------------------------------------------------------------- /src/assets/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/twitter.png -------------------------------------------------------------------------------- /src/assets/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/upload.png -------------------------------------------------------------------------------- /src/assets/vkontakte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesbox/emulator/12e79e64fd4a4aa20fd1239e8a6773ffae393961/src/assets/vkontakte.png -------------------------------------------------------------------------------- /src/core/CorePlayerBase.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import com.adobe.images.PNGEncoder; 4 | 5 | import flash.display.Bitmap; 6 | import flash.display.BitmapData; 7 | import flash.events.Event; 8 | import flash.events.IOErrorEvent; 9 | import flash.events.ProgressEvent; 10 | import flash.events.SampleDataEvent; 11 | import flash.events.SecurityErrorEvent; 12 | import flash.geom.Point; 13 | import flash.geom.Rectangle; 14 | import flash.media.Sound; 15 | import flash.media.SoundChannel; 16 | import flash.net.Socket; 17 | import flash.utils.ByteArray; 18 | import flash.utils.setTimeout; 19 | 20 | public class CorePlayerBase extends Bitmap implements ICorePlayer 21 | { 22 | private var coreModule:ICoreModule; 23 | private var keyCodes:Array; 24 | private var sound:Sound; 25 | private var soundChannel:SoundChannel; 26 | private var pausedValue:Boolean = true; 27 | private var handler:ICoreHandler; 28 | private var gamepadSocket:Socket; 29 | private var gamepadOffsets:Array; 30 | 31 | protected var inputFlags:uint; 32 | 33 | private static const Port:int = 8087; 34 | private static const Localhost:String = '127.0.0.1'; 35 | 36 | private static const CompanionButtonsOrder:Array = 37 | [ 38 | 'up', 'down', 'left', 'right', 39 | 'a', 'b', 'c', 40 | 'x', 'y', 'z', 41 | 'select', 'start', 42 | 'l', 'r' 43 | ]; 44 | 45 | public function CorePlayerBase(core:ICoreModule, handler:ICoreHandler) 46 | { 47 | this.coreModule = core; 48 | this.handler = handler; 49 | 50 | bitmapData = new BitmapData(Variables.Width, Variables.Height, false, 0x000000); 51 | 52 | initGamepad(); 53 | } 54 | 55 | private function initGamepad():void 56 | { 57 | if(handler.isNeedGamepad()) 58 | { 59 | gamepadSocket = new Socket; 60 | 61 | gamepadSocket.addEventListener(Event.CONNECT, function():void 62 | { 63 | var names:Array = coreModule.getGamepadKeysNames(); 64 | gamepadOffsets = []; 65 | 66 | for each(var order:String in CompanionButtonsOrder) 67 | { 68 | gamepadOffsets.push(names.indexOf(order)); 69 | } 70 | }); 71 | 72 | var processGamepad:Function = function(input:uint):uint 73 | { 74 | var inputFlags:uint = 0; 75 | 76 | for(var index:int = 0; index < gamepadOffsets.length; index++) 77 | { 78 | var offset:int = gamepadOffsets[index]; 79 | 80 | if(offset != -1 && (input & (1 << index))) 81 | { 82 | inputFlags |= (1 << offset); 83 | } 84 | } 85 | 86 | return inputFlags; 87 | }; 88 | 89 | gamepadSocket.addEventListener(ProgressEvent.SOCKET_DATA, function():void 90 | { 91 | while(gamepadSocket.bytesAvailable) 92 | { 93 | var input:uint = gamepadSocket.readUnsignedInt(); 94 | var firstInput:uint = processGamepad(input & 0xffff); 95 | var secondInput:uint = processGamepad((input & 0xffff0000) >> 16); 96 | 97 | inputFlags = ((firstInput & 0xfff) | ((secondInput & 0xfff) << 12)); 98 | } 99 | }); 100 | 101 | var connectToGamepad:Function = function():void 102 | { 103 | setTimeout(function():void 104 | { 105 | gamepadSocket.connect(Localhost, Port); 106 | }, 1000); 107 | } 108 | 109 | gamepadSocket.addEventListener(Event.CLOSE, function():void 110 | { 111 | connectToGamepad(); 112 | }); 113 | 114 | gamepadSocket.addEventListener(IOErrorEvent.IO_ERROR, function():void 115 | { 116 | connectToGamepad(); 117 | }); 118 | 119 | gamepadSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function():void 120 | { 121 | connectToGamepad(); 122 | }); 123 | 124 | connectToGamepad(); 125 | 126 | } 127 | } 128 | 129 | public function pause():void 130 | { 131 | pausedValue = true; 132 | 133 | stopChannel(); 134 | } 135 | 136 | public function play():void 137 | { 138 | pausedValue = false; 139 | 140 | if(!muted) 141 | { 142 | startChannel(); 143 | } 144 | } 145 | 146 | public function get paused():Boolean 147 | { 148 | return pausedValue; 149 | } 150 | 151 | public function set muted(value:Boolean):void 152 | { 153 | coreModule.muted = value; 154 | 155 | if(value) 156 | { 157 | stopChannel(); 158 | } 159 | else 160 | { 161 | startChannel(); 162 | } 163 | } 164 | 165 | public function get muted():Boolean 166 | { 167 | return coreModule.muted; 168 | } 169 | 170 | private function stopChannel():void 171 | { 172 | if(soundChannel) 173 | { 174 | soundChannel.stop(); 175 | soundChannel = null; 176 | } 177 | } 178 | 179 | private function startChannel():void 180 | { 181 | if(sound) 182 | { 183 | stopChannel(); 184 | soundChannel = sound.play(); 185 | } 186 | } 187 | 188 | public function load(saveDataComp:ByteArray):void 189 | { 190 | if (saveDataComp) 191 | { 192 | saveDataComp.position = 0; 193 | var saveData:ByteArray = new ByteArray; 194 | saveDataComp.readBytes(saveData); 195 | saveData.position = 0; 196 | 197 | if (saveData.bytesAvailable) 198 | { 199 | saveData.uncompress(); 200 | coreModule.load(saveData); 201 | } 202 | } 203 | } 204 | 205 | public function save():ByteArray 206 | { 207 | var saveData:ByteArray = coreModule.save(); 208 | 209 | if (saveData) 210 | { 211 | saveData.compress(); 212 | saveData.position = 0; 213 | } 214 | 215 | return saveData; 216 | } 217 | 218 | public function initEmulation(isNtsc:Boolean, rom:ByteArray, region:String):void 219 | { 220 | coreModule.init(isNtsc, rom, region); 221 | 222 | stage.frameRate = isNtsc ? Variables.NtscFramerate : Variables.PalFramerate; 223 | sound = new Sound; 224 | sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData); 225 | 226 | if(!muted) 227 | { 228 | startChannel(); 229 | } 230 | } 231 | 232 | public function updateKeyCodes(codes:Array):void 233 | { 234 | keyCodes = codes; 235 | } 236 | 237 | protected function onKey(code:uint, down:Boolean = true):void 238 | { 239 | var index:int = keyCodes.indexOf(code); 240 | var mask:int = 1 << index; 241 | down ? inputFlags |= mask : inputFlags &= ~mask; 242 | } 243 | 244 | protected function emulate(input:uint):void 245 | { 246 | coreModule.tick(input, bitmapData); 247 | 248 | if(handler) 249 | { 250 | handler.onEmulate(); 251 | } 252 | } 253 | 254 | private function onSampleData(event:SampleDataEvent):void 255 | { 256 | coreModule.sound(event.data); 257 | } 258 | 259 | public function get screen():ByteArray 260 | { 261 | var data:BitmapData = new BitmapData(Variables.Width, Variables.Height); 262 | data.copyPixels(bitmapData, new Rectangle(0, 0, Variables.Width, Variables.Height), new Point); 263 | return PNGEncoder.encode(data); 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/core/CorePlayerContest.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import com.adobe.images.PNGEncoder; 4 | 5 | import flash.events.Event; 6 | import flash.events.KeyboardEvent; 7 | import flash.utils.ByteArray; 8 | 9 | public class CorePlayerContest extends CorePlayerBase 10 | { 11 | private var walkData:ByteArray; 12 | 13 | public function CorePlayerContest(core:ICoreModule, handler:ICoreHandler) 14 | { 15 | super(core, handler); 16 | } 17 | 18 | public function getWalk():ByteArray 19 | { 20 | var data:ByteArray = new ByteArray; 21 | 22 | walkData.position = 0; 23 | walkData.readBytes(data); 24 | 25 | data.compress(); 26 | data.position = 0; 27 | 28 | return data; 29 | } 30 | 31 | public function initContestEmulation(isNtsc:Boolean, rom:ByteArray, region:String):void 32 | { 33 | walkData = new ByteArray; 34 | 35 | stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); 36 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 37 | stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); 38 | 39 | initEmulation(isNtsc, rom, region); 40 | } 41 | 42 | private function onEnterFrame(event:Event):void 43 | { 44 | if(!paused) 45 | { 46 | emulate(inputFlags); 47 | 48 | walkData.writeShort(inputFlags & 0xfff); 49 | } 50 | } 51 | 52 | private function onKeyDown(event:KeyboardEvent):void 53 | { 54 | onKey(event.keyCode); 55 | } 56 | 57 | private function onKeyUp(event:KeyboardEvent):void 58 | { 59 | onKey(event.keyCode, false); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/core/CorePlayerNetwork.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import flash.events.Event; 4 | import flash.events.KeyboardEvent; 5 | import flash.utils.ByteArray; 6 | import flash.utils.setInterval; 7 | 8 | public class CorePlayerNetwork extends CorePlayerBase 9 | { 10 | private var recvInput:Array = []; 11 | private var isFirstPeer:Boolean; 12 | private var handler:ICorePlayerHandler; 13 | private var inputQueue:Array = []; 14 | 15 | private static const Delimiter:uint = 3; 16 | 17 | public function CorePlayerNetwork(core:ICoreModule, handler:ICorePlayerHandler) 18 | { 19 | super(core, handler); 20 | this.handler = handler; 21 | } 22 | 23 | public function initNetworkEmulation(isNtsc:Boolean, isFirstPeer:Boolean, rom:ByteArray, region:String):void 24 | { 25 | initEmulation(isNtsc, rom, region); 26 | 27 | this.isFirstPeer = isFirstPeer; 28 | 29 | stage.addEventListener(Event.ENTER_FRAME, onEnterFrameNetwork); 30 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 31 | stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); 32 | 33 | if(isFirstPeer) 34 | { 35 | sendInputValue(0); 36 | } 37 | else 38 | { 39 | handler.sendDummy(); 40 | } 41 | 42 | setInterval(function():void 43 | { 44 | handler.sendDummy(); 45 | }, 1000); 46 | } 47 | 48 | public function recvInputValue(input:uint):void 49 | { 50 | recvInput.push(input); 51 | } 52 | 53 | private function sendInputValue(input:uint):void 54 | { 55 | handler.sendInput(input); 56 | } 57 | 58 | private function onKeyDown(event:KeyboardEvent):void 59 | { 60 | onKey(event.keyCode); 61 | } 62 | 63 | private function onKeyUp(event:KeyboardEvent):void 64 | { 65 | onKey(event.keyCode, false); 66 | } 67 | 68 | private function onEnterFrameNetwork(event:Event):void 69 | { 70 | if(paused) 71 | { 72 | return; 73 | } 74 | 75 | if(inputQueue.length > 0) 76 | { 77 | emulate(uint(inputQueue.shift())); 78 | return; 79 | } 80 | 81 | if(recvInput.length == 1) 82 | { 83 | var input:uint = recvInput.shift(); 84 | 85 | if(isFirstPeer) 86 | { 87 | sendInputValue(inputFlags); 88 | } 89 | else 90 | { 91 | input = (input & 0xfff) | ((inputFlags & 0xfff) << 12); 92 | 93 | sendInputValue(input); 94 | } 95 | 96 | var frames:uint = Delimiter; 97 | while(frames--) 98 | { 99 | inputQueue.push(input); 100 | } 101 | 102 | emulate(input); 103 | 104 | return; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/core/CorePlayerOwnServer.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import flash.display.FrameLabel; 4 | import flash.events.Event; 5 | import flash.events.KeyboardEvent; 6 | import flash.utils.ByteArray; 7 | import flash.utils.setInterval; 8 | 9 | public class CorePlayerOwnServer extends CorePlayerBase 10 | { 11 | private var recvInput:Array = []; 12 | private var handler:ICorePlayerHandler; 13 | private var inputQueue:Array = []; 14 | private var delimiter:uint; 15 | 16 | public function CorePlayerOwnServer(core:ICoreModule, handler:ICorePlayerHandler) 17 | { 18 | super(core, handler); 19 | this.handler = handler; 20 | } 21 | 22 | public function initNetworkEmulation(isNtsc:Boolean, rom:ByteArray, region:String, frameskip:uint):void 23 | { 24 | initEmulation(isNtsc, rom, region); 25 | 26 | this.delimiter = frameskip; 27 | 28 | stage.addEventListener(Event.ENTER_FRAME, onEnterFrameNetwork); 29 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 30 | stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); 31 | 32 | sendInputValue(0); 33 | } 34 | 35 | public function recvInputValue(input:uint):void 36 | { 37 | recvInput.push(input); 38 | } 39 | 40 | private function sendInputValue(input:uint):void 41 | { 42 | handler.sendInput(input); 43 | } 44 | 45 | private function onKeyDown(event:KeyboardEvent):void 46 | { 47 | onKey(event.keyCode); 48 | } 49 | 50 | private function onKeyUp(event:KeyboardEvent):void 51 | { 52 | onKey(event.keyCode, false); 53 | } 54 | 55 | private function onEnterFrameNetwork(event:Event):void 56 | { 57 | if(paused) 58 | { 59 | return; 60 | } 61 | 62 | if(inputQueue.length > 0) 63 | { 64 | emulate(uint(inputQueue.shift())); 65 | return; 66 | } 67 | 68 | if(recvInput.length == 1) 69 | { 70 | sendInputValue(inputFlags); 71 | 72 | var input:uint = recvInput.shift(); 73 | var frames:uint = delimiter; 74 | 75 | while(frames--) 76 | { 77 | inputQueue.push(input); 78 | } 79 | 80 | emulate(input); 81 | 82 | return; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/core/CorePlayerSingle.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import flash.events.Event; 4 | import flash.events.KeyboardEvent; 5 | import flash.utils.ByteArray; 6 | 7 | public class CorePlayerSingle extends CorePlayerBase 8 | { 9 | public function CorePlayerSingle(core:ICoreModule, handler:ICoreHandler) 10 | { 11 | super(core, handler); 12 | } 13 | 14 | public function initSingleEmulation(isNtsc:Boolean, rom:ByteArray, region:String):void 15 | { 16 | stage.focus = stage; 17 | 18 | stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); 19 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 20 | stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); 21 | 22 | initEmulation(isNtsc, rom, region); 23 | } 24 | 25 | private function onEnterFrame(event:Event):void 26 | { 27 | if(!paused) 28 | { 29 | emulate(inputFlags); 30 | } 31 | } 32 | 33 | private function onKeyDown(event:KeyboardEvent):void 34 | { 35 | onKey(event.keyCode); 36 | } 37 | 38 | private function onKeyUp(event:KeyboardEvent):void 39 | { 40 | onKey(event.keyCode, false); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/core/CorePlayerWalk.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import flash.events.Event; 4 | import flash.utils.ByteArray; 5 | 6 | public class CorePlayerWalk extends CorePlayerBase 7 | { 8 | private var walkData:ByteArray; 9 | 10 | public function CorePlayerWalk(core:ICoreModule, handler:ICoreHandler) 11 | { 12 | super(core, handler); 13 | } 14 | 15 | public function initWalkEmulation(isNtsc:Boolean, walk:ByteArray, rom:ByteArray, region:String):void 16 | { 17 | initEmulation(isNtsc, rom, region); 18 | 19 | walk.position = 0; 20 | walkData = new ByteArray; 21 | walk.readBytes(walkData); 22 | walkData.position = 0; 23 | 24 | stage.addEventListener(Event.ENTER_FRAME, onWalkEnterFrame); 25 | } 26 | 27 | private function onWalkEnterFrame(event:Event):void 28 | { 29 | if(!paused) 30 | { 31 | if(walkData.bytesAvailable) 32 | { 33 | var input:uint = walkData.readUnsignedShort(); 34 | emulate(input & 0xfff); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/core/ICoreHandler.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | public interface ICoreHandler 4 | { 5 | function onEmulate():void; 6 | function isNeedGamepad():Boolean; 7 | } 8 | } -------------------------------------------------------------------------------- /src/core/ICorePlayer.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | public interface ICorePlayer 6 | { 7 | function set muted(value:Boolean):void; 8 | function get muted():Boolean; 9 | function load(state:ByteArray):void; 10 | function save():ByteArray; 11 | function initEmulation(isNtsc:Boolean, rom:ByteArray, region:String):void; 12 | } 13 | } -------------------------------------------------------------------------------- /src/core/ICorePlayerHandler.as: -------------------------------------------------------------------------------- 1 | package core 2 | { 3 | public interface ICorePlayerHandler extends ICoreHandler 4 | { 5 | function sendInput(input:uint):void; 6 | function sendDummy():void; 7 | } 8 | } -------------------------------------------------------------------------------- /src/mode/Base.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import core.ICoreHandler; 4 | import flash.net.navigateToURL; 5 | 6 | import flash.display.DisplayObject; 7 | import flash.display.Sprite; 8 | import flash.display.StageDisplayState; 9 | import flash.events.Event; 10 | import flash.events.FullScreenEvent; 11 | import flash.events.IOErrorEvent; 12 | import flash.events.MouseEvent; 13 | import flash.geom.Rectangle; 14 | import flash.net.FileReference; 15 | import flash.net.URLLoader; 16 | import flash.net.URLLoaderDataFormat; 17 | import flash.net.URLRequest; 18 | import flash.utils.ByteArray; 19 | import flash.utils.clearInterval; 20 | import flash.utils.clearTimeout; 21 | import flash.utils.setInterval; 22 | import flash.utils.setTimeout; 23 | 24 | import model.Gamepad; 25 | import model.Settings; 26 | 27 | import server.Api; 28 | import server.IApiHandler; 29 | 30 | import ui.Actions; 31 | import ui.FullscreenMessage; 32 | import ui.IActionsHandler; 33 | import ui.Message; 34 | 35 | internal class Base extends Sprite implements IApiHandler, ICoreHandler, IActionsHandler 36 | { 37 | private var activeMessage:Message; 38 | private var gamepadMessage:Message; 39 | private var fullscreenMessage:FullscreenMessage; 40 | 41 | protected var api:Api; 42 | protected var settings:Settings; 43 | protected var gameData:GameData; 44 | protected var locale:Locale; 45 | 46 | protected static const UploadHotkeyCode:uint = 113; // F2 47 | protected static const SaveHotkeyCode:uint = 119; // F8 48 | protected static const LoadHotkeyCode:uint = 116; // F5 49 | protected static const FullscreenHotkeyCode:uint = 122; // F11 50 | 51 | public function Base(gameData:GameData) 52 | { 53 | super(); 54 | 55 | locale = Locale.instance; 56 | 57 | this.gameData = gameData; 58 | 59 | settings = new Settings(gameData.core.getSettingsUid()); 60 | api = new Api(this, gameData.domain); 61 | 62 | this.addEventListener(Event.ADDED_TO_STAGE, function():void 63 | { 64 | initActionsShowing(); 65 | // enableGamepad(!Tools.isWindows); 66 | 67 | stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullscreenModeChanged); 68 | 69 | if(Tools.isInteractiveFullscreenSupported()) 70 | { 71 | stage.addEventListener(FullScreenEvent.FULL_SCREEN_INTERACTIVE_ACCEPTED, fullscreenAccepted); 72 | } 73 | 74 | // setFullscreenRect(); 75 | 76 | const Ntsc:String = 'ntsc'; 77 | if(stage.loaderInfo.parameters.hasOwnProperty(Ntsc)) 78 | { 79 | gameData.ntsc = stage.loaderInfo.parameters[Ntsc] == 'true'; 80 | } 81 | 82 | const Region:String = 'region'; 83 | if(stage.loaderInfo.parameters.hasOwnProperty(Region)) 84 | { 85 | gameData.region = stage.loaderInfo.parameters[Region]; 86 | } 87 | 88 | init(); 89 | }); 90 | } 91 | 92 | private function initActionsShowing():void 93 | { 94 | var timeoutId:uint = 0; 95 | 96 | stage.addEventListener(MouseEvent.MOUSE_MOVE, function():void 97 | { 98 | startActionsShow(); 99 | 100 | if(timeoutId) 101 | { 102 | clearTimeout(timeoutId); 103 | timeoutId = 0; 104 | } 105 | 106 | timeoutId = setTimeout(function():void 107 | { 108 | if(timeoutId) 109 | { 110 | clearTimeout(timeoutId); 111 | timeoutId = 0; 112 | } 113 | 114 | stopActionsShow(); 115 | }, 3000); 116 | 117 | }); 118 | 119 | stage.addEventListener(Event.MOUSE_LEAVE, function():void 120 | { 121 | stopActionsShow(); 122 | }); 123 | } 124 | 125 | protected function showActions(actions:DisplayObject):void 126 | { 127 | if(actions.visible) return; 128 | 129 | actions.visible = true; 130 | actions.alpha = 0.0; 131 | actions.y = Variables.Height; 132 | 133 | var id:uint = setInterval(function():void 134 | { 135 | if(!actions.visible) clearInterval(id); 136 | 137 | if(actions.y > Variables.Height - Actions.Height) 138 | { 139 | actions.y -= 1; 140 | } 141 | else 142 | { 143 | clearInterval(id); 144 | } 145 | 146 | if(actions.alpha < 1.0) 147 | { 148 | actions.alpha += 1.0/Number(Actions.Height); 149 | } 150 | }, 20); 151 | } 152 | 153 | protected function hideActions(actions:DisplayObject):void 154 | { 155 | actions.visible = false; 156 | } 157 | 158 | protected function startActionsShow():void {} 159 | 160 | protected function stopActionsShow():void {} 161 | 162 | protected function init():void 163 | { 164 | JSProxy.initSigningCallback(onApiUserSigned); 165 | initActivateEngine(); 166 | 167 | if(!settings.keyboard 168 | || settings.keyboard.empty) 169 | { 170 | var keysCount:int = gameData.core.getGamepadDefaultKeys().length; 171 | 172 | var joystick:Gamepad = new Gamepad(keysCount); 173 | joystick.codes = gameData.core.getGamepadDefaultKeys(); 174 | settings.keyboard = joystick; 175 | } 176 | 177 | showDefaultKeyboard(); 178 | start(); 179 | } 180 | 181 | private function showDefaultKeyboard():void 182 | { 183 | var needShowing:Boolean = JSON.stringify(settings.keyboard.codes) 184 | == JSON.stringify(gameData.core.getGamepadDefaultKeys()); 185 | 186 | if(needShowing) 187 | { 188 | JSProxy.showDefaultKeyboard(); 189 | } 190 | } 191 | 192 | protected function start():void {}; 193 | 194 | protected function resume():void 195 | { 196 | activeMessage.hide(); 197 | } 198 | 199 | protected function pause():void 200 | { 201 | activeMessage.show('

' + 202 | locale.click_here_to_play_the_game + //value('Click here to play the game') + 203 | '...

'); 204 | } 205 | 206 | protected function initActivateEngine():void 207 | { 208 | activeMessage = new Message; 209 | addChild(activeMessage); 210 | 211 | gamepadMessage = new Message; 212 | addChild(gamepadMessage); 213 | 214 | fullscreenMessage = new FullscreenMessage; 215 | addChild(fullscreenMessage); 216 | 217 | stage.addEventListener(Event.ACTIVATE, function():void 218 | { 219 | if(fullscreenMessage.visible)return; 220 | resume(); 221 | }); 222 | 223 | stage.addEventListener(Event.DEACTIVATE, function():void 224 | { 225 | if(fullscreenMessage.visible)return; 226 | pause(); 227 | }); 228 | } 229 | 230 | public function onApiError(info:String):void 231 | { 232 | if(!activeMessage) return; 233 | 234 | var callbacks:Object = 235 | { 236 | close:function():void 237 | { 238 | activeMessage.hide(); 239 | } 240 | }; 241 | 242 | activeMessage.show('

'+locale.error_occured 243 | + '

' 244 | + locale.close 245 | + '

', callbacks); 246 | } 247 | public function onApiSaved(state:ByteArray):void {} 248 | public function onApiLoaded(state:ByteArray):void {} 249 | public function onApiNeedSign():void {} 250 | public function onApiUserSigned(signed:Boolean):void {} 251 | public function onApiState(userLogined:Boolean, state:ByteArray):void {} 252 | public function onApiUploaded():void {} 253 | public function onApiFavorited(value:Boolean):void {} 254 | 255 | protected function onScreenShot():void {} 256 | 257 | public function onEmulate():void {} 258 | 259 | public function isNeedGamepad():Boolean 260 | { 261 | return gameData.action != 'walk'; 262 | } 263 | 264 | public function onActionsShareFacebook():void 265 | { 266 | JSProxy.windowOpen('http://www.facebook.com/sharer.php?u=' + Tools.currentUrl, 'Send to Facebook'); 267 | } 268 | 269 | public function onActionsShareGoogle():void 270 | { 271 | JSProxy.windowOpen('https://plus.google.com/share?url=' + Tools.currentUrl, 'Send to Google+'); 272 | } 273 | 274 | public function onActionsShareTwitter():void 275 | { 276 | JSProxy.windowOpen('http://twitter.com/share?url=' + Tools.currentUrl, 'Send to Twitter'); 277 | } 278 | 279 | public function onActionsShareVkontakte():void 280 | { 281 | JSProxy.windowOpen('http://vk.com/share.php?url=' + Tools.currentUrl, 'Send to VKontakte'); 282 | } 283 | 284 | public function onActionsShareGithub():void 285 | { 286 | Tools.gotoNesboxPage(); 287 | } 288 | 289 | protected function pauseEmulation():void {} 290 | protected function resumeEmulation():void {} 291 | protected function enableFullscreen(enable:Boolean):void {} 292 | 293 | public function onActionsFullscreen():void 294 | { 295 | if(stage.displayState == StageDisplayState.NORMAL) 296 | { 297 | setFullscreenRect(); 298 | stage.displayState = StageDisplayState.FULL_SCREEN; 299 | } 300 | else 301 | { 302 | stage.displayState = StageDisplayState.NORMAL; 303 | } 304 | } 305 | 306 | public function onActionsFullscreenInteractive():void 307 | { 308 | if(stage.displayState == StageDisplayState.NORMAL) 309 | { 310 | pauseEmulation(); 311 | 312 | var handlers:Object = 313 | { 314 | cancel:function():void 315 | { 316 | stage.displayState = StageDisplayState.NORMAL; 317 | } 318 | }; 319 | 320 | fullscreenMessage.show('

' 321 | + locale.click_allow_button 322 | + '


' 323 | + ''+locale.cancel.toUpperCase()+'

', handlers); 324 | 325 | resetFullscreenRect(); 326 | stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; 327 | } 328 | else 329 | { 330 | stage.displayState = StageDisplayState.NORMAL; 331 | } 332 | } 333 | 334 | private function fullscreenModeChanged(event:FullScreenEvent):void 335 | { 336 | if(!event.fullScreen) 337 | { 338 | resetFullscreenRect(); 339 | fullscreenMessage.hide(); 340 | resumeEmulation(); 341 | } 342 | } 343 | 344 | private function fullscreenAccepted(event:FullScreenEvent):void 345 | { 346 | fullscreenMessage.hide(); 347 | 348 | setFullscreenRect(); 349 | 350 | resumeEmulation(); 351 | } 352 | 353 | private function setFullscreenRect():void 354 | { 355 | parent.scaleX = parent.scaleY = 1; 356 | 357 | var fullWidth:int = stage.fullScreenWidth; 358 | var fullHeight:int = stage.fullScreenHeight; 359 | var rect:Rectangle = new Rectangle(); 360 | 361 | if(Variables.Width/Variables.Height <= fullWidth/fullHeight) 362 | { 363 | rect.x = (Variables.Width - fullWidth * Variables.Height / fullHeight) / 2; 364 | rect.width = fullWidth * Variables.Height / fullHeight; 365 | rect.height = Variables.Height; 366 | } 367 | else 368 | { 369 | rect.y = (Variables.Height - fullHeight * Variables.Width/ fullWidth) / 2; 370 | rect.width = Variables.Width; 371 | rect.height = fullHeight * Variables.Width / fullWidth; 372 | } 373 | 374 | stage.fullScreenSourceRect = rect; 375 | } 376 | 377 | private function resetFullscreenRect():void 378 | { 379 | parent.scaleX = parent.scaleY = 2; 380 | stage.fullScreenSourceRect = null; 381 | } 382 | 383 | public function onActionsMute():void {} 384 | public function onActionsLoad():void {} 385 | public function onActionsSave():void {} 386 | public function onActionsSetup():void {} 387 | public function onActionsUpload():void {} 388 | public function onActionsFavorite():void {} 389 | 390 | public function onActionsGamepad():void 391 | { 392 | var callbacks:Object = 393 | { 394 | air:function():void 395 | { 396 | navigateToURL(new URLRequest('//get.adobe.com/air/'), '_blank'); 397 | }, 398 | 399 | companion:function():void 400 | { 401 | navigateToURL(new URLRequest('//github.com/nesbox/nesbox-companion/raw/master/air/companion.air'), '_blank'); 402 | }, 403 | 404 | close:function():void 405 | { 406 | gamepadMessage.hide(); 407 | } 408 | }; 409 | 410 | gamepadMessage.show('

'+locale.gamepad_app_info+'




' + 411 | 'Download Adobe AIR

' + 412 | 'Download Nesbox Companion


' + 413 | ''+locale.close.toLocaleUpperCase()+'

', callbacks); 414 | } 415 | 416 | } 417 | } -------------------------------------------------------------------------------- /src/mode/Contest.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import core.CorePlayerContest; 4 | 5 | import flash.events.KeyboardEvent; 6 | 7 | import model.Gamepad; 8 | 9 | import ui.Actions; 10 | import ui.ActionsMode; 11 | import ui.IBaseSetup; 12 | import ui.ISetupHandler; 13 | import ui.Message; 14 | import ui.Setup; 15 | import ui.SetupBuilder; 16 | 17 | public class Contest extends Base 18 | implements 19 | ISetupHandler 20 | { 21 | private var nes:CorePlayerContest; 22 | private var setup:IBaseSetup; 23 | private var message:Message; 24 | private var actions:Actions; 25 | private var state:EmulatorState; 26 | 27 | public function Contest(gameData:GameData) 28 | { 29 | super(gameData); 30 | 31 | nes = new CorePlayerContest(gameData.core, this); 32 | actions = new Actions(this, ActionsMode.Contest); 33 | setup = SetupBuilder.Make(this, gameData); 34 | message = new Message(); 35 | 36 | actions.muted = nes.muted = settings.muted; 37 | actions.visible = false; 38 | actions.enableFullscreen = Tools.isInteractiveFullscreenSupported(); 39 | } 40 | 41 | protected override function init():void 42 | { 43 | addChild(nes); 44 | addChild(actions); 45 | addChild(setup.sprite); 46 | addChild(message); 47 | 48 | state = EmulatorState.Playing; 49 | 50 | super.init(); 51 | } 52 | 53 | protected override function startActionsShow():void 54 | { 55 | super.showActions(actions); 56 | } 57 | 58 | protected override function stopActionsShow():void 59 | { 60 | super.hideActions(actions); 61 | } 62 | 63 | protected override function resume():void 64 | { 65 | super.resume(); 66 | 67 | if(!setup.visible 68 | && !message.visible) 69 | { 70 | nes.play(); 71 | } 72 | } 73 | 74 | protected override function pause():void 75 | { 76 | if(!setup.visible 77 | && !message.visible) 78 | { 79 | super.pause(); 80 | nes.pause(); 81 | } 82 | } 83 | 84 | protected override function pauseEmulation():void 85 | { 86 | nes.pause(); 87 | } 88 | 89 | protected override function resumeEmulation():void 90 | { 91 | nes.play(); 92 | } 93 | 94 | // protected override function updateGamepadCodes(codes:Array):void 95 | // { 96 | // nes.updateGamepadCodes(codes); 97 | // } 98 | 99 | protected override function enableFullscreen(enable:Boolean):void 100 | { 101 | actions.enableFullscreen = enable; 102 | } 103 | 104 | // protected override function enableGamepad(enable:Boolean):void 105 | // { 106 | // actions.enableGamepad = enable; 107 | // } 108 | 109 | private function uploadWalk():void 110 | { 111 | nes.pause(); 112 | message.show('

'+locale.uploading_walkthrough+'...

'); 113 | 114 | api.uploadWalk(gameData.rom, nes.getWalk()); 115 | } 116 | 117 | private function initUploadShortcut():void 118 | { 119 | stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void 120 | { 121 | switch(event.keyCode) 122 | { 123 | case UploadHotkeyCode: 124 | onActionsUpload(); 125 | break; 126 | } 127 | }); 128 | } 129 | 130 | private function onSignIn():void 131 | { 132 | nes.pause(); 133 | JSProxy.showSignInModal(); 134 | } 135 | 136 | private function onSignUp():void 137 | { 138 | nes.pause(); 139 | JSProxy.showSignUpModal(); 140 | } 141 | 142 | public function onSetupSave(joystick:Gamepad):void 143 | { 144 | settings.keyboard = joystick; 145 | nes.updateKeyCodes(joystick.codes); 146 | nes.play(); 147 | setup.visible = false; 148 | } 149 | 150 | public function onSetupCancel():void 151 | { 152 | nes.play(); 153 | setup.visible = false; 154 | } 155 | 156 | protected override function start():void 157 | { 158 | nes.updateKeyCodes(settings.keyboard.codes); 159 | 160 | initUploadShortcut(); 161 | nes.initContestEmulation(gameData.ntsc, gameData.data, gameData.region); 162 | Focus.activated ? nes.play() : pause(); 163 | } 164 | 165 | public override function onActionsMute():void 166 | { 167 | nes.muted = !nes.muted; 168 | settings.muted = nes.muted; 169 | actions.muted = nes.muted; 170 | } 171 | 172 | public override function onActionsSetup():void 173 | { 174 | nes.pause(); 175 | setup.show(settings.keyboard); 176 | } 177 | 178 | public override function onActionsUpload():void 179 | { 180 | state = EmulatorState.Uploadig; 181 | uploadWalk(); 182 | } 183 | 184 | public function onSigninCancel():void 185 | { 186 | message.hide(); 187 | nes.play(); 188 | } 189 | 190 | public override function onApiError(info:String):void 191 | { 192 | var callbacks:Object = 193 | { 194 | cancelsign:onSigninCancel 195 | }; 196 | 197 | message.show('

' + locale.error_occured + 198 | '

' + locale.close.toUpperCase() + 199 | '

', callbacks); 200 | } 201 | 202 | public override function onApiNeedSign():void 203 | { 204 | var callbacks:Object = 205 | { 206 | signin:onSignIn, 207 | signup:onSignUp, 208 | cancelsign:onSigninCancel 209 | }; 210 | 211 | message.show('

'+locale.you_need_to_be_signed_in_to_upload_walk+'

' + 212 | ''+locale.sign_in.toUpperCase()+' ' + 213 | locale.or + 214 | ' '+locale.sign_up.toUpperCase()+'

' + 215 | ''+locale.cancel.toUpperCase()+'

', callbacks); 216 | } 217 | 218 | public override function onApiUserSigned(signed:Boolean):void 219 | { 220 | if(signed) 221 | { 222 | switch(state) 223 | { 224 | case EmulatorState.Uploadig: 225 | uploadWalk(); 226 | break; 227 | } 228 | 229 | nes.play(); 230 | } 231 | else 232 | { 233 | 234 | } 235 | } 236 | 237 | public override function onApiUploaded():void 238 | { 239 | state = EmulatorState.Playing; 240 | message.hide(); 241 | nes.play(); 242 | } 243 | 244 | protected override function onScreenShot():void 245 | { 246 | api.screen(gameData.rom, nes.screen); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/mode/Network.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import core.CorePlayerNetwork; 4 | import core.ICorePlayerHandler; 5 | 6 | import flash.events.Event; 7 | import flash.events.IOErrorEvent; 8 | import flash.events.KeyboardEvent; 9 | import flash.net.URLLoader; 10 | import flash.net.URLLoaderDataFormat; 11 | import flash.net.URLRequest; 12 | import flash.system.System; 13 | 14 | import model.Gamepad; 15 | 16 | import network.INetworkSessionHandler; 17 | import network.NetworkSession; 18 | 19 | import ui.Actions; 20 | import ui.ActionsMode; 21 | import ui.IBaseSetup; 22 | import ui.ISetupHandler; 23 | import ui.Message; 24 | import ui.Setup; 25 | import ui.SetupBuilder; 26 | 27 | public class Network extends Base 28 | implements 29 | ICorePlayerHandler, 30 | INetworkSessionHandler, 31 | ISetupHandler 32 | { 33 | private var nes:CorePlayerNetwork; 34 | private var actions:Actions; 35 | private var setup:IBaseSetup; 36 | private var message:Message; 37 | private var session:NetworkSession; 38 | 39 | public function Network(gameData:GameData) 40 | { 41 | super(gameData); 42 | 43 | nes = new CorePlayerNetwork(gameData.core, this); 44 | actions = new Actions(this, ActionsMode.Network); 45 | setup = SetupBuilder.Make(this, gameData); 46 | message = new Message; 47 | session = new NetworkSession(this); 48 | 49 | actions.muted = nes.muted = settings.muted; 50 | actions.visible = false; 51 | actions.enableFullscreen = Tools.isInteractiveFullscreenSupported(); 52 | } 53 | 54 | protected override function init():void 55 | { 56 | addChild(nes); 57 | addChild(actions); 58 | addChild(setup.sprite); 59 | addChild(message); 60 | 61 | super.init(); 62 | } 63 | 64 | protected override function startActionsShow():void 65 | { 66 | super.showActions(actions); 67 | } 68 | 69 | protected override function stopActionsShow():void 70 | { 71 | super.hideActions(actions); 72 | } 73 | 74 | protected override function resume():void 75 | { 76 | super.resume(); 77 | 78 | if(!setup.visible 79 | && !message.visible) 80 | { 81 | nes.play(); 82 | } 83 | } 84 | 85 | protected override function pauseEmulation():void 86 | { 87 | nes.pause(); 88 | } 89 | 90 | protected override function resumeEmulation():void 91 | { 92 | nes.play(); 93 | } 94 | 95 | // protected override function updateGamepadCodes(codes:Array):void 96 | // { 97 | // nes.updateGamepadCodes(codes); 98 | // } 99 | 100 | protected override function enableFullscreen(enable:Boolean):void 101 | { 102 | actions.enableFullscreen = enable; 103 | } 104 | 105 | // protected override function enableGamepad(enable:Boolean):void 106 | // { 107 | // actions.enableGamepad = enable; 108 | // } 109 | 110 | private function checkArena():void 111 | { 112 | if(gameData.value && gameData.value.length == 64) 113 | { 114 | message.show('

'+locale.waiting_for_connection +'...



' + 115 | locale.sprintf(locale.if_you_cannot_connect, 'http://cc.rtmfp.net')+'

'); 116 | 117 | session.connect(gameData.value); 118 | } 119 | else 120 | { 121 | message.show('

'+locale.connecting_to_server+'...

'); 122 | session.connect(); 123 | } 124 | } 125 | 126 | 127 | public override function onActionsMute():void 128 | { 129 | nes.muted = !nes.muted; 130 | settings.muted = nes.muted; 131 | actions.muted = nes.muted; 132 | } 133 | 134 | public override function onActionsSetup():void 135 | { 136 | nes.pause(); 137 | setup.show(settings.keyboard); 138 | } 139 | 140 | public override function onActionsUpload():void {} 141 | 142 | public function onSetupSave(joystick:Gamepad):void 143 | { 144 | settings.keyboard = joystick; 145 | nes.updateKeyCodes(joystick.codes); 146 | nes.play(); 147 | setup.visible = false; 148 | } 149 | 150 | public function onSetupCancel():void 151 | { 152 | nes.play(); 153 | setup.visible = false; 154 | } 155 | 156 | protected override function start():void 157 | { 158 | nes.updateKeyCodes(settings.keyboard.codes); 159 | nes.play(); 160 | 161 | checkArena(); 162 | } 163 | 164 | public function sendInput(input:uint):void 165 | { 166 | session.sendInput(input); 167 | } 168 | 169 | public function sendDummy():void 170 | { 171 | session.sendDummy(); 172 | } 173 | 174 | public function onNetworkPeer(value:String):void 175 | { 176 | if(!gameData.value || gameData.value.length != 64) 177 | { 178 | gameData.value = value; 179 | 180 | var arenaUrl:String = 181 | [ 182 | gameData.domain, 183 | (gameData.locale == 'en' ? '' : '/' + gameData.locale), 184 | '/game/', gameData.system, 185 | '/', gameData.game, 186 | '/rom/', gameData.rom, 187 | '#arena=', gameData.value 188 | ].join(''); 189 | 190 | Tools.shortLink(arenaUrl, function(shortUrl:String):void 191 | { 192 | if(shortUrl) 193 | { 194 | var callbacks:Object = 195 | { 196 | clipboard:function():void 197 | { 198 | System.setClipboard(shortUrl); 199 | 200 | message.show('

'+locale.new_send_copied_url+'

' + 201 | locale.waiting_for_connection+'...

' + 202 | locale.sprintf(locale.also_you_can_find_partner, '
'+locale.public_chat+'')+'

' + 203 | locale.sprintf(locale.if_you_cannot_connect, 'cc.rtmfp.net')+'

'); 204 | } 205 | }; 206 | 207 | message.show('

'+locale.connected_to_server+'...

' + 208 | locale.remote_url+': ' + shortUrl + '

' + 209 | '' + 210 | locale.click_here_to_copy_url_to_clipboard+',

' + 211 | locale.then_send_it_to_friend+'...

', callbacks); 212 | } 213 | else 214 | { 215 | message.show('

'+locale.connection_error+'

'); 216 | } 217 | }); 218 | } 219 | } 220 | 221 | public function onNetworkInput(input:uint):void 222 | { 223 | nes.recvInputValue(input); 224 | } 225 | 226 | public function onNetworkTest():void 227 | { 228 | message.show('

'+locale.testing_connection+'...

'); 229 | 230 | session.test(); 231 | } 232 | 233 | public function onNetworkStart(isFirstPeer:Boolean, ping:uint):void 234 | { 235 | var callbacks:Object = 236 | { 237 | ok:function():void 238 | { 239 | message.hide(); 240 | nes.play(); 241 | 242 | if(!Focus.activated) 243 | { 244 | pause(); 245 | } 246 | 247 | nes.updateKeyCodes(settings.keyboard.codes); 248 | nes.initNetworkEmulation(gameData.ntsc, isFirstPeer, gameData.data, gameData.region); 249 | } 250 | }; 251 | 252 | if(ping < 100) 253 | callbacks.ok(); 254 | else 255 | message.show('

'+locale.sprintf(locale.ping_is, ping) +'
' + 256 | locale.the_game_will_be_uncomfortable + '

' + 257 | 'OK

', callbacks); 258 | } 259 | 260 | protected override function onScreenShot():void 261 | { 262 | api.screen(gameData.rom, nes.screen); 263 | } 264 | } 265 | } -------------------------------------------------------------------------------- /src/mode/Own.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import core.CorePlayerSingle; 4 | 5 | import flash.events.Event; 6 | import flash.events.KeyboardEvent; 7 | import flash.net.FileFilter; 8 | import flash.net.FileReference; 9 | import flash.utils.ByteArray; 10 | 11 | import model.Gamepad; 12 | 13 | import ui.Actions; 14 | import ui.ActionsMode; 15 | import ui.IBaseSetup; 16 | import ui.ISetupHandler; 17 | import ui.Message; 18 | import ui.Setup; 19 | import ui.SetupBuilder; 20 | 21 | public class Own extends Base 22 | implements 23 | ISetupHandler 24 | { 25 | private var nes:CorePlayerSingle; 26 | private var setup:IBaseSetup; 27 | private var message:Message; 28 | private var actions:Actions; 29 | private var state:EmulatorState; 30 | 31 | private var lastState:ByteArray; 32 | 33 | public function Own(gameData:GameData) 34 | { 35 | super(gameData); 36 | 37 | nes = new CorePlayerSingle(gameData.core, this); 38 | actions = new Actions(this, ActionsMode.Custom); 39 | setup = SetupBuilder.Make(this, gameData); 40 | message = new Message(); 41 | 42 | actions.muted = nes.muted = settings.muted; 43 | actions.visible = false; 44 | actions.enableFullscreen = Tools.isInteractiveFullscreenSupported(); 45 | } 46 | 47 | protected override function init():void 48 | { 49 | addChild(nes); 50 | addChild(actions); 51 | addChild(setup.sprite); 52 | addChild(message); 53 | 54 | state = EmulatorState.Playing; 55 | 56 | super.init(); 57 | } 58 | 59 | protected override function startActionsShow():void 60 | { 61 | super.showActions(actions); 62 | } 63 | 64 | protected override function stopActionsShow():void 65 | { 66 | super.hideActions(actions); 67 | } 68 | 69 | protected override function resume():void 70 | { 71 | super.resume(); 72 | 73 | if(!setup.visible 74 | && !message.visible) 75 | { 76 | nes.play(); 77 | } 78 | } 79 | 80 | protected override function pause():void 81 | { 82 | if(!setup.visible 83 | && !message.visible) 84 | { 85 | super.pause(); 86 | nes.pause(); 87 | } 88 | } 89 | 90 | protected override function pauseEmulation():void 91 | { 92 | nes.pause(); 93 | } 94 | 95 | protected override function resumeEmulation():void 96 | { 97 | nes.play(); 98 | } 99 | 100 | // protected override function updateGamepadCodes(codes:Array):void 101 | // { 102 | // nes.updateGamepadCodes(codes); 103 | // } 104 | 105 | protected override function enableFullscreen(enable:Boolean):void 106 | { 107 | actions.enableFullscreen = enable; 108 | } 109 | 110 | // protected override function enableGamepad(enable:Boolean):void 111 | // { 112 | // actions.enableGamepad = enable; 113 | // } 114 | 115 | private function loadState():void 116 | { 117 | nes.pause(); 118 | 119 | message.show('

' + locale.loading_game + '...

'); 120 | 121 | var onComplete:Function = function():void 122 | { 123 | this.state = EmulatorState.Playing; 124 | nes.load(lastState); 125 | message.hide(); 126 | nes.play(); 127 | } 128 | 129 | if(lastState 130 | && lastState.length) 131 | { 132 | onComplete(); 133 | } 134 | else 135 | { 136 | var ref:FileReference = new FileReference(); 137 | ref.addEventListener(Event.CANCEL, function():void 138 | { 139 | this.state = EmulatorState.Playing; 140 | message.hide(); 141 | nes.play(); 142 | }); 143 | ref.addEventListener(Event.COMPLETE, function():void 144 | { 145 | lastState = ref.data; 146 | onComplete(); 147 | }); 148 | ref.addEventListener(Event.SELECT, function():void 149 | { 150 | ref.load(); 151 | }); 152 | ref.browse([new FileFilter('Saved files', '*.save')]); 153 | } 154 | } 155 | 156 | private function saveState():void 157 | { 158 | var data:ByteArray = nes.save(); 159 | 160 | if(data && data.bytesAvailable) 161 | { 162 | nes.pause(); 163 | message.show('

' + locale.saving_game + '...

'); 164 | 165 | var onComplete:Function = function():void 166 | { 167 | this.state = EmulatorState.Playing; 168 | message.hide(); 169 | nes.play(); 170 | } 171 | 172 | var ref:FileReference = new FileReference(); 173 | ref.addEventListener(Event.CANCEL, function():void 174 | { 175 | onComplete(); 176 | }); 177 | ref.addEventListener(Event.COMPLETE, function():void 178 | { 179 | lastState = data; 180 | onComplete(); 181 | }); 182 | ref.save(data, gameData.rom + '.save'); 183 | } 184 | } 185 | 186 | private function initSaveLoadShortcuts():void 187 | { 188 | stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void 189 | { 190 | switch(event.keyCode) 191 | { 192 | case SaveHotkeyCode: 193 | onActionsLoad(); 194 | break; 195 | case LoadHotkeyCode: 196 | onActionsSave(); 197 | break; 198 | } 199 | }); 200 | } 201 | 202 | public function onSetupSave(joystick:Gamepad):void 203 | { 204 | settings.keyboard = joystick; 205 | nes.updateKeyCodes(joystick.codes); 206 | nes.play(); 207 | setup.visible = false; 208 | } 209 | 210 | public function onSetupCancel():void 211 | { 212 | nes.play(); 213 | setup.visible = false; 214 | } 215 | 216 | protected override function start():void 217 | { 218 | nes.updateKeyCodes(settings.keyboard.codes); 219 | 220 | initSaveLoadShortcuts(); 221 | nes.initSingleEmulation(gameData.ntsc, gameData.data, gameData.region); 222 | 223 | Focus.activated ? resume() : pause(); 224 | } 225 | 226 | public override function onActionsMute():void 227 | { 228 | nes.muted = !nes.muted; 229 | settings.muted = nes.muted; 230 | actions.muted = nes.muted; 231 | } 232 | 233 | public override function onActionsLoad():void 234 | { 235 | loadState(); 236 | } 237 | 238 | public override function onActionsSave():void 239 | { 240 | state = EmulatorState.Saving; 241 | saveState(); 242 | } 243 | 244 | public override function onActionsSetup():void 245 | { 246 | nes.pause(); 247 | setup.show(settings.keyboard); 248 | } 249 | 250 | protected override function onScreenShot():void 251 | { 252 | api.screen(gameData.rom, nes.screen); 253 | } 254 | 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/mode/OwnServer.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import com.hurlant.util.Base64; 4 | 5 | import core.CorePlayerOwnServer; 6 | import core.ICorePlayerHandler; 7 | 8 | import flash.system.System; 9 | 10 | import model.Gamepad; 11 | import model.ServerSettings; 12 | 13 | import network.IOwnServerSessionHandler; 14 | import network.OwnServerSession; 15 | 16 | import ui.Actions; 17 | import ui.ActionsMode; 18 | import ui.IBaseSetup; 19 | import ui.IOwnServerSetupHandler; 20 | import ui.ISetupHandler; 21 | import ui.Message; 22 | import ui.OwnServerSetup; 23 | import ui.Setup; 24 | import ui.SetupBuilder; 25 | 26 | public class OwnServer extends Base 27 | implements 28 | ICorePlayerHandler, 29 | IOwnServerSessionHandler, 30 | ISetupHandler, 31 | IOwnServerSetupHandler 32 | { 33 | private var nes:CorePlayerOwnServer; 34 | private var actions:Actions; 35 | private var setup:IBaseSetup; 36 | private var message:Message; 37 | private var session:OwnServerSession; 38 | private var ownServerSetup:OwnServerSetup; 39 | private var isFirstPeer:Boolean; 40 | 41 | public function OwnServer(gameData:GameData) 42 | { 43 | super(gameData); 44 | 45 | nes = new CorePlayerOwnServer(gameData.core, this); 46 | actions = new Actions(this, ActionsMode.Network); 47 | setup = SetupBuilder.Make(this, gameData); 48 | message = new Message(); 49 | session = new OwnServerSession(this); 50 | ownServerSetup = new OwnServerSetup(this); 51 | 52 | actions.muted = nes.muted = settings.muted; 53 | actions.visible = false; 54 | actions.enableFullscreen = Tools.isInteractiveFullscreenSupported(); 55 | } 56 | 57 | protected override function init():void 58 | { 59 | addChild(nes); 60 | addChild(actions); 61 | addChild(setup.sprite); 62 | addChild(message); 63 | addChild(ownServerSetup); 64 | 65 | super.init(); 66 | } 67 | 68 | protected override function startActionsShow():void 69 | { 70 | super.showActions(actions); 71 | } 72 | 73 | protected override function stopActionsShow():void 74 | { 75 | super.hideActions(actions); 76 | } 77 | 78 | protected override function resume():void 79 | { 80 | super.resume(); 81 | 82 | if(!setup.visible 83 | && !message.visible) 84 | { 85 | nes.play(); 86 | } 87 | } 88 | 89 | protected override function pauseEmulation():void 90 | { 91 | nes.pause(); 92 | } 93 | 94 | protected override function resumeEmulation():void 95 | { 96 | nes.play(); 97 | } 98 | 99 | protected override function enableFullscreen(enable:Boolean):void 100 | { 101 | actions.enableFullscreen = enable; 102 | } 103 | 104 | private function checkRoom():void 105 | { 106 | if(gameData.value && gameData.value.length > 0) 107 | { 108 | var data:Object = JSON.parse(Base64.decode(gameData.value)); 109 | 110 | if(data && data.ip && data.port) 111 | { 112 | if(data.room) 113 | { 114 | isFirstPeer = false; 115 | 116 | message.show('

'+locale.waiting_for_connection +'...

'); 117 | 118 | session.connect(data.ip, data.port, data.room); 119 | } 120 | else 121 | { 122 | isFirstPeer = true; 123 | var serverSettings:ServerSettings = new ServerSettings(data.ip, data.port, 0); 124 | ownServerSetup.show(serverSettings); 125 | } 126 | } 127 | else 128 | { 129 | onOwnServerError(); 130 | } 131 | } 132 | else 133 | { 134 | isFirstPeer = true; 135 | 136 | ownServerSetup.show(settings.server); 137 | } 138 | } 139 | 140 | public override function onActionsMute():void 141 | { 142 | nes.muted = !nes.muted; 143 | settings.muted = nes.muted; 144 | actions.muted = nes.muted; 145 | } 146 | 147 | public override function onActionsSetup():void 148 | { 149 | nes.pause(); 150 | setup.show(settings.keyboard); 151 | } 152 | 153 | public override function onActionsUpload():void {} 154 | 155 | public function onSetupSave(joystick:Gamepad):void 156 | { 157 | settings.keyboard = joystick; 158 | nes.updateKeyCodes(joystick.codes); 159 | nes.play(); 160 | setup.visible = false; 161 | } 162 | 163 | public function onSetupCancel():void 164 | { 165 | nes.play(); 166 | setup.visible = false; 167 | } 168 | 169 | protected override function start():void 170 | { 171 | nes.updateKeyCodes(settings.keyboard.codes); 172 | nes.play(); 173 | 174 | checkRoom(); 175 | } 176 | 177 | public function sendInput(input:uint):void 178 | { 179 | session.sendInput(input); 180 | } 181 | 182 | public function sendDummy():void {} 183 | 184 | public function onOwnServerConnected(ip:String, port:int, room:String, frameskip:int):void 185 | { 186 | if(isFirstPeer) 187 | { 188 | var value:String = Base64.encode(JSON.stringify( 189 | { 190 | ip:ip, 191 | port:port, 192 | room:room 193 | })); 194 | 195 | var roomUrl:String = 196 | [ 197 | gameData.domain, 198 | (gameData.locale == 'en' ? '' : '/' + gameData.locale), 199 | '/game/', gameData.system, 200 | '/', gameData.game, 201 | '/rom/', gameData.rom, 202 | '#room=', value 203 | ].join(''); 204 | 205 | Tools.shortLink(roomUrl, function(shortUrl:String):void 206 | { 207 | if(shortUrl) 208 | { 209 | var callbacks:Object = 210 | { 211 | clipboard:function():void 212 | { 213 | System.setClipboard(shortUrl); 214 | 215 | message.show('

'+locale.new_send_copied_url+'

' + 216 | locale.waiting_for_connection+'...

'); 217 | 218 | startPlaying(frameskip); 219 | } 220 | }; 221 | 222 | message.show('

'+locale.you_are_connected+'.

' + 223 | locale.remote_url_is+': '+shortUrl+'.



' + 224 | ''+locale.click_here_to_copy_url_to_clipboard+'

' + 225 | locale.and_send_to_friend+'.

', callbacks); 226 | } 227 | else 228 | { 229 | message.show('

'+locale.connection_error+'

'); 230 | } 231 | }); 232 | } 233 | else 234 | { 235 | startPlaying(frameskip); 236 | } 237 | } 238 | 239 | private function startPlaying(frameskip:int):void 240 | { 241 | nes.play(); 242 | nes.updateKeyCodes(settings.keyboard.codes); 243 | nes.initNetworkEmulation(gameData.ntsc, gameData.data, gameData.region, frameskip); 244 | } 245 | 246 | public function onOwnServerDisconnected():void 247 | { 248 | nes.pause(); 249 | message.show('

'+locale.connection_has_closed+'!

'); 250 | } 251 | 252 | public function onOwnServerError():void 253 | { 254 | var callbacks:Object = 255 | { 256 | again:function():void 257 | { 258 | ownServerSetup.show(settings.server); 259 | } 260 | }; 261 | 262 | message.show('

'+locale.server_connection_error+',
' + 263 | locale.make_sure_entered_correct_ip+'.' + 264 | '



' + 265 | ''+locale.try_again.toUpperCase()+'

', callbacks); 266 | } 267 | 268 | protected override function onScreenShot():void 269 | { 270 | api.screen(gameData.rom, nes.screen); 271 | } 272 | 273 | public function onOwnServerSetupConnect(serverSettings:ServerSettings):void 274 | { 275 | ownServerSetup.visible = false; 276 | 277 | message.show('

'+locale.waiting_for_connection +'...

'); 278 | 279 | settings.server = serverSettings; 280 | 281 | session.connect(serverSettings.ip 282 | , serverSettings.port 283 | , null 284 | , serverSettings.frameskip); 285 | } 286 | 287 | public function onOwnServerInput(input:uint):void 288 | { 289 | if(message.visible) 290 | message.hide(); 291 | 292 | nes.recvInputValue(input); 293 | } 294 | } 295 | } -------------------------------------------------------------------------------- /src/mode/Single.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import com.adobe.images.PNGEncoder; 4 | 5 | import core.CorePlayerSingle; 6 | 7 | import flash.display.BitmapData; 8 | import flash.events.KeyboardEvent; 9 | import flash.geom.Matrix; 10 | import flash.geom.Point; 11 | import flash.geom.Rectangle; 12 | import flash.utils.ByteArray; 13 | 14 | import model.Gamepad; 15 | 16 | import ui.Actions; 17 | import ui.ActionsMode; 18 | import ui.IBaseSetup; 19 | import ui.ISetupHandler; 20 | import ui.Message; 21 | import ui.Setup; 22 | import ui.SetupBuilder; 23 | 24 | public class Single extends Base 25 | implements 26 | ISetupHandler 27 | { 28 | private var nes:CorePlayerSingle; 29 | private var setup:IBaseSetup; 30 | private var message:Message; 31 | private var actions:Actions; 32 | private var state:EmulatorState; 33 | 34 | private var lastState:ByteArray; 35 | 36 | public function Single(gameData:GameData) 37 | { 38 | super(gameData); 39 | 40 | nes = new CorePlayerSingle(gameData.core, this); 41 | actions = new Actions(this, ActionsMode.Single); 42 | setup = SetupBuilder.Make(this, gameData); 43 | message = new Message(); 44 | 45 | actions.muted = nes.muted = settings.muted; 46 | actions.visible = false; 47 | actions.loadActive = false; 48 | actions.enableFullscreen = Tools.isInteractiveFullscreenSupported(); 49 | actions.favoriteActive = false; 50 | } 51 | 52 | protected override function init():void 53 | { 54 | addChild(nes); 55 | addChild(actions); 56 | addChild(setup.sprite); 57 | addChild(message); 58 | 59 | state = EmulatorState.Playing; 60 | 61 | super.init(); 62 | } 63 | 64 | protected override function startActionsShow():void 65 | { 66 | super.showActions(actions); 67 | } 68 | 69 | protected override function stopActionsShow():void 70 | { 71 | super.hideActions(actions); 72 | } 73 | 74 | protected override function resume():void 75 | { 76 | super.resume(); 77 | 78 | if(!setup.sprite.visible 79 | && !message.visible) 80 | { 81 | nes.play(); 82 | } 83 | } 84 | 85 | protected override function pause():void 86 | { 87 | if(!setup.sprite.visible 88 | && !message.visible) 89 | { 90 | super.pause(); 91 | nes.pause(); 92 | } 93 | } 94 | 95 | protected override function pauseEmulation():void 96 | { 97 | nes.pause(); 98 | } 99 | 100 | protected override function resumeEmulation():void 101 | { 102 | nes.play(); 103 | } 104 | 105 | // protected override function updateGamepadCodes(codes:Array):void 106 | // { 107 | // nes.updateGamepadCodes(codes); 108 | // } 109 | 110 | protected override function enableFullscreen(enable:Boolean):void 111 | { 112 | actions.enableFullscreen = enable; 113 | } 114 | 115 | // protected override function enableGamepad(enable:Boolean):void 116 | // { 117 | // actions.enableGamepad = enable; 118 | // } 119 | 120 | private function loadState(saveId:String = null):void 121 | { 122 | nes.pause(); 123 | 124 | message.show('

' + locale.loading_game + '...

'); 125 | 126 | if(lastState 127 | && lastState.length) 128 | { 129 | onApiLoaded(lastState); 130 | } 131 | else 132 | { 133 | api.loadState(gameData.rom, saveId); 134 | } 135 | } 136 | 137 | private function saveState():void 138 | { 139 | nes.pause(); 140 | 141 | message.show('

'+locale.please_wait+'...

'); 142 | 143 | var data:ByteArray = nes.save(); 144 | 145 | if(data && data.bytesAvailable) 146 | { 147 | nes.pause(); 148 | message.show('

' + locale.saving_game + '...

'); 149 | 150 | api.save(gameData.rom, data, nes.screen); 151 | } 152 | } 153 | 154 | private function initSaveLoadShortcuts():void 155 | { 156 | stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void 157 | { 158 | switch(event.keyCode) 159 | { 160 | case SaveHotkeyCode: 161 | onActionsLoad(); 162 | break; 163 | case LoadHotkeyCode: 164 | onActionsSave(); 165 | // case 114: 166 | // onScreenShot(); 167 | // break; 168 | } 169 | }); 170 | } 171 | 172 | private function onSignIn():void 173 | { 174 | message.hide(); 175 | nes.pause(); 176 | JSProxy.showSignInModal(); 177 | } 178 | 179 | private function onSignUp():void 180 | { 181 | message.hide(); 182 | nes.pause(); 183 | JSProxy.showSignUpModal(); 184 | } 185 | 186 | public function onSetupSave(joystick:Gamepad):void 187 | { 188 | settings.keyboard = joystick; 189 | nes.updateKeyCodes(joystick.codes); 190 | nes.play(); 191 | setup.sprite.visible = false; 192 | } 193 | 194 | public function onSetupCancel():void 195 | { 196 | nes.play(); 197 | setup.sprite.visible = false; 198 | } 199 | 200 | protected override function start():void 201 | { 202 | nes.updateKeyCodes(settings.keyboard.codes); 203 | 204 | initSaveLoadShortcuts(); 205 | nes.initSingleEmulation(gameData.ntsc, gameData.data, gameData.region); 206 | 207 | if(gameData.value && gameData.value.length) 208 | { 209 | if(!Focus.activated) 210 | { 211 | pause(); 212 | } 213 | 214 | state = EmulatorState.Loading; 215 | message.show('

' + locale.loading_game + '

'); 216 | 217 | api.loadState(gameData.rom, gameData.value); 218 | } 219 | else 220 | { 221 | api.check(gameData.rom); 222 | } 223 | 224 | api.isFavorited(gameData.rom); 225 | } 226 | 227 | public override function onActionsFavorite():void 228 | { 229 | // api.favorite(gameData.rom, !actions.favorited); 230 | } 231 | 232 | public override function onActionsMute():void 233 | { 234 | nes.muted = !nes.muted; 235 | settings.muted = nes.muted; 236 | actions.muted = nes.muted; 237 | } 238 | 239 | public override function onActionsLoad():void 240 | { 241 | if(actions.loadActive) 242 | { 243 | var handlers:Object = 244 | { 245 | yes:function():void 246 | { 247 | message.hide(); 248 | state = EmulatorState.Loading; 249 | loadState(); 250 | }, 251 | no:function():void 252 | { 253 | message.hide(); 254 | nes.play(); 255 | } 256 | }; 257 | 258 | nes.pause(); 259 | message.show('

'+locale.do_you_want_to_load_state+'

'+ 260 | '' + 261 | locale.yes.toUpperCase() + ' ' + 262 | locale.or + ' ' + 263 | locale.no.toUpperCase() + '

', handlers); 264 | 265 | } 266 | } 267 | 268 | public override function onActionsSave():void 269 | { 270 | state = EmulatorState.Saving; 271 | saveState(); 272 | } 273 | 274 | public override function onActionsSetup():void 275 | { 276 | nes.pause(); 277 | setup.show(settings.keyboard); 278 | } 279 | 280 | public function onSigninCancel():void 281 | { 282 | message.hide(); 283 | nes.play(); 284 | } 285 | 286 | public override function onApiError(info:String):void 287 | { 288 | var callbacks:Object = 289 | { 290 | cancelsign:onSigninCancel 291 | }; 292 | 293 | message.show('

' + locale.error_occured + 294 | '

' + locale.close.toUpperCase() + 295 | '

', callbacks); 296 | } 297 | 298 | public override function onApiSaved(state:ByteArray):void 299 | { 300 | lastState = state; 301 | actions.loadActive = true; 302 | this.state = EmulatorState.Playing; 303 | message.hide(); 304 | nes.play(); 305 | } 306 | 307 | public override function onApiLoaded(state:ByteArray):void 308 | { 309 | this.state = EmulatorState.Playing; 310 | 311 | lastState = state; 312 | 313 | if(state && state.length) 314 | { 315 | nes.load(state); 316 | actions.loadActive = true; 317 | } 318 | else 319 | { 320 | actions.loadActive = false; 321 | } 322 | 323 | message.hide(); 324 | 325 | if(Focus.activated) 326 | { 327 | nes.play(); 328 | } 329 | } 330 | 331 | public override function onApiNeedSign():void 332 | { 333 | var callbacks:Object = 334 | { 335 | signin:onSignIn, 336 | signup:onSignUp, 337 | cancelsign:onSigninCancel 338 | }; 339 | 340 | message.show('

' + 341 | locale.you_need_to_be_signed_in_to_save + '

' + 342 | '' + locale.sign_in.toUpperCase()+' ' + 343 | locale.or + ' ' + 344 | locale.sign_up.toUpperCase() + '

' + 345 | ''+locale.cancel.toUpperCase()+'

', callbacks); 346 | } 347 | 348 | public override function onApiUserSigned(signed:Boolean):void 349 | { 350 | if(signed) 351 | { 352 | switch(state) 353 | { 354 | case EmulatorState.Loading: 355 | loadState(); 356 | break; 357 | case EmulatorState.Saving: 358 | saveState(); 359 | break; 360 | } 361 | 362 | nes.play(); 363 | } 364 | else 365 | { 366 | 367 | } 368 | } 369 | 370 | public override function onApiState(userLogined:Boolean, state:ByteArray):void 371 | { 372 | if(state && state.length) 373 | { 374 | actions.loadActive = true; 375 | lastState = state; 376 | 377 | var callbacks:Object = 378 | { 379 | yes:function():void 380 | { 381 | nes.load(lastState); 382 | nes.play(); 383 | message.hide(); 384 | }, 385 | 386 | no:function():void 387 | { 388 | message.hide(); 389 | nes.play(); 390 | } 391 | }; 392 | 393 | message.show('

'+locale.do_you_want_to_load_state + '

' + 394 | '' + 395 | locale.yes.toUpperCase() + ' ' + 396 | locale.or + ' ' + 397 | locale.no.toUpperCase() + '

', callbacks); 398 | } 399 | else 400 | { 401 | actions.loadActive = false; 402 | 403 | Focus.activated ? nes.play() : pause(); 404 | } 405 | } 406 | 407 | protected override function onScreenShot():void 408 | { 409 | api.screen(gameData.rom, nes.screen); 410 | } 411 | 412 | public override function onApiFavorited(value:Boolean):void 413 | { 414 | // actions.favoriteActive = true; 415 | // actions.favorited = value; 416 | } 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /src/mode/Walk.as: -------------------------------------------------------------------------------- 1 | package mode 2 | { 3 | import core.CorePlayerWalk; 4 | 5 | import flash.events.Event; 6 | import flash.utils.ByteArray; 7 | 8 | import server.IApiHandler; 9 | 10 | import ui.Actions; 11 | import ui.ActionsMode; 12 | import ui.IActionsHandler; 13 | import ui.Message; 14 | 15 | public class Walk extends Base implements IActionsHandler, IApiHandler 16 | { 17 | private var nes:CorePlayerWalk; 18 | private var actions:Actions; 19 | private var message:Message; 20 | 21 | private var frames:uint; 22 | 23 | public function Walk(gameData:GameData) 24 | { 25 | super(gameData); 26 | 27 | nes = new CorePlayerWalk(gameData.core, this); 28 | actions = new Actions(this, ActionsMode.Walk); 29 | message = new Message; 30 | 31 | actions.muted = nes.muted = settings.muted; 32 | actions.visible = false; 33 | } 34 | 35 | protected override function init():void 36 | { 37 | addChild(nes); 38 | addChild(actions); 39 | addChild(message); 40 | 41 | initActivateEngine(); 42 | 43 | nes.pause(); 44 | message.show('

'+locale.loading_walkthrough+'...

'); 45 | 46 | api.loadWalk(gameData.rom, gameData.value); 47 | } 48 | 49 | protected override function startActionsShow():void 50 | { 51 | super.showActions(actions); 52 | } 53 | 54 | protected override function stopActionsShow():void 55 | { 56 | super.hideActions(actions); 57 | } 58 | 59 | protected override function resume():void 60 | { 61 | super.resume(); 62 | 63 | if(!message.visible) 64 | { 65 | nes.play(); 66 | } 67 | } 68 | 69 | protected override function pause():void 70 | { 71 | if(!message.visible) 72 | { 73 | super.pause(); 74 | nes.pause(); 75 | } 76 | } 77 | 78 | public override function onActionsMute():void 79 | { 80 | nes.muted = !nes.muted; 81 | settings.muted = nes.muted; 82 | actions.muted = nes.muted; 83 | } 84 | 85 | public override function onApiError(info:String):void 86 | { 87 | var callbacks:Object = 88 | { 89 | close:function():void 90 | { 91 | nes.play(); 92 | } 93 | }; 94 | 95 | message.show('

Error occurred,
please, try again later...' + 96 | '

CLOSE

', callbacks); 97 | } 98 | 99 | public override function onApiLoaded(walk:ByteArray):void 100 | { 101 | if(walk) 102 | { 103 | walk.uncompress(); 104 | 105 | frames = walk.length >> 1; 106 | 107 | stage.addEventListener(Event.ENTER_FRAME, onUpdateTime); 108 | 109 | nes.initWalkEmulation(gameData.ntsc, walk, gameData.data, gameData.region); 110 | message.hide(); 111 | 112 | Focus.activated ? nes.play() : pause(); 113 | } 114 | } 115 | 116 | private function onUpdateTime(event:Event):void 117 | { 118 | if(nes.paused)return; 119 | 120 | var seconds:int = frames / stage.frameRate; 121 | var minutes:int = seconds / 60; 122 | var hours:int = minutes / 60; 123 | 124 | minutes -= hours*60; 125 | seconds -= hours*60*60 + minutes*60; 126 | 127 | actions.info = '

' + 128 | [ 129 | hours < 10 ? '0' + hours.toString() : hours 130 | , minutes < 10 ? '0' + minutes.toString() : minutes 131 | , seconds < 10 ? '0' + seconds.toString() : seconds 132 | ].join(':') + '

'; 133 | 134 | frames--; 135 | 136 | if(frames == 0) 137 | { 138 | stage.removeEventListener(Event.ENTER_FRAME, onUpdateTime); 139 | } 140 | } 141 | 142 | protected override function onScreenShot():void 143 | { 144 | api.screen(gameData.rom, nes.screen); 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /src/model/Gamepad.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | public class Gamepad 4 | { 5 | public var codes:Array; 6 | 7 | private var size:int; 8 | 9 | public function Gamepad(size:int) 10 | { 11 | this.size = size; 12 | codes = new Array(size); 13 | } 14 | 15 | public function get empty():Boolean 16 | { 17 | for(var index:int = 0; index < size; index++) 18 | if(!codes[index]) 19 | return true; 20 | 21 | return false; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/model/ServerSettings.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | public class ServerSettings 4 | { 5 | public var ip:String; 6 | public var port:int; 7 | public var frameskip:int; 8 | 9 | public function ServerSettings(ip:String, port:int, frameskip:int) 10 | { 11 | this.ip = ip; 12 | this.port = port; 13 | this.frameskip = frameskip; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/model/Settings.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import flash.net.SharedObject; 4 | 5 | public class Settings 6 | { 7 | private var settings:Object = 8 | { 9 | muted:false, 10 | keyboard:null, 11 | server:new ServerSettings('127.0.0.1', 8080, 3) 12 | }; 13 | 14 | private var sharedSettings:SharedObject; 15 | 16 | public function Settings(uid:String) 17 | { 18 | sharedSettings = SharedObject.getLocal(uid); 19 | 20 | var valid:Boolean = false; 21 | 22 | if(sharedSettings.data.settings) 23 | { 24 | valid = true; 25 | 26 | for(var key:String in settings) 27 | { 28 | if(!sharedSettings.data.settings.hasOwnProperty(key)) 29 | { 30 | valid = false; 31 | break; 32 | } 33 | } 34 | } 35 | 36 | if(valid) 37 | { 38 | for(var validKey:String in settings) 39 | { 40 | settings[validKey] = sharedSettings.data.settings[validKey]; 41 | } 42 | sharedSettings.data.settings = settings; 43 | } 44 | else 45 | { 46 | sharedSettings.data.settings = settings; 47 | sharedSettings.flush(); 48 | } 49 | } 50 | 51 | public function get muted():Boolean 52 | { 53 | return settings.muted; 54 | } 55 | 56 | public function set muted(value:Boolean):void 57 | { 58 | settings.muted = value; 59 | sharedSettings.flush(); 60 | } 61 | 62 | public function get keyboard():Gamepad 63 | { 64 | if(settings.keyboard && settings.keyboard as Array) 65 | { 66 | var gamepad:Gamepad = new Gamepad(settings.keyboard.length); 67 | gamepad.codes = settings.keyboard; 68 | return gamepad; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | public function set keyboard(value:Gamepad):void 75 | { 76 | if(value) 77 | { 78 | settings.keyboard = value.codes; 79 | sharedSettings.flush(); 80 | } 81 | } 82 | 83 | public function get server():ServerSettings 84 | { 85 | var serverSettings:ServerSettings = new ServerSettings(settings.server.ip, settings.server.port, settings.server.frameskip); 86 | 87 | return serverSettings; 88 | } 89 | 90 | public function set server(value:ServerSettings):void 91 | { 92 | settings.server = value; 93 | sharedSettings.flush(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/network/INetworkSessionHandler.as: -------------------------------------------------------------------------------- 1 | package network 2 | { 3 | public interface INetworkSessionHandler 4 | { 5 | function onNetworkPeer(value:String):void; 6 | function onNetworkInput(value:uint):void; 7 | function onNetworkTest():void; 8 | function onNetworkStart(isFirstPeer:Boolean, ping:uint):void; 9 | } 10 | } -------------------------------------------------------------------------------- /src/network/IOwnServerSessionHandler.as: -------------------------------------------------------------------------------- 1 | package network 2 | { 3 | public interface IOwnServerSessionHandler 4 | { 5 | function onOwnServerConnected(ip:String, port:int, room:String, frameskip:int):void; 6 | function onOwnServerDisconnected():void; 7 | function onOwnServerError():void; 8 | function onOwnServerInput(input:uint):void; 9 | } 10 | } -------------------------------------------------------------------------------- /src/network/NetworkSession.as: -------------------------------------------------------------------------------- 1 | package network 2 | { 3 | import flash.events.NetStatusEvent; 4 | import flash.net.NetConnection; 5 | import flash.net.NetStream; 6 | import flash.utils.getTimer; 7 | 8 | public class NetworkSession 9 | { 10 | private static const ServerAddress:String = 'rtmfp://p2p.rtmfp.net'; 11 | private static const DeveloperKey:String = '48faff0c77b9daf283b09c73-c7547fd7f58f'; 12 | private static const PublisherType:String = 'snesbox'; 13 | private static const TestIterations:uint = 100; 14 | 15 | private var nc:NetConnection; 16 | 17 | private var myPeerId:String; 18 | private var farPeerId:String; 19 | 20 | private var sendStream:NetStream; 21 | private var recvStream:NetStream; 22 | 23 | private var sendStreamStarted:Boolean; 24 | private var recvStreamStarted:Boolean; 25 | private var isFirstPeer:Boolean; 26 | 27 | public var handler:INetworkSessionHandler; 28 | 29 | public function NetworkSession(handler:INetworkSessionHandler) 30 | { 31 | this.handler = handler; 32 | 33 | nc = new NetConnection(); 34 | 35 | var client:Object = {}; 36 | client.onRelay = function(id:String):void 37 | { 38 | if (!farPeerId || !farPeerId.length) 39 | { 40 | farPeerId = id; 41 | initStreams(); 42 | } 43 | }; 44 | 45 | nc.client = client; 46 | 47 | nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus) 48 | } 49 | 50 | public function connect(farPeerId:String = ''):void 51 | { 52 | this.farPeerId = farPeerId; 53 | 54 | nc.connect(ServerAddress, DeveloperKey); 55 | } 56 | 57 | private function onNetStatus(event:NetStatusEvent):void 58 | { 59 | switch(event.info.code) 60 | { 61 | case 'NetConnection.Connect.Success': 62 | { 63 | if (!myPeerId) 64 | { 65 | myPeerId = nc.nearID; 66 | 67 | handler.onNetworkPeer(myPeerId); 68 | 69 | var isSecondPeer:Boolean = farPeerId && farPeerId.length == 64; 70 | 71 | isFirstPeer = !isSecondPeer; 72 | 73 | if (isSecondPeer) 74 | { 75 | nc.call('relay', null, farPeerId); 76 | initStreams(); 77 | } 78 | } 79 | } 80 | break; 81 | 82 | case 'NetStream.Connect.Success': 83 | break; 84 | case 'NetStream.Connect.Closed': 85 | break; 86 | } 87 | } 88 | 89 | private function initStreams():void 90 | { 91 | sendStream = new NetStream(nc, NetStream.DIRECT_CONNECTIONS); 92 | sendStream.addEventListener(NetStatusEvent.NET_STATUS, sendStreamStatusHandler); 93 | sendStream.publish(PublisherType); 94 | 95 | recvStream = new NetStream(nc, farPeerId); 96 | recvStream.addEventListener(NetStatusEvent.NET_STATUS, recvStreamStatusHandler); 97 | recvStream.play(PublisherType); 98 | 99 | var recvClient:Object = { }; 100 | var testIndex:uint = TestIterations; 101 | var totalPing:uint = 0; 102 | 103 | recvClient.i = function(value:uint):void 104 | { 105 | var input:uint = value & 0xffffff; 106 | 107 | handler.onNetworkInput(input); 108 | }; 109 | 110 | recvClient.d = function(value:uint):void {}; 111 | 112 | recvClient.ping = function(time:uint):void 113 | { 114 | sendStream.send('pong', time); 115 | } 116 | 117 | recvClient.pong = function(time:uint):void 118 | { 119 | var delta:uint = getTimer() - time; 120 | testIndex--; 121 | totalPing += delta; 122 | 123 | if(testIndex) 124 | { 125 | test(); 126 | } 127 | else 128 | { 129 | var ping:uint = totalPing / TestIterations; 130 | handler.onNetworkStart(isFirstPeer, ping); 131 | } 132 | } 133 | 134 | recvStream.client = recvClient; 135 | } 136 | 137 | private function sendStreamStatusHandler(event:NetStatusEvent):void 138 | { 139 | switch(event.info.code) 140 | { 141 | case 'NetStream.Play.Start': 142 | sendStreamStarted = true; 143 | break; 144 | } 145 | 146 | checkStart(); 147 | } 148 | 149 | private function recvStreamStatusHandler(event:NetStatusEvent):void 150 | { 151 | switch(event.info.code) 152 | { 153 | case 'NetStream.Play.Start': 154 | recvStreamStarted = true; 155 | break; 156 | } 157 | 158 | checkStart(); 159 | } 160 | 161 | private function checkStart():void 162 | { 163 | if (sendStreamStarted 164 | && recvStreamStarted) 165 | { 166 | sendStream.removeEventListener(NetStatusEvent.NET_STATUS, sendStreamStatusHandler); 167 | recvStream.removeEventListener(NetStatusEvent.NET_STATUS, recvStreamStatusHandler); 168 | 169 | handler.onNetworkTest(); 170 | } 171 | } 172 | 173 | public function sendInput(input:uint):void 174 | { 175 | sendStream.send('i', input); 176 | } 177 | 178 | public function sendDummy():void 179 | { 180 | sendStream.send('d', 555); 181 | } 182 | 183 | public function test():void 184 | { 185 | sendStream.send('ping', getTimer()); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/network/OwnServerSession.as: -------------------------------------------------------------------------------- 1 | package network 2 | { 3 | import flash.events.ErrorEvent; 4 | import flash.events.Event; 5 | import flash.events.IOErrorEvent; 6 | import flash.events.ProgressEvent; 7 | import flash.events.SecurityErrorEvent; 8 | import flash.net.Socket; 9 | 10 | public class OwnServerSession 11 | { 12 | private var socket:Socket; 13 | private var ip:String; 14 | private var port:int; 15 | private var room:String; 16 | private var frameskip:int; 17 | 18 | private var connected:Boolean; 19 | 20 | public var handler:IOwnServerSessionHandler; 21 | 22 | public function OwnServerSession(handler:IOwnServerSessionHandler) 23 | { 24 | this.handler = handler; 25 | 26 | connected = false; 27 | 28 | socket = new Socket(); 29 | 30 | socket.addEventListener(Event.CONNECT, onConnect); 31 | socket.addEventListener(Event.CLOSE, onDisconnect); 32 | socket.addEventListener(IOErrorEvent.IO_ERROR, onError); 33 | socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); 34 | 35 | socket.addEventListener(ProgressEvent.SOCKET_DATA, onData); 36 | } 37 | 38 | public function connect(ip:String, port:int, room:String, frameskip:int = 0):void 39 | { 40 | this.ip = ip; 41 | this.port = port; 42 | this.frameskip = frameskip; 43 | this.room = room; 44 | 45 | socket.connect(ip, port); 46 | } 47 | 48 | private function onConnect(event:Event):void 49 | { 50 | sendMessage( 51 | { 52 | type:'handshake', 53 | room:room, 54 | frameskip:frameskip 55 | }); 56 | } 57 | 58 | private function onData(event:ProgressEvent):void 59 | { 60 | if(connected) 61 | { 62 | var input:uint = socket.readUnsignedInt() & 0xffffff; 63 | handler.onOwnServerInput(input); 64 | } 65 | else 66 | { 67 | var data:String = socket.readUTFBytes(socket.bytesAvailable); 68 | var response:Object = JSON.parse(data); 69 | 70 | switch(response.type) 71 | { 72 | case 'handshake': 73 | { 74 | var room:String = response.room; 75 | 76 | frameskip = response.frameskip; 77 | 78 | if(room) 79 | { 80 | connected = true; 81 | handler.onOwnServerConnected(ip, port, room, frameskip); 82 | } 83 | 84 | break; 85 | } 86 | } 87 | } 88 | } 89 | 90 | private function onDisconnect(event:Event):void 91 | { 92 | handler.onOwnServerDisconnected(); 93 | } 94 | 95 | private function onError(event:ErrorEvent):void 96 | { 97 | handler.onOwnServerError(); 98 | } 99 | 100 | private function sendMessage(data:Object):void 101 | { 102 | socket.writeUTFBytes(JSON.stringify(data)); 103 | socket.flush(); 104 | } 105 | 106 | public function sendInput(input:uint):void 107 | { 108 | if(connected) 109 | { 110 | socket.writeUnsignedInt(input); 111 | socket.flush(); 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/server/Api.as: -------------------------------------------------------------------------------- 1 | package server 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | public class Api 6 | { 7 | public function Api(handler:IApiHandler, domain:String) {} 8 | public function isFavorited(rom:String):void {} 9 | public function favorite(rom:String, value:Boolean):void {} 10 | public function check(rom:String):void {} 11 | public function loadState(rom:String, user:String):void {} 12 | public function loadWalk(rom:String, user:String):void {} 13 | public function save(rom:String, state:ByteArray, screen:ByteArray):void {} 14 | public function uploadWalk(rom:String, walk:ByteArray):void {} 15 | public function screen(rom:String, screen:ByteArray):void {} 16 | } 17 | } -------------------------------------------------------------------------------- /src/server/IApiHandler.as: -------------------------------------------------------------------------------- 1 | package server 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | public interface IApiHandler 6 | { 7 | function onApiError(info:String):void; 8 | function onApiSaved(state:ByteArray):void; 9 | function onApiLoaded(state:ByteArray):void; 10 | function onApiNeedSign():void; 11 | function onApiUserSigned(signed:Boolean):void; 12 | function onApiState(userLogined:Boolean, state:ByteArray):void; 13 | function onApiUploaded():void; 14 | function onApiFavorited(value:Boolean):void; 15 | } 16 | } -------------------------------------------------------------------------------- /src/ui/ActionAsset.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | internal final class ActionAsset 4 | { 5 | [Embed(source='/assets/setup.png')] 6 | public static const SetupButton:Class; 7 | 8 | [Embed(source='/assets/mute.png')] 9 | public static const MuteButton:Class; 10 | 11 | [Embed(source='/assets/load.png')] 12 | public static const LoadButton:Class; 13 | 14 | [Embed(source='/assets/save.png')] 15 | public static const SaveButton:Class; 16 | 17 | [Embed(source='/assets/fullscreen.png')] 18 | public static const FullscreenButton:Class; 19 | 20 | [Embed(source='/assets/upload.png')] 21 | public static const UploadButton:Class; 22 | 23 | [Embed(source='/assets/gamepad.png')] 24 | public static const GamepadButton:Class; 25 | 26 | [Embed(source='/assets/favorite.png')] 27 | public static const FavoriteButton:Class; 28 | 29 | [Embed(source='/assets/facebook.png')] 30 | public static const FacebookButton:Class; 31 | 32 | [Embed(source='/assets/google.png')] 33 | public static const GoogleButton:Class; 34 | 35 | [Embed(source='/assets/twitter.png')] 36 | public static const TwitterButton:Class; 37 | 38 | [Embed(source='/assets/vkontakte.png')] 39 | public static const VkontakteButton:Class; 40 | 41 | [Embed(source='/assets/github.png')] 42 | public static const GithubButton:Class; 43 | 44 | } 45 | } -------------------------------------------------------------------------------- /src/ui/Actions.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.Sprite; 4 | 5 | public class Actions extends Sprite 6 | { 7 | private static const UpColor:uint = 0x000000; 8 | private static const OverColor:uint = 0xffffff; 9 | private static const ToggleColor:uint = 0x9b9b9b; 10 | private static const OffColor:uint = 0x777777; 11 | private static const BackColor:uint = 0x666666; 12 | 13 | private var handler:IActionsHandler; 14 | 15 | private const singleModeButtonsMap:Array = 16 | [ 17 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 18 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 19 | {name:'save', icon:ActionAsset.SaveButton, click:save}, 20 | {name:'load', icon:ActionAsset.LoadButton, click:load}, 21 | {name:'gamepad', icon:ActionAsset.GamepadButton, click:gamepad}, 22 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive} 23 | ]; 24 | 25 | private const ownModeButtonsMap:Array = 26 | [ 27 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 28 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 29 | {name:'save', icon:ActionAsset.SaveButton, click:save}, 30 | {name:'load', icon:ActionAsset.LoadButton, click:load}, 31 | {name:'gamepad', icon:ActionAsset.GamepadButton, click:gamepad}, 32 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive}, 33 | ]; 34 | 35 | private const networkModeButtonsMap:Array = 36 | [ 37 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 38 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 39 | {name:'gamepad', icon:ActionAsset.GamepadButton, click:gamepad}, 40 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive}, 41 | ]; 42 | 43 | private const walkModeButtonsMap:Array = 44 | [ 45 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 46 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreen}, 47 | ]; 48 | 49 | private const contestModeButtonsMap:Array = 50 | [ 51 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 52 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 53 | {name:'upload', icon:ActionAsset.UploadButton, click:upload}, 54 | {name:'gamepad', icon:ActionAsset.GamepadButton, click:gamepad}, 55 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive}, 56 | ]; 57 | 58 | private const socialSingleModeButtonsMap:Array = 59 | [ 60 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 61 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 62 | {name:'save', icon:ActionAsset.SaveButton, click:save}, 63 | {name:'load', icon:ActionAsset.LoadButton, click:load}, 64 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive}, 65 | ]; 66 | 67 | private const socialNetworkModeButtonsMap:Array = 68 | [ 69 | {name:'setup', icon:ActionAsset.SetupButton, click:setup}, 70 | {name:'mute', icon:ActionAsset.MuteButton, click:mute}, 71 | {name:'fullscreen', icon:ActionAsset.FullscreenButton, click:fullscreenInteractive}, 72 | ]; 73 | 74 | private const socialButtonsMap:Array = 75 | [ 76 | {name:'github', icon:ActionAsset.GithubButton, click:github}, 77 | ]; 78 | 79 | private var buttons:Array = []; 80 | private var loadActiveValue:Boolean = false; 81 | private var saveActiveValue:Boolean = false; 82 | private var favoriteValue:Boolean = false; 83 | private var favoriteActiveValue:Boolean = false; 84 | private var infoText:Text; 85 | 86 | public static const Height:uint = 16; 87 | 88 | public function Actions(handler:IActionsHandler, mode:ActionsMode) 89 | { 90 | this.handler = handler; 91 | 92 | graphics.beginFill(BackColor); 93 | graphics.drawRect(0, 0, Variables.Width, Height); 94 | graphics.endFill(); 95 | 96 | switch(mode) 97 | { 98 | case ActionsMode.Single: 99 | fillButtons(singleModeButtonsMap); 100 | break; 101 | case ActionsMode.Network: 102 | fillButtons(networkModeButtonsMap); 103 | break; 104 | case ActionsMode.Walk: 105 | fillButtons(walkModeButtonsMap); 106 | break; 107 | case ActionsMode.Contest: 108 | fillButtons(contestModeButtonsMap); 109 | break; 110 | case ActionsMode.SocialSingle: 111 | fillButtons(socialSingleModeButtonsMap); 112 | return; 113 | case ActionsMode.SocialNetwork: 114 | fillButtons(socialNetworkModeButtonsMap); 115 | return; 116 | case ActionsMode.Custom: 117 | fillButtons(ownModeButtonsMap); 118 | break; 119 | } 120 | 121 | fillSocialButtons(); 122 | } 123 | 124 | public function set info(value:String):void 125 | { 126 | if(!infoText) 127 | { 128 | infoText = new Text; 129 | addChild(infoText); 130 | } 131 | 132 | infoText.htmlText = value; 133 | infoText.x = (Variables.Width - infoText.width)/2; 134 | infoText.y = - 1; 135 | } 136 | 137 | private function fillSocialButtons():void 138 | { 139 | var offset:int = Variables.Width - socialButtonsMap.length*Height; 140 | for each(var item:Object in socialButtonsMap) 141 | { 142 | var button:Button = new Button(item.name, item.icon, item.click, 'share'); 143 | addChild(button).x = offset; 144 | offset += Height; 145 | 146 | buttons.push(button); 147 | } 148 | } 149 | 150 | private function fillButtons(map:Array):void 151 | { 152 | var offset:int = 0; 153 | for each(var item:Object in map) 154 | { 155 | var button:Button = new Button(item.name, item.icon, item.click, item.name); 156 | addChild(button).x = offset; 157 | offset += Height; 158 | 159 | buttons.push(button); 160 | } 161 | } 162 | 163 | private function mute():void 164 | { 165 | Analytics.trackActionMuteEvent(); 166 | handler.onActionsMute(); 167 | } 168 | 169 | private function fullscreen():void 170 | { 171 | Analytics.trackActionFullscreenEvent(); 172 | handler.onActionsFullscreen(); 173 | } 174 | 175 | private function fullscreenInteractive():void 176 | { 177 | Analytics.trackActionFullscreenEvent(); 178 | handler.onActionsFullscreenInteractive(); 179 | } 180 | 181 | public function set muted(value:Boolean):void 182 | { 183 | getButton('mute').upColor = value ? ToggleColor : UpColor; 184 | } 185 | 186 | private function load():void 187 | { 188 | Analytics.trackActionLoadEvent(); 189 | handler.onActionsLoad(); 190 | } 191 | 192 | private function save():void 193 | { 194 | Analytics.trackActionSaveEvent(); 195 | handler.onActionsSave(); 196 | } 197 | 198 | private function enableButton(name:String, value:Boolean):void 199 | { 200 | var button:Button = getButton(name); 201 | 202 | if(button) 203 | { 204 | button.enabled = value; 205 | button.upColor = value ? UpColor : OffColor; 206 | } 207 | } 208 | 209 | public function set enableFullscreen(value:Boolean):void 210 | { 211 | enableButton('fullscreen', value); 212 | } 213 | 214 | // public function set enableGamepad(value:Boolean):void 215 | // { 216 | // enableButton('gamepad', value); 217 | // } 218 | 219 | public function set loadActive(value:Boolean):void 220 | { 221 | enableButton('load', value); 222 | loadActiveValue = value; 223 | } 224 | 225 | public function get loadActive():Boolean 226 | { 227 | return loadActiveValue; 228 | } 229 | 230 | public function set saveActive(value:Boolean):void 231 | { 232 | enableButton('save', value); 233 | saveActiveValue = value; 234 | } 235 | 236 | public function get saveActive():Boolean 237 | { 238 | return saveActiveValue; 239 | } 240 | 241 | private function setup():void 242 | { 243 | Analytics.trackActionSetupEvent(); 244 | handler.onActionsSetup(); 245 | } 246 | 247 | private function getButton(name:String):Button 248 | { 249 | for each(var button:Button in buttons) 250 | { 251 | if(button.name == name) 252 | { 253 | return button; 254 | } 255 | } 256 | 257 | return null; 258 | } 259 | 260 | private function upload():void 261 | { 262 | Analytics.trackActionUploadEvent(); 263 | handler.onActionsUpload(); 264 | } 265 | 266 | private function facebook():void 267 | { 268 | Analytics.trackShareFacebookEvent(); 269 | handler.onActionsShareFacebook(); 270 | } 271 | 272 | private function google():void 273 | { 274 | Analytics.trackShareGoogleEvent(); 275 | handler.onActionsShareGoogle(); 276 | } 277 | 278 | private function twitter():void 279 | { 280 | Analytics.trackShareTwitterEvent(); 281 | handler.onActionsShareTwitter(); 282 | } 283 | 284 | private function vkontakte():void 285 | { 286 | Analytics.trackShareVkontakteEvent(); 287 | handler.onActionsShareVkontakte(); 288 | } 289 | 290 | private function github():void 291 | { 292 | handler.onActionsShareGithub(); 293 | } 294 | 295 | private function gamepad():void 296 | { 297 | Analytics.trackActionGamepadEvent(); 298 | handler.onActionsGamepad(); 299 | } 300 | 301 | private function favorite():void 302 | { 303 | Analytics.trackActionFavoriteEvent(); 304 | handler.onActionsFavorite(); 305 | } 306 | 307 | // public function get favorited():Boolean 308 | // { 309 | // return favoriteValue; 310 | // } 311 | // 312 | // public function set favorited(value:Boolean):void 313 | // { 314 | // getButton('favorite').upColor = value ? ToggleColor : UpColor; 315 | // favoriteValue = value; 316 | // } 317 | 318 | public function set favoriteActive(value:Boolean):void 319 | { 320 | enableButton('favorite', value); 321 | favoriteActiveValue = value; 322 | } 323 | 324 | public function get favoriteActive():Boolean 325 | { 326 | return favoriteActiveValue; 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /src/ui/ActionsMode.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | public final class ActionsMode 4 | { 5 | public static const Single:ActionsMode = new ActionsMode; 6 | public static const Custom:ActionsMode = new ActionsMode; 7 | public static const Network:ActionsMode = new ActionsMode; 8 | public static const Walk:ActionsMode = new ActionsMode; 9 | public static const Contest:ActionsMode = new ActionsMode; 10 | public static const SocialSingle:ActionsMode = new ActionsMode; 11 | public static const SocialNetwork:ActionsMode = new ActionsMode; 12 | } 13 | } -------------------------------------------------------------------------------- /src/ui/Button.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.SimpleButton; 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.events.MouseEvent; 8 | import flash.geom.ColorTransform; 9 | import flash.geom.Point; 10 | import flash.geom.Rectangle; 11 | import flash.utils.clearTimeout; 12 | import flash.utils.setTimeout; 13 | 14 | internal final class Button extends SimpleButton 15 | { 16 | private var index:int; 17 | private var upIcon:Bitmap; 18 | private var hintTimerId:uint; 19 | private var hintName:String; 20 | 21 | private static var hint:Text; 22 | 23 | public function Button(name:String, icon:Object, handler:Object, hintName:String, isAlpha:Boolean = false) 24 | { 25 | this.name = name; 26 | this.hintName = hintName; 27 | 28 | tabEnabled = false; 29 | 30 | var up:Sprite = new Sprite; 31 | var over:Sprite = new Sprite; 32 | 33 | upIcon = new icon; 34 | var overIcon:Bitmap = new icon; 35 | 36 | if(isAlpha) 37 | { 38 | overIcon.alpha = .8; 39 | } 40 | else 41 | { 42 | setStateColor(overIcon, 0xffffff); 43 | } 44 | 45 | up.addChild(upIcon); 46 | over.addChild(overIcon); 47 | 48 | super(up, over, up, up); 49 | 50 | addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void 51 | { 52 | hideHint(); 53 | 54 | if(handler != null && enabled) 55 | { 56 | handler(); 57 | } 58 | }); 59 | 60 | addEventListener(MouseEvent.MOUSE_OVER, function(event:MouseEvent):void 61 | { 62 | if(!hintTimerId) 63 | { 64 | hintTimerId = setTimeout(function():void 65 | { 66 | showHint(); 67 | hintTimerId = 0; 68 | }, 300); 69 | } 70 | }); 71 | 72 | addEventListener(MouseEvent.MOUSE_OUT, function(event:MouseEvent):void 73 | { 74 | hideHint(); 75 | }); 76 | 77 | addEventListener(Event.ADDED_TO_STAGE, function(event:Event):void 78 | { 79 | if(!hint) 80 | { 81 | hint = new Text('#000000'); 82 | hint.visible = false; 83 | hint.background = true; 84 | hint.backgroundColor = 0xffffff; 85 | 86 | parent.addChild(hint); 87 | } 88 | }); 89 | } 90 | 91 | private function showHint():void 92 | { 93 | hint.visible = true; 94 | 95 | hint.htmlText = '

' + Locale.instance['hint_' + hintName] + '

'; 96 | 97 | const HINT_GAP:int = 2; 98 | hint.x = int(x - (hint.width-16)/2); 99 | hint.y = -(hint.height + HINT_GAP); 100 | 101 | if(hint.x <= 0) 102 | { 103 | hint.x = HINT_GAP; 104 | } 105 | 106 | if(hint.x + hint.width > stage.stageWidth/2) 107 | { 108 | hint.x = stage.stageWidth/2 - hint.width - HINT_GAP; 109 | } 110 | 111 | } 112 | 113 | private function hideHint():void 114 | { 115 | hint.visible = false; 116 | hint.htmlText = ''; 117 | 118 | if(hintTimerId) 119 | { 120 | clearTimeout(hintTimerId); 121 | hintTimerId = 0; 122 | } 123 | } 124 | 125 | private static function setStateColor(stateIcon:Bitmap, color:uint):void 126 | { 127 | var transform:ColorTransform = new ColorTransform; 128 | 129 | transform.color = color; 130 | stateIcon.bitmapData.colorTransform(new Rectangle(0, 0, stateIcon.width, stateIcon.height), transform); 131 | } 132 | 133 | public function set upColor(value:uint):void 134 | { 135 | setStateColor(upIcon, value); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /src/ui/FullscreenMessage.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.events.Event; 4 | 5 | public class FullscreenMessage extends Message 6 | { 7 | public function FullscreenMessage() 8 | { 9 | super(); 10 | scale = 2; 11 | } 12 | 13 | protected override function onAddedToStage(event:Event):void 14 | { 15 | x = y = 0; 16 | alpha = .95; 17 | 18 | graphics.beginFill(0x666666); 19 | graphics.drawRect(0, 0, stage.fullScreenWidth, stage.fullScreenHeight); 20 | graphics.endFill(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ui/IActionsHandler.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | public interface IActionsHandler 4 | { 5 | function onActionsMute():void; 6 | function onActionsFullscreen():void; 7 | function onActionsFullscreenInteractive():void; 8 | function onActionsLoad():void; 9 | function onActionsSave():void; 10 | function onActionsSetup():void; 11 | function onActionsUpload():void; 12 | function onActionsGamepad():void; 13 | function onActionsFavorite():void; 14 | 15 | function onActionsShareFacebook():void; 16 | function onActionsShareGoogle():void; 17 | function onActionsShareTwitter():void; 18 | function onActionsShareVkontakte():void; 19 | function onActionsShareGithub():void; 20 | } 21 | } -------------------------------------------------------------------------------- /src/ui/IBaseSetup.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.DisplayObject; 4 | 5 | import model.Gamepad; 6 | 7 | public interface IBaseSetup 8 | { 9 | function show(gamepad:Gamepad):void; 10 | function get sprite():DisplayObject; 11 | function get visible():Boolean; 12 | function set visible(value:Boolean):void; 13 | } 14 | } -------------------------------------------------------------------------------- /src/ui/IOwnServerSetupHandler.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import model.ServerSettings; 4 | 5 | public interface IOwnServerSetupHandler 6 | { 7 | function onOwnServerSetupConnect(serverSettings:ServerSettings):void; 8 | } 9 | } -------------------------------------------------------------------------------- /src/ui/ISetupHandler.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import model.Gamepad; 4 | 5 | public interface ISetupHandler 6 | { 7 | function onSetupSave(joystick:Gamepad):void; 8 | function onSetupCancel():void; 9 | } 10 | } -------------------------------------------------------------------------------- /src/ui/ISignHandler.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | public interface ISignHandler 4 | { 5 | function onSignin(login:String, password:String):void; 6 | function onSignup(login:String, email:String, password:String):void; 7 | function onSigninCancel():void; 8 | } 9 | } -------------------------------------------------------------------------------- /src/ui/Keyboard.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | internal final class Keyboard 4 | { 5 | public static const Keys:Object = 6 | { 7 | '110' : 'numpad decimal' 8 | , '108' : 'numpad enter' 9 | , '111' : 'numpad divide' 10 | , '38' : 'up' 11 | , '117' : 'f6' 12 | , '191' : 'slash' 13 | , '107' : 'numpad add' 14 | , '105' : 'numpad 9' 15 | , '221' : 'rightbracket' 16 | , '116' : 'f5' 17 | , '21' : 'numpad' 18 | , '55' : 'number 7' 19 | , '97' : 'numpad 1' 20 | , '189' : 'minus' 21 | , '118' : 'f7' 22 | , '119' : 'f8' 23 | , '57' : 'number 9' 24 | , '120' : 'f9' 25 | , '9' : 'tab' 26 | , '35' : 'end' 27 | , '219' : 'leftbracket' 28 | , '36' : 'home' 29 | , '45' : 'insert' 30 | , '65' : 'a' 31 | , '70' : 'f' 32 | , '115' : 'f4' 33 | , '112' : 'f1' 34 | , '186' : 'semicolon' 35 | , '67' : 'c' 36 | , '102' : 'numpad 6' 37 | , '68' : 'd' 38 | , '66' : 'b' 39 | , '104' : 'numpad 8' 40 | , '69' : 'e' 41 | , '54' : 'number 6' 42 | , '75' : 'k' 43 | , '56' : 'number 8' 44 | , '190' : 'period' 45 | , '72' : 'h' 46 | , '222' : 'quote' 47 | , '73' : 'i' 48 | , '49' : 'number 1' 49 | , '101' : 'numpad 5' 50 | , '48' : 'number 0' 51 | , '79' : 'o' 52 | , '17' : 'control' 53 | , '33' : 'page up' 54 | , '76' : 'l' 55 | , '71' : 'g' 56 | , '74' : 'j' 57 | , '81' : 'q' 58 | , '77' : 'm' 59 | , '16' : 'shift' 60 | , '78' : 'n' 61 | , '125' : 'f14' 62 | , '83' : 's' 63 | , '126' : 'f15' 64 | , '84' : 't' 65 | , '80' : 'p' 66 | , '85' : 'u' 67 | , '114' : 'f3' 68 | , '86' : 'v' 69 | , '82' : 'r' 70 | , '27' : 'escape' 71 | , '53' : 'number 5' 72 | , '87' : 'w' 73 | , '52' : 'number 4' 74 | , '124' : 'f13' 75 | , '88' : 'x' 76 | , '32' : 'space' 77 | , '89' : 'y' 78 | , '113' : 'f2' 79 | , '121' : 'f10' 80 | , '90' : 'z' 81 | , '122' : 'f11' 82 | , '187' : 'equal' 83 | , '103' : 'numpad 7' 84 | , '13' : 'enter' 85 | , '123' : 'f12' 86 | , '39' : 'right' 87 | , '100' : 'numpad 4' 88 | , '37' : 'left' 89 | , '15' : 'command' 90 | , '8' : 'backspace' 91 | , '188' : 'comma' 92 | , '46' : 'delete' 93 | , '51' : 'number 3' 94 | , '106' : 'numpad multiply' 95 | , '220' : 'backslash' 96 | , '99' : 'numpad 3' 97 | , '20' : 'caps lock' 98 | , '96' : 'numpad 0' 99 | , '109' : 'numpad subtract' 100 | , '34' : 'page down' 101 | , '50' : 'number 2' 102 | , '40' : 'down' 103 | , '192' : 'backquote' 104 | , '18' : 'alternate' 105 | , '98' : 'numpad 2' 106 | }; 107 | } 108 | } -------------------------------------------------------------------------------- /src/ui/Message.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.Event; 5 | import flash.events.TextEvent; 6 | import flash.text.StyleSheet; 7 | import flash.text.TextFieldAutoSize; 8 | import flash.text.TextFormat; 9 | import flash.text.TextFormatAlign; 10 | 11 | public class Message extends Sprite 12 | { 13 | protected var scale:int = 1; 14 | 15 | public function Message() 16 | { 17 | visible = false; 18 | 19 | addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); 20 | } 21 | 22 | protected function onAddedToStage(event:Event):void 23 | { 24 | x = y = 0; 25 | alpha = .95; 26 | 27 | graphics.beginFill(0x666666); 28 | graphics.drawRect(0, 0, Variables.Width, Variables.Height); 29 | graphics.endFill(); 30 | } 31 | 32 | public function show(value:String, handler:Object = null):void 33 | { 34 | visible = value.length > 0; 35 | 36 | this.removeChildren(); 37 | 38 | const LINE_HEIGHT:int = 10; 39 | var parts:Array = value.split('
'); 40 | var vertPos:int = (height/scale - parts.length * LINE_HEIGHT) / 2; 41 | 42 | var onInfoLink:Function = function(event:TextEvent):void 43 | { 44 | if(handler && handler.hasOwnProperty(event.text)) 45 | { 46 | if(handler[event.text] is Function) 47 | { 48 | handler[event.text](); 49 | } 50 | } 51 | } 52 | 53 | for each(var part:String in parts) 54 | { 55 | part = part.split('

').join(''); 56 | part = part.split('

').join(''); 57 | 58 | var field:Text = new Text; 59 | field.multiline = true; 60 | field.autoSize = TextFieldAutoSize.NONE; 61 | field.wordWrap = true; 62 | 63 | var style:Object = field.styleSheet.getStyle('p'); 64 | style.textAlign = 'center'; 65 | field.styleSheet.setStyle('p', style); 66 | 67 | field.addEventListener(TextEvent.LINK, onInfoLink); 68 | field.htmlText = ['

', part, '

'].join(''); 69 | 70 | field.width = int((width-32)/scale); 71 | field.x = 16/scale; 72 | field.y = int(vertPos); 73 | 74 | vertPos += LINE_HEIGHT; 75 | 76 | addChild(field); 77 | } 78 | } 79 | 80 | public function hide():void 81 | { 82 | show(''); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/ui/OwnServerSetup.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.TextEvent; 5 | 6 | import model.ServerSettings; 7 | 8 | public class OwnServerSetup extends Sprite 9 | { 10 | private var title:Text; 11 | 12 | private var howToLabel:Text; 13 | 14 | private var ipLabel:Text; 15 | private var ipInput:TextInput; 16 | 17 | private var portLabel:Text; 18 | private var portInput:TextInput; 19 | 20 | private var frameskipLabel:Text; 21 | private var frameskipInput:TextInput; 22 | 23 | private var buttons:Text; 24 | 25 | private var handler:IOwnServerSetupHandler; 26 | 27 | private var locale:Locale; 28 | 29 | public function OwnServerSetup(handler:IOwnServerSetupHandler) 30 | { 31 | super(); 32 | 33 | locale = Locale.instance; 34 | 35 | this.handler = handler; 36 | 37 | visible = false; 38 | 39 | title = new Text; 40 | title.htmlText = '

'+locale.server_setup.toUpperCase()+'

'; 41 | addChild(title); 42 | 43 | howToLabel = new Text(); 44 | howToLabel.htmlText = '

' 45 | + locale.please_read 46 | + ': '+locale.how_start_own_server+'?

'; 47 | addChild(howToLabel); 48 | 49 | ipLabel = new Text; 50 | ipLabel.htmlText = '

IP:

'; 51 | addChild(ipLabel); 52 | 53 | portLabel = new Text; 54 | portLabel.htmlText = '

'+locale.server_port+':

'; 55 | addChild(portLabel); 56 | 57 | ipInput = new TextInput(); 58 | addChild(ipInput); 59 | 60 | portInput = new TextInput(); 61 | addChild(portInput); 62 | 63 | frameskipLabel = new Text; 64 | frameskipLabel.htmlText = '

'+locale.server_frameskip+':

'; 65 | addChild(frameskipLabel); 66 | 67 | frameskipInput = new TextInput(); 68 | addChild(frameskipInput); 69 | 70 | buttons = new Text(); 71 | buttons.htmlText = '

' + 72 | ''+locale.connect.toLocaleUpperCase()+'

'; 73 | buttons.addEventListener(TextEvent.LINK, onLink); 74 | addChild(buttons); 75 | } 76 | 77 | public function show(serverSettings:ServerSettings):void 78 | { 79 | ipInput.text = serverSettings.ip; 80 | portInput.text = serverSettings.port.toString(); 81 | frameskipInput.text = serverSettings.frameskip.toString(); 82 | 83 | update(); 84 | 85 | visible = true; 86 | } 87 | 88 | private function update():void 89 | { 90 | graphics.clear(); 91 | graphics.beginFill(0x666666); 92 | graphics.drawRect(0, 0, Variables.Width, Variables.Height); 93 | graphics.endFill(); 94 | 95 | const Gap:int = 10; 96 | 97 | title.x = (Variables.Width - title.width) / 2; 98 | title.y = Gap; 99 | 100 | howToLabel.x = Gap; 101 | howToLabel.y = title.y + title.height + Gap; 102 | 103 | ipLabel.x = Gap; 104 | ipLabel.y = howToLabel.y + howToLabel.height + Gap; 105 | 106 | ipInput.x = ipLabel.x + ipLabel.width; 107 | ipInput.y = ipLabel.y; 108 | ipInput.width = 80; 109 | ipInput.height = ipLabel.height; 110 | 111 | portLabel.x = ipLabel.x; 112 | portLabel.y = ipInput.y + ipInput.height + Gap; 113 | 114 | portInput.x = portLabel.x + portLabel.width; 115 | portInput.y = portLabel.y; 116 | portInput.width = 40; 117 | portInput.height = portLabel.height; 118 | 119 | frameskipLabel.x = portLabel.x; 120 | frameskipLabel.y = portInput.y + portInput.height + Gap; 121 | 122 | frameskipInput.x = frameskipLabel.x + frameskipLabel.width; 123 | frameskipInput.y = frameskipLabel.y; 124 | frameskipInput.width = 40; 125 | frameskipInput.height = frameskipLabel.height; 126 | 127 | buttons.x = (Variables.Width - buttons.width) / 2; 128 | buttons.y = portInput.y + portInput.height + Gap*5; 129 | } 130 | 131 | private function onLink(event:TextEvent):void 132 | { 133 | switch(event.text) 134 | { 135 | case 'connect': 136 | connect(); 137 | break; 138 | } 139 | } 140 | 141 | private function connect():void 142 | { 143 | handler.onOwnServerSetupConnect(new ServerSettings(ipInput.text, int(portInput.text), int(frameskipInput.text))); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /src/ui/Setup.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.DisplayObject; 4 | import flash.display.Sprite; 5 | import flash.events.KeyboardEvent; 6 | import flash.events.MouseEvent; 7 | import flash.events.TextEvent; 8 | 9 | import model.Gamepad; 10 | 11 | internal class Setup extends Sprite implements IBaseSetup 12 | { 13 | private var joystickSprite:Sprite; 14 | private var title:Text; 15 | private var info:Text; 16 | private var leftKeys:Sprite; 17 | private var middleKeys:Sprite; 18 | private var rightKeys:Sprite; 19 | private var buttons:Text; 20 | private var defaults:Text; 21 | private var joystickData:Gamepad; 22 | private var assigning:String; 23 | private var gamepadModule:IGamepadModule; 24 | private var keyNames:Array; 25 | private var locale:Locale; 26 | 27 | private var handler:ISetupHandler; 28 | 29 | public function Setup(handler:ISetupHandler, gamepadModule:IGamepadModule) 30 | { 31 | super(); 32 | 33 | locale = Locale.instance; 34 | 35 | this.handler = handler; 36 | this.gamepadModule = gamepadModule; 37 | 38 | keyNames = gamepadModule.getGamepadKeysNames(); 39 | 40 | visible = false; 41 | 42 | initJoystick(); 43 | 44 | title = new Text; 45 | title.htmlText = '

' + locale.keyboard_setup.toUpperCase() + '

'; 46 | addChild(title); 47 | 48 | info = new Text; 49 | info.htmlText = '

' + locale.select_joystick_button + '...

'; 50 | addChild(info); 51 | 52 | leftKeys = new Sprite; 53 | addChild(leftKeys); 54 | 55 | middleKeys = new Sprite; 56 | addChild(middleKeys); 57 | 58 | rightKeys = new Sprite; 59 | addChild(rightKeys); 60 | 61 | defaults = new Text; 62 | defaults.htmlText = '

' + locale.load_defaults + '

'; 63 | addChild(defaults); 64 | defaults.addEventListener(TextEvent.LINK, onLink); 65 | 66 | buttons = new Text; 67 | buttons.htmlText = '

' + 68 | locale.save.toUpperCase() + 69 | ' ' + locale.or + ' ' + 70 | locale.cancel.toUpperCase() + '

'; 71 | addChild(buttons); 72 | buttons.addEventListener(TextEvent.LINK, onLink); 73 | } 74 | 75 | public function get sprite():DisplayObject 76 | { 77 | return this; 78 | } 79 | 80 | public function show(joystick:Gamepad):void 81 | { 82 | visible = true; 83 | buttons.htmlText = '

' + 84 | locale.save.toUpperCase() + 85 | ' ' + locale.or + ' ' + 86 | locale.cancel.toUpperCase() + '

'; 87 | 88 | joystickData = new Gamepad(0); 89 | joystickData.codes = joystick.codes.slice(); 90 | 91 | update(); 92 | } 93 | 94 | private function initJoystick():void 95 | { 96 | joystickSprite = new Sprite; 97 | joystickSprite.addChild(gamepadModule.getGamepadImage()); 98 | addChild(joystickSprite); 99 | 100 | var keyNames:Array = gamepadModule.getGamepadKeysNames(); 101 | 102 | for each(var name:String in keyNames) 103 | { 104 | var gamepadButton:GamepadButton = gamepadModule.getGamepadButton(name); 105 | var button:Sprite = new Sprite; 106 | 107 | button.addChild(gamepadButton.bitmap); 108 | joystickSprite.addChild(button); 109 | 110 | button.x = gamepadButton.x; 111 | button.y = gamepadButton.y; 112 | button.buttonMode = true; 113 | button.name = gamepadButton.name; 114 | 115 | button.addEventListener(MouseEvent.MOUSE_OVER, function(event:MouseEvent):void 116 | { 117 | Sprite(event.target).alpha = .6; 118 | }); 119 | 120 | button.addEventListener(MouseEvent.MOUSE_OUT, function(event:MouseEvent):void 121 | { 122 | Sprite(event.target).alpha = 1; 123 | }); 124 | 125 | button.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void 126 | { 127 | assignKey(Sprite(event.target).name); 128 | }); 129 | } 130 | } 131 | 132 | private function assignKey(name:String):void 133 | { 134 | assigning = name; 135 | 136 | joystickData.codes[keyNames.indexOf(assigning)] = 0; 137 | 138 | updateKeys(); 139 | 140 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 141 | } 142 | 143 | private function onKeyDown(event:KeyboardEvent):void 144 | { 145 | var key:uint = event.keyCode; 146 | 147 | joystickData.codes[keyNames.indexOf(assigning)] = key; 148 | 149 | assigning = ''; 150 | 151 | updateKeys(); 152 | 153 | stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 154 | } 155 | 156 | private function update():void 157 | { 158 | graphics.clear(); 159 | graphics.beginFill(0x666666); 160 | graphics.drawRect(0, 0, Variables.Width, Variables.Height); 161 | graphics.endFill(); 162 | 163 | title.x = (Variables.Width - title.width) / 2; 164 | title.y = 4; 165 | 166 | info.x = (Variables.Width - info.width) / 2; 167 | info.y = title.y + title.height; 168 | 169 | joystickSprite.x = (Variables.Width - joystickSprite.width) / 2; 170 | joystickSprite.y = info.y + info.height; 171 | 172 | defaults.x = (Variables.Width - defaults.width) / 2; 173 | defaults.y = joystickSprite.y + joystickSprite.height; 174 | 175 | updateKeys(); 176 | 177 | leftKeys.x = 10; 178 | middleKeys.x = int(Variables.Width / 3) + leftKeys.x; 179 | rightKeys.x = int(Variables.Width / 3) + middleKeys.x; 180 | 181 | leftKeys.y = middleKeys.y = rightKeys.y = defaults.y + defaults.height; 182 | 183 | buttons.x = (Variables.Width - buttons.width) / 2; 184 | buttons.y = leftKeys.y + leftKeys.height - 4; 185 | 186 | } 187 | 188 | private function getKeyText(value:int):String 189 | { 190 | if(joystickData && joystickData.codes) 191 | { 192 | var text:String = Keyboard.Keys[joystickData.codes[value]]; 193 | 194 | if(text && text.length) 195 | { 196 | return text.toUpperCase(); 197 | } 198 | 199 | } 200 | 201 | return '...'; 202 | } 203 | 204 | private function updateKeys():void 205 | { 206 | var fill:Function = function(parent:Sprite, data:Array):void 207 | { 208 | var vertPos:int = 0; 209 | 210 | for each(var item:String in data) 211 | { 212 | var text:Text = new Text(assigning == item ? '#ffffff' : '#cccccc'); 213 | 214 | text.styleSheet.setStyle('.' + item, 215 | { 216 | color: assigning == item ? '#ffffff' : '#cccccc' 217 | }); 218 | 219 | text.htmlText += '

' + item + ' - ' 221 | + getKeyText(keyNames.indexOf(item)) + '

'; 222 | 223 | text.y = vertPos; 224 | vertPos += 12; 225 | 226 | parent.addChild(text); 227 | } 228 | }; 229 | 230 | leftKeys.removeChildren(); 231 | middleKeys.removeChildren(); 232 | rightKeys.removeChildren(); 233 | 234 | if(keyNames.length >= 4) 235 | { 236 | fill(leftKeys, keyNames.slice(0, 4)); 237 | } 238 | 239 | if(keyNames.length >= 8) 240 | { 241 | fill(middleKeys, keyNames.slice(4, 8)); 242 | } 243 | 244 | if(keyNames.length >= 12) 245 | { 246 | fill(rightKeys, keyNames.slice(8, 12)); 247 | } 248 | 249 | buttons.visible = !joystickData.empty; 250 | } 251 | 252 | private function onLink(event:TextEvent):void 253 | { 254 | switch(event.text) 255 | { 256 | case 'save': 257 | save(); 258 | break; 259 | case 'cancel': 260 | cancel(); 261 | break; 262 | // case 'done': 263 | // done(); 264 | // break; 265 | case 'defaults': 266 | loadDefaults(); 267 | break; 268 | } 269 | } 270 | 271 | private function save():void 272 | { 273 | handler.onSetupSave(joystickData); 274 | } 275 | 276 | private function cancel():void 277 | { 278 | handler.onSetupCancel(); 279 | } 280 | 281 | // private function done():void 282 | // { 283 | // handler.onSetupDone(joystickData); 284 | // } 285 | 286 | private function loadDefaults():void 287 | { 288 | joystickData.codes = gamepadModule.getGamepadDefaultKeys(); 289 | 290 | updateKeys(); 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /src/ui/SetupBuilder.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | public class SetupBuilder 4 | { 5 | public static function Make(handler:ISetupHandler, gameData:GameData):IBaseSetup 6 | { 7 | var isTutorial:Boolean = gameData.system == 'gb' || gameData.system == 'gba'; 8 | 9 | return isTutorial 10 | ? new SetupTutorial(handler, gameData.core) 11 | : new Setup(handler, gameData.core); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ui/SetupTutorial.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.display.DisplayObject; 4 | import flash.display.Sprite; 5 | import flash.events.KeyboardEvent; 6 | import flash.events.TextEvent; 7 | import flash.text.StyleSheet; 8 | import model.Gamepad; 9 | 10 | 11 | public class SetupTutorial extends Sprite implements IBaseSetup 12 | { 13 | private var locale:Locale; 14 | private var gamepadModule:IGamepadModule; 15 | private var joystickData:Gamepad; 16 | private var keyNames:Array; 17 | 18 | private var title:Text; 19 | private var keysText:Text; 20 | private var message:Message; 21 | private var assigning:String; 22 | private var defaults:Text; 23 | private var buttons:Text; 24 | 25 | private var handler:ISetupHandler; 26 | 27 | public function SetupTutorial(handler:ISetupHandler, gamepadModule:IGamepadModule) 28 | { 29 | super(); 30 | 31 | locale = Locale.instance; 32 | 33 | this.handler = handler; 34 | this.gamepadModule = gamepadModule; 35 | 36 | keyNames = gamepadModule.getGamepadKeysNames(); 37 | 38 | visible = false; 39 | 40 | { 41 | title = new Text; 42 | title.htmlText = '

' + locale.keyboard_setup.toUpperCase() + '

'; 43 | addChild(title); 44 | } 45 | 46 | { 47 | keysText = new Text(); 48 | keysText.multiline = true; 49 | 50 | var style:StyleSheet = keysText.styleSheet; 51 | 52 | style.setStyle('a', {textDecoration : 'none'}); 53 | style.setStyle('a:hover', {textDecoration : 'underline'}); 54 | 55 | keysText.styleSheet = style; 56 | addChild(keysText); 57 | 58 | keysText.addEventListener(TextEvent.LINK, assignButton); 59 | } 60 | 61 | { 62 | defaults = new Text; 63 | defaults.htmlText = '

' + 64 | locale.load_defaults + '

'; 65 | addChild(defaults); 66 | defaults.addEventListener(TextEvent.LINK, onLink); 67 | } 68 | 69 | { 70 | buttons = new Text; 71 | buttons.htmlText = '

' + 72 | locale.save.toUpperCase() + 73 | ' ' + locale.or + ' ' + 74 | locale.cancel.toUpperCase() + '

'; 75 | addChild(buttons); 76 | buttons.addEventListener(TextEvent.LINK, onLink); 77 | } 78 | 79 | message = new Message(); 80 | addChild(message); 81 | 82 | } 83 | 84 | private function onLink(event:TextEvent):void 85 | { 86 | switch(event.text) 87 | { 88 | case 'save': 89 | save(); 90 | break; 91 | case 'cancel': 92 | cancel(); 93 | break; 94 | case 'defaults': 95 | loadDefaults(); 96 | break; 97 | } 98 | } 99 | 100 | private function save():void 101 | { 102 | handler.onSetupSave(joystickData); 103 | } 104 | 105 | private function cancel():void 106 | { 107 | handler.onSetupCancel(); 108 | } 109 | 110 | private function loadDefaults():void 111 | { 112 | joystickData.codes = gamepadModule.getGamepadDefaultKeys(); 113 | 114 | updateKeys(); 115 | } 116 | 117 | private function onKey(event:KeyboardEvent):void 118 | { 119 | var key:uint = event.keyCode; 120 | 121 | joystickData.codes[keyNames.indexOf(assigning)] = key; 122 | assigning = ''; 123 | updateKeys(); 124 | 125 | stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey); 126 | message.hide(); 127 | } 128 | 129 | private function assignButton(event:TextEvent):void 130 | { 131 | assigning = event.text; 132 | 133 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey); 134 | 135 | var callbacks:Object = 136 | { 137 | cancel:function():void 138 | { 139 | stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey); 140 | message.hide(); 141 | } 142 | }; 143 | 144 | message.show('

Please, press button on your keyboard to assign...


' + 145 | 'CANCEL

', callbacks); 146 | } 147 | 148 | public function get sprite():DisplayObject 149 | { 150 | return this; 151 | } 152 | 153 | public function show(joystick:Gamepad):void 154 | { 155 | visible = true; 156 | 157 | joystickData = new Gamepad(0); 158 | joystickData.codes = joystick.codes.slice(); 159 | 160 | update(); 161 | } 162 | 163 | private function update():void 164 | { 165 | graphics.clear(); 166 | graphics.beginFill(0x666666); 167 | graphics.drawRect(0, 0, Variables.Width, Variables.Height); 168 | graphics.endFill(); 169 | 170 | title.x = (Variables.Width - title.width) / 2; 171 | title.y = 4; 172 | 173 | updateKeys(); 174 | 175 | defaults.x = (Variables.Width - defaults.width) / 2; 176 | defaults.y = 110; 177 | 178 | buttons.x = (Variables.Width - buttons.width) / 2; 179 | buttons.y = defaults.y + defaults.height; 180 | } 181 | 182 | private function updateKeys():void 183 | { 184 | var htmlText:String = ''; 185 | 186 | for each(var item:String in keyNames) 187 | { 188 | htmlText += '' + item + ' - ' 189 | + getKeyText(keyNames.indexOf(item)) + '
'; 190 | } 191 | 192 | keysText.x = 10; 193 | keysText.y = 16; 194 | 195 | keysText.htmlText = '

' + htmlText + '

'; 196 | } 197 | 198 | private function getKeyText(value:int):String 199 | { 200 | if(joystickData && joystickData.codes) 201 | { 202 | var text:String = Keyboard.Keys[joystickData.codes[value]]; 203 | 204 | if(text && text.length) 205 | { 206 | return text.toUpperCase(); 207 | } 208 | } 209 | 210 | return '...'; 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/ui/TextInput.as: -------------------------------------------------------------------------------- 1 | package ui 2 | { 3 | import flash.text.TextField; 4 | import flash.text.TextFieldType; 5 | import flash.text.TextFormat; 6 | 7 | internal class TextInput extends TextField 8 | { 9 | private var format:TextFormat; 10 | 11 | public function TextInput(defaultText:String = '') 12 | { 13 | background = true; 14 | backgroundColor = 0x888888; 15 | type = TextFieldType.INPUT; 16 | tabEnabled = true; 17 | 18 | format = new TextFormat; 19 | 20 | format.font = 'verdana'; 21 | format.color = 0xffffff; 22 | format.size = 8; 23 | 24 | text = defaultText; 25 | } 26 | 27 | public override function set text(value:String):void 28 | { 29 | super.text = value; 30 | 31 | setTextFormat(format); 32 | } 33 | } 34 | } --------------------------------------------------------------------------------