├── res
├── bg.jpg
├── bg.png
├── node.png
├── test.png
├── button.png
├── gauge.png
├── favicon.ico
├── menu-bg.jpg
├── note-bg.png
├── result-bg.jpg
├── turntable.png
├── judge-image.png
├── level-font.png
├── note-black.png
├── note-white.png
├── sound-only.png
├── black-keydown.png
├── fonts
│ └── spaceage.ttf
├── great-effect.png
├── note-turntable.png
├── numeral-font.png
├── white-keydown.png
├── turntable-keydown.png
├── loading.js
└── va.txt
├── .cocos-project.json
├── test
├── src
│ ├── test-utils.coffee
│ ├── test-greatEffect.coffee
│ ├── test-note.coffee
│ ├── test-animationLayer.coffee
│ ├── test-playtimeLayer.coffee
│ ├── test-bpmLayer.coffee
│ ├── test-timer.coffee
│ ├── test-keyEffectLayer.coffee
│ ├── test-main.coffee
│ ├── test-rateLayer.coffee
│ ├── test-judgementLayer.coffee
│ ├── test-numeralLayer.coffee
│ ├── test-parser.coffee
│ └── test-statsLayer.coffee
├── project.json
└── runner.html
├── .gitignore
├── .travis.yml
├── project.json
├── bower.json
├── src
├── measureNode.coffee
├── eventObserver.coffee
├── judge.coffee
├── searchController.coffee
├── keyboardService.coffee
├── timer.coffee
├── note.coffee
├── bpmLayer.coffee
├── greatEffect.coffee
├── judgementLayer.coffee
├── audio.coffee
├── greatEffectsLayer.coffee
├── playtimeLayer.coffee
├── keyEffectsLayer.coffee
├── numeralLayer.coffee
├── loaderScene.coffee
├── resource.coffee
├── animationLayer.coffee
├── main.coffee
├── fallObj.coffee
├── gameoverScene.coffee
├── searchLayer.coffee
├── rateLayer.coffee
├── statsLayer.coffee
├── menuScene.coffee
├── notesLayer.coffee
├── parser.coffee
└── app.coffee
├── manifest.webapp
├── .project
├── package.json
├── index.html
├── README.md
├── gulpfile.coffee
└── bms.cson
/res/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/bg.jpg
--------------------------------------------------------------------------------
/res/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/bg.png
--------------------------------------------------------------------------------
/res/node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/node.png
--------------------------------------------------------------------------------
/res/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/test.png
--------------------------------------------------------------------------------
/res/button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/button.png
--------------------------------------------------------------------------------
/res/gauge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/gauge.png
--------------------------------------------------------------------------------
/res/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/favicon.ico
--------------------------------------------------------------------------------
/res/menu-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/menu-bg.jpg
--------------------------------------------------------------------------------
/res/note-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/note-bg.png
--------------------------------------------------------------------------------
/res/result-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/result-bg.jpg
--------------------------------------------------------------------------------
/res/turntable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/turntable.png
--------------------------------------------------------------------------------
/.cocos-project.json:
--------------------------------------------------------------------------------
1 | {
2 | "has_native": true,
3 | "project_type": "js"
4 | }
--------------------------------------------------------------------------------
/res/judge-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/judge-image.png
--------------------------------------------------------------------------------
/res/level-font.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/level-font.png
--------------------------------------------------------------------------------
/res/note-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/note-black.png
--------------------------------------------------------------------------------
/res/note-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/note-white.png
--------------------------------------------------------------------------------
/res/sound-only.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/sound-only.png
--------------------------------------------------------------------------------
/res/black-keydown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/black-keydown.png
--------------------------------------------------------------------------------
/res/fonts/spaceage.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/fonts/spaceage.ttf
--------------------------------------------------------------------------------
/res/great-effect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/great-effect.png
--------------------------------------------------------------------------------
/res/note-turntable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/note-turntable.png
--------------------------------------------------------------------------------
/res/numeral-font.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/numeral-font.png
--------------------------------------------------------------------------------
/res/white-keydown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/white-keydown.png
--------------------------------------------------------------------------------
/res/turntable-keydown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bokuweb/bmsjs/HEAD/res/turntable-keydown.png
--------------------------------------------------------------------------------
/test/src/test-utils.coffee:
--------------------------------------------------------------------------------
1 | capture = (name)-> if window.callPhantom? then callPhantom {'screenshot': name}
2 |
3 | module.exports =
4 | capture : capture
5 |
6 |
--------------------------------------------------------------------------------
/test/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "debugMode" : 1,
3 | "frameRate" : 60,
4 | "id" : "gameCanvas",
5 | "renderMode" : 1,
6 | "jsList" : []
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | frameworks/
3 | tools/
4 | main.js
5 | CMakeLists.txt
6 | js/
7 | bower_components/
8 | bms/
9 | #package.json#
10 | test/test-all.js
11 | publish/
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - '0.10'
5 |
6 | install:
7 | - npm install -g bower
8 | - npm install
9 | - bower install -f
10 |
11 | script:
12 | - 'gulp test'
13 |
--------------------------------------------------------------------------------
/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_type": "javascript",
3 |
4 | "debugMode" : 0,
5 | "showFPS" : false,
6 | "frameRate" : 60,
7 | "id" : "gameCanvas",
8 | "renderMode" : 0,
9 | "engineDir":"frameworks/cocos2d-html5",
10 |
11 | "modules" : ["cocos2d"],
12 |
13 | "jsList" : [
14 |
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bms_proto",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "ignore": [
6 | "**/.*",
7 | "node_modules",
8 | "bower_components",
9 | "test",
10 | "tests"
11 | ],
12 | "dependencies": {
13 | "mocha": "~2.2.5",
14 | "jquery": "~2.1.3",
15 | "chai": "~2.3.0",
16 | "lodash": "~3.9.3"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/measureNode.coffee:
--------------------------------------------------------------------------------
1 | FallObj = require './fallObj'
2 |
3 | MeasureNode = FallObj.extend
4 |
5 | ctor : (texture, @_timer)->
6 | @_super texture, @_timer
7 |
8 | start : ->
9 | @_super()
10 |
11 | update : ->
12 | @_super()
13 | if @y < @dstY[@index]
14 | @removeFromParent on
15 | @release()
16 |
17 | module.exports = MeasureNode
18 |
--------------------------------------------------------------------------------
/src/eventObserver.coffee:
--------------------------------------------------------------------------------
1 | EventObserver = cc.Class.extend
2 |
3 | ctor : ->
4 | @_listeners = []
5 |
6 | on: (name, callback, params)->
7 | @_listeners.push
8 | name: name
9 | callback: callback
10 | params : params
11 |
12 | trigger: (name, data)->
13 | for listener in @_listeners when listener.name is name
14 | listener.callback name, data, listener.params
15 | return
16 |
17 | module.exports = EventObserver
18 |
--------------------------------------------------------------------------------
/manifest.webapp:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0",
3 | "name": "bms_proto",
4 | "description": "bms_proto",
5 | "launch_path": "/index.html",
6 | "icons": {
7 | "128": "/res/icon.png"
8 | },
9 | "developer": {
10 | "name": "Cocos2d-html5",
11 | "url": "http://cocos2d-x.org/"
12 | },
13 | "default_locale": "en",
14 | "installs_allowed_from": [
15 | "*"
16 | ],
17 | "orientation": "portrait-primary",
18 | "fullscreen": "true"
19 | }
20 |
--------------------------------------------------------------------------------
/src/judge.coffee:
--------------------------------------------------------------------------------
1 | Judge = cc.Class.extend
2 | ctor : (@_config)->
3 | console.dir @_config
4 |
5 | exec : (diffTime)->
6 | return "pgreat" if -@_config.pgreat < diffTime < @_config.pgreat
7 | return "great" if -@_config.great < diffTime < @_config.great
8 | return "good" if -@_config.good < diffTime < @_config.good
9 | return "bad" if -@_config.bad < diffTime < @_config.bad
10 | return "poor"
11 |
12 | module.exports = Judge
13 |
--------------------------------------------------------------------------------
/src/searchController.coffee:
--------------------------------------------------------------------------------
1 | _ = require 'lodash'
2 |
3 | SearchController = cc.Layer.extend
4 | ctor : (@_items) ->
5 |
6 | search : (txt) ->
7 | visibleItems = _.filter @_items, (item) ->
8 | list = txt.replace(/ /g," ").split(/ /)
9 | _.filter list, (txt) ->
10 | txt = txt.replace /[A-Za-z0-9]/g, (s) -> String.fromCharCode(s.charCodeAt(0) - 0xFEE0)
11 | re = new RegExp txt, "i"
12 | if item.title?
13 | item.title.search(re) isnt -1
14 | .length is list.length
15 |
16 | module.exports = SearchController
17 |
--------------------------------------------------------------------------------
/src/keyboardService.coffee:
--------------------------------------------------------------------------------
1 | EventObserver = require './eventObserver'
2 |
3 | KeyboardService = cc.Layer.extend
4 | ctor : (@_timer)->
5 | @_super()
6 | @_notifier = new EventObserver()
7 |
8 | init : (config)->
9 | return false unless 'keyboard' of cc.sys.capabilities
10 | cc.eventManager.addListener
11 | event : cc.EventListener.KEYBOARD
12 | onKeyPressed : @_onKeyPressed.bind this
13 | , this
14 | true
15 |
16 | addListener : (key, listener, id)->
17 | @_notifier.on key, listener, id
18 |
19 | _onKeyPressed : (key, event)->
20 | @_notifier.trigger key, @_timer.get()
21 |
22 | module.exports = KeyboardService
23 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | bmsjs
4 |
5 |
6 |
7 |
8 |
9 |
10 | org.ccdt.cocosproject
11 | org.ccdt.jsdt.core.jsNature
12 |
13 |
14 | 1.2
15 |
16 |
17 |
18 | script
19 | 2
20 | PROJECT_LOC/frameworks/js-bindings/bindings/script
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/timer.coffee:
--------------------------------------------------------------------------------
1 | Timer = cc.Class.extend
2 | ctor : ->
3 | @_startTime = 0
4 | @_pauseTime = 0
5 | @_isPause = false
6 |
7 | start : ->
8 | @_isPause = false
9 | @_startTime = new Date()
10 |
11 | set : (time_msec)->
12 | @_startTime = new Date()
13 | @_pauseTime = time_msec
14 |
15 | get : ->
16 | if @_isPause
17 | @_pauseTime
18 | else if @_startTime
19 | ((new Date() - @_startTime) + @_pauseTime)
20 | else 0
21 |
22 | pause : ->
23 | @_isPause = true
24 | @_pauseTime = ((new Date() - @_startTime) + @_pauseTime)
25 |
26 | stop : ->
27 | @_startTime = 0
28 | @_pauseTime = 0
29 |
30 | module.exports = Timer
31 |
--------------------------------------------------------------------------------
/src/note.coffee:
--------------------------------------------------------------------------------
1 | FallObj = require './fallObj'
2 | EventObserver = require './eventObserver'
3 |
4 | Note = FallObj.extend
5 |
6 | ctor : (texture, @_timer, @_removeTime) ->
7 | @_super texture, @_timer
8 | @_notifier = new EventObserver()
9 |
10 | addListener: (name, listner) ->
11 | @_notifier.on name, listner
12 |
13 | update : ->
14 | @_super()
15 | time = @_timer.get()
16 | @y = @dstY[@index] if @y <= @dstY[@index]
17 |
18 | if @clear and not @hasJudged
19 | @hasJudged = true
20 | return
21 |
22 | if time > @timing + @_removeTime
23 | @_notifier.trigger 'remove', this
24 | @removeFromParent on
25 | @release()
26 | return
27 |
28 | module.exports = Note
29 |
--------------------------------------------------------------------------------
/src/bpmLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayer = require './numeralLayer'
2 |
3 | BpmLayer = cc.Layer.extend
4 | ctor: (@_skin, @_timer, @_bpms) ->
5 | @_super()
6 | @_bpm = new NumeralLayer @_skin
7 |
8 | init : ->
9 | @_index = 0
10 | @_bpm.init 3, @_bpms[0].val
11 | @_bpm.x = cc.screenSize.width / 2 + @_skin.x
12 | @_bpm.y = cc.screenSize.height - @_skin.y
13 | @addChild @_bpm
14 |
15 | start : -> @scheduleUpdate()
16 |
17 | get : ->
18 | i = if @_index >= 1 then @_index - 1 else 0
19 | @_bpms[i].val
20 |
21 | update : ->
22 | time = @_timer.get()
23 | if @_bpms[@_index]?
24 | if time > @_bpms[@_index].timing
25 | @_bpm.reflect @_bpms[@_index].val
26 | @_index++
27 |
28 | module.exports = BpmLayer
29 |
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bms-proto",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "bokuweb",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "gulp": "*",
13 | "coffee-script": "*",
14 | "watchify": "*",
15 | "gulp-watchify": "*",
16 | "gulp-coffee": "*",
17 | "gulp-plumber": "*",
18 | "coffeeify": "*",
19 | "gulp-rename": "*",
20 | "gulp-mocha-phantomjs": "*",
21 | "gulp-webserver": "*",
22 | "gulp-shell": "*",
23 | "gulp-cson": "*"
24 | },
25 | "browser": {
26 | "jquery": "./bower_components/jquery/dist/jquery.js",
27 | "lodash": "./bower_components/lodash/lodash.min.js"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/greatEffect.coffee:
--------------------------------------------------------------------------------
1 | GreatEffect = cc.Sprite.extend
2 | ctor : (src, params)->
3 | w = params.width
4 | h = params.height
5 | @_super src, cc.rect 0, 0, w, h
6 | animationframe = []
7 | num = params.row * params.colum
8 |
9 | for i in [0...num]
10 | frame = new cc.SpriteFrame src, cc.rect w * (i % params.row), h * ~~(i / params.row), w, h
11 | animationframe.push frame
12 | @_animation = new cc.Animation animationframe, params.delay
13 | @_animation.retain()
14 |
15 | run : ->
16 | cb = ->
17 | @removeFromParent on
18 | @_animation.release()
19 | @release()
20 |
21 | action = cc.sequence(
22 | new cc.Animate @_animation
23 | cc.CallFunc.create cb, this
24 | )
25 | @runAction action
26 |
27 | module.exports = GreatEffect
28 |
--------------------------------------------------------------------------------
/src/judgementLayer.coffee:
--------------------------------------------------------------------------------
1 | JudgementLayer = cc.Layer.extend
2 | ctor: (@_skin) ->
3 | @_super()
4 |
5 | init : ->
6 | @_judgement = new cc.Sprite @_skin.src, cc.rect 0, 0, @_skin.width, @_skin.height
7 | @_judgement.x = cc.screenSize.width / 2 + @_skin.x
8 | @_judgement.y = cc.screenSize.height - @_skin.y
9 | @_judgement.setOpacity 0
10 | @addChild @_judgement
11 |
12 | #
13 | # frame =
14 | # 0 : pgreat
15 | # 1 : grear
16 | # 2 : good
17 | # 3 : bad
18 | # 4 : poor
19 | #
20 | show : (frame, combo, time_sec) ->
21 | @_judgement.setTextureRect cc.rect 0, @_skin.height * frame, @_skin.width, @_skin.height
22 | @_judgement.stopAllActions()
23 | @_judgement.setOpacity 255
24 | @_judgement.runAction cc.fadeOut time_sec
25 |
26 | module.exports = JudgementLayer
27 |
--------------------------------------------------------------------------------
/src/audio.coffee:
--------------------------------------------------------------------------------
1 | Audio = cc.Layer.extend
2 |
3 | ctor : (@_timer, @_bgms)->
4 | @_super()
5 | @_wav = []
6 | @_index = 0
7 | @_audio = cc.audioEngine
8 |
9 | init : (res, prefix)->
10 | @_wav[k] = (prefix + encodeURIComponent(v)) for k, v of res
11 |
12 | play : (id)->
13 | @_audio.playEffect @_wav[id], false if @_wav[id]?
14 |
15 | startBgm : ->
16 | @scheduleUpdate()
17 |
18 | stopBgm : ->
19 |
20 | update : ->
21 | time = @_timer.get()
22 | while time >= @_bgms[@_index]?.timing
23 | @play @_bgms[@_index].id
24 | @_index++
25 |
26 | onExit : ->
27 | @_super()
28 | @removeAllChildren on
29 | cc.audioEngine.stopAllEffects()
30 | for wav in @_wav when wav?
31 | cc.audioEngine.unloadEffect wav
32 | @_wav = []
33 |
34 | module.exports = Audio
35 |
--------------------------------------------------------------------------------
/src/greatEffectsLayer.coffee:
--------------------------------------------------------------------------------
1 | GreatEffect = require './greatEffect'
2 |
3 | GreatEffectLayer = cc.Layer.extend
4 | ctor : (@_res)->
5 | @_super()
6 | @_effects = []
7 | @_index = 0
8 |
9 | init : (num)->
10 | @_batchNode = new cc.SpriteBatchNode @_res.src
11 | @addChild @_batchNode
12 | for i in [0...num]
13 | params =
14 | width : @_res.width
15 | height : @_res.height
16 | row : @_res.row
17 | colum : @_res.colum
18 | delay : @_res.delay
19 | effect = new GreatEffect @_batchNode.texture, params
20 | effect.y = -effect.y
21 | @_effects.push effect
22 | effect.retain()
23 | return
24 |
25 | run : (x, y)->
26 | @_effects[@_index].x = x
27 | @_effects[@_index].y = y
28 | @_batchNode.addChild @_effects[@_index]
29 | @_effects[@_index].run()
30 | @_index += 1
31 |
32 | module.exports = GreatEffectLayer
33 |
--------------------------------------------------------------------------------
/src/playtimeLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayer = require './numeralLayer'
2 |
3 | PlaytimeLayer = cc.Layer.extend
4 | ctor: (@_skin, @_timer) ->
5 | @_super()
6 | @_oldtime = 0
7 | @_minuite = new NumeralLayer @_skin
8 | @_second = new NumeralLayer @_skin
9 |
10 | init : ->
11 | @_minuite.init 2, 0
12 | @_minuite.x = cc.screenSize.width / 2 + @_skin.minuite.x
13 | @_minuite.y = cc.screenSize.height - @_skin.minuite.y
14 | @addChild @_minuite
15 |
16 | @_second.init 2, 0
17 | @_second.x = cc.screenSize.width / 2 + @_skin.second.x
18 | @_second.y = cc.screenSize.height - @_skin.second.y
19 | @addChild @_second
20 |
21 | start : -> @scheduleUpdate()
22 |
23 | update : ->
24 | now = ~~(@_timer.get() / 1000)
25 | if now isnt @_oldtime
26 | @_minuite.reflect now / 60
27 | @_second.reflect now % 60
28 | @_oldtime = now
29 |
30 | module.exports = PlaytimeLayer
31 |
--------------------------------------------------------------------------------
/src/keyEffectsLayer.coffee:
--------------------------------------------------------------------------------
1 | KeyEffectsLayer = cc.Layer.extend
2 | ctor : (@_skin) ->
3 | @_super()
4 | @_effects = []
5 |
6 | init : (xList) ->
7 | @_effects.length = 0
8 | for x, i in xList
9 | switch i
10 | when 0, 2, 4, 6 then @_effects[i] = new cc.Sprite @_skin.whiteKeydownImage.src
11 | when 1, 3, 5 then @_effects[i] = new cc.Sprite @_skin.blackKeydownImage.src
12 | when 7 then @_effects[i] = new cc.Sprite @_skin.turntableKeydownImage.src
13 | else throw new Error "error unlnown note"
14 | @_effects[i].x = x
15 | @_effects[i].y = cc.screenSize.height - @_skin.y
16 | #@_effects[i].setAnchorPoint cc.p(0.5,0)
17 | @addChild @_effects[i]
18 | @_effects[i].setOpacity 0
19 | return
20 |
21 | show : (id, time_sec) ->
22 | @_effects[id].setOpacity 255
23 | @_effects[id].runAction cc.fadeOut time_sec
24 |
25 | module.exports = KeyEffectsLayer
26 |
--------------------------------------------------------------------------------
/src/numeralLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayer = cc.Layer.extend
2 | ctor: (@_skin) ->
3 | @_super()
4 | @_sprites = []
5 |
6 | init : (@_digits, num = 0) ->
7 | scaledWidth = @_skin.width * @_skin.scale
8 | @_batchNode = new cc.SpriteBatchNode @_skin.src
9 | @addChild @_batchNode
10 | @_frames = for i in [0...10]
11 | new cc.SpriteFrame @_batchNode.texture, cc.rect @_skin.width * i, 0, @_skin.width, @_skin.height
12 |
13 | for i in [0...@_digits]
14 | @_sprites[i] = new cc.Sprite()
15 | @_sprites[i].setSpriteFrame @_frames[0]
16 | @_sprites[i].x = i * (-scaledWidth - @_skin.margin) + (scaledWidth * @_digits / 2)
17 | @_sprites[i].scale = @_skin.scale
18 | @_batchNode.addChild @_sprites[i]
19 | @reflect num
20 |
21 | reflect : (num) ->
22 | for i in [0...@_digits]
23 | @_sprites[i].setSpriteFrame @_frames[~~(num % 10)]
24 | num /= 10
25 |
26 | module.exports = NumeralLayer
27 |
--------------------------------------------------------------------------------
/test/runner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha Test Runner
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/loaderScene.coffee:
--------------------------------------------------------------------------------
1 | LoaderScene = cc.LoaderScene.extend
2 | init : ->
3 | @_bgLayer = new cc.LayerColor cc.color(0, 0, 0, 255)
4 | @addChild @_bgLayer, 0
5 |
6 | @_label = new cc.LabelTTF "Loading... 0%", "Arial", 16
7 | @_label.x = cc.director.getWinSize().width / 2
8 | @_label.y = cc.director.getWinSize().height / 2
9 | @_label.setColor cc.color(255, 255, 255)
10 | @_bgLayer.addChild @_label, 10
11 |
12 | _initStage : (img, centerPos) ->
13 | #@_super img, centerPos
14 |
15 | onEnter : ->
16 | @_super()
17 |
18 | onExit : ->
19 | @_super()
20 |
21 | initWithResources : (resources, cb, target) ->
22 | @_super resources, cb, target
23 |
24 | _startLoading : ->
25 | @_super()
26 |
27 | LoaderScene.preload = (resources, cb, target) ->
28 | _cc = cc
29 | if not _cc.loaderScene
30 | _cc.loaderScene = new LoaderScene()
31 | _cc.loaderScene.init()
32 |
33 | _cc.loaderScene.initWithResources resources, cb, target
34 | cc.director.runScene _cc.loaderScene
35 | _cc.loaderScene
36 |
37 | module.exports = LoaderScene
38 |
--------------------------------------------------------------------------------
/src/resource.coffee:
--------------------------------------------------------------------------------
1 | resObjs =
2 | bgImage : "res/bg.jpg"
3 | nodeImage : "res/node.png"
4 | noteWhiteImage : "res/note-white.png"
5 | noteBlackImage : "res/note-black.png"
6 | noteTurntableImage : "res/note-turntable.png"
7 | noteBgImage : "res/note-bg.png"
8 | greatEffectImage : "res/great-effect.png"
9 | turntableKeydownImage : "res/turntable-keydown.png"
10 | whiteKeydownImage : "res/white-keydown.png"
11 | blackKeydownImage : "res/black-keydown.png"
12 | testImage : "res/test.png"
13 | meterImage : "res/gauge.png"
14 | numeralImage : "res/number.png"
15 | turntableImage : "res/turntable.png"
16 | soundonlyImage : "res/sound-only.png"
17 | resultBgImage : "res/result-bg.jpg"
18 | menuBgImage : "res/menu-bg.jpg"
19 | itemBgImage : "res/item-bg.png"
20 | levelFontImage : "res/level-font.png"
21 |
22 | resList = []
23 |
24 | resList.push v for k, v of resObjs
25 |
26 | # fontのみ絶対pathにしないとディレクトリ構造とURLの差異でロードに失敗する
27 | resList.push
28 | type : "font"
29 | name : "sapceage"
30 | srcs : [cc.pathToBmsDir + "res/fonts/spaceage.ttf"]
31 |
32 | module.exports =
33 | resObjs : resObjs
34 | resList : resList
35 |
--------------------------------------------------------------------------------
/test/src/test-greatEffect.coffee:
--------------------------------------------------------------------------------
1 | GreatEffectTest = cc.Class.extend
2 |
3 | start : ->
4 | describe 'great effect class test', ->
5 | @timeout 3000
6 | GreatEffect = require '../../src/greatEffect'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'great effect create and update test', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | params =
17 | width : 80
18 | height : 80
19 | row : 6
20 | colum : 3
21 | delay : 0.02
22 | effect = new GreatEffect '../res/great-effect.png', params
23 | effect.x = cc.director.getWinSize().width / 2
24 | effect.y = cc.director.getWinSize().height / 2
25 | @addChild effect
26 | effect.run()
27 |
28 | expect @children.length
29 | .to.be.equal 1
30 |
31 | setTimeout =>
32 | expect @children.length
33 | .to.be.equal 0
34 | done()
35 | , 1000
36 |
37 | cc.director.runScene new TestScene()
38 |
39 |
40 | module.exports = GreatEffectTest
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/animationLayer.coffee:
--------------------------------------------------------------------------------
1 | POOR_INDICATOR_TIME_MSEC = 200
2 |
3 | AnimationLayer = cc.Layer.extend
4 | ctor: (@_skin, @_timer) ->
5 | @_super()
6 | @_srcs = []
7 |
8 | init : (srcs, @_bmps, prefix) ->
9 | @_index = 0
10 | @_isPoor = false
11 | for k, v of srcs
12 | @_srcs[k] = prefix + v
13 | @_firstImage ?= prefix + v
14 |
15 | @_bmp = new cc.Sprite @_firstImage
16 | @_bmp.x = cc.screenSize.width / 2 + @_skin.x
17 | @_bmp.y = cc.screenSize.height - @_skin.y
18 | #@_bmp.width = @_skin.width
19 | #@_bmp.height = @_skin.height
20 | #@_bmp.scale = 3.06
21 | @_bmp.scale = 2.5
22 | @_bmp.setOpacity 0
23 | @addChild @_bmp
24 |
25 | start : -> @scheduleUpdate()
26 |
27 | onPoor : ->
28 | if @_srcs[0]?
29 | @_isPoor = true
30 | @_bmp.setTexture @_srcs[0]
31 | @scheduleOnce @_disablePoor, POOR_INDICATOR_TIME_MSEC / 1000
32 |
33 | update : ->
34 | time = @_timer.get()
35 | if time > @_bmps[@_index]?.timing
36 | @_bmp.setOpacity 255
37 | @_bmp.setTexture @_srcs[@_bmps[@_index].id] unless @_isPoor
38 | @_index++
39 |
40 | onExit : ->
41 | @_super()
42 | @removeAllChildren on
43 | @_srcs = []
44 |
45 | _disablePoor : -> @_isPoor = false
46 |
47 | module.exports = AnimationLayer
48 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cocos2d-html5 Hello World test
6 |
7 |
8 |
9 |
10 |
11 |
12 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/test/src/test-note.coffee:
--------------------------------------------------------------------------------
1 | NoteTest = cc.Class.extend
2 |
3 | start : ->
4 | describe 'note class test', ->
5 | @timeout 10000
6 | Note = require '../../src/note'
7 | Timer = require '../../src/timer'
8 | capture = require './test-utils'
9 | .capture
10 | expect = chai.expect
11 | capNum = 0
12 |
13 | it 'note create and update test', (done)->
14 | TestScene = cc.Scene.extend
15 | onEnter : ->
16 | @_super()
17 | @_timer = new Timer()
18 | note = new Note '../res/note-white.png', @_timer, 100
19 | note.x = 160
20 | note.y = -note.height
21 | note.timing = 2000
22 | note.clear = false
23 | note.appendFallParams [timing : 0, val : 180], 0, 400
24 | @addChild note
25 | note.start()
26 | @_timer.start()
27 | expect @children.length
28 | .to.be.equal 1
29 |
30 | setTimeout =>
31 | capture "test/capture/notes/notes" + capNum++
32 | , 2000
33 |
34 | setTimeout =>
35 | expect @children.length
36 | .to.be.equal 0
37 | done()
38 | , 2500
39 |
40 | cc.director.runScene new TestScene()
41 |
42 | before ->
43 |
44 | after ->
45 |
46 |
47 | module.exports = NoteTest
48 |
49 |
50 |
--------------------------------------------------------------------------------
/test/src/test-animationLayer.coffee:
--------------------------------------------------------------------------------
1 | AnimationLayerTest = cc.Class.extend
2 | start : ->
3 | describe 'animation layer class test', ->
4 | @timeout 10000
5 | AnimationLayer = require '../../src/animationLayer'
6 | Timer = require '../../src/timer'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'initialize stats and capture stats', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | size = cc.director.getWinSize()
17 | timer = new Timer()
18 | skin =
19 | x : size.width / 2
20 | y : size.height / 2
21 | bmp = new AnimationLayer skin, timer
22 | srcs = [
23 | '../res/test1.png'
24 | '../res/test2.png'
25 | '../res/test3.png'
26 | ]
27 | bmps = [
28 | {timing : 1000, id : 0}
29 | {timing : 2000, id : 1}
30 | {timing : 1000, id : 2}
31 | ]
32 |
33 | bmp.init srcs, bmps, ''
34 | @addChild bmp
35 | bmp.start()
36 | timer.start()
37 |
38 | setTimeout =>
39 | capture "test/capture/BmpLayer/bmp" + capNum++
40 | done()
41 | , 4100
42 |
43 | cc.director.runScene new TestScene()
44 |
45 | module.exports = AnimationLayerTest
46 |
47 |
48 |
--------------------------------------------------------------------------------
/test/src/test-playtimeLayer.coffee:
--------------------------------------------------------------------------------
1 | PlaytimeLayerTest = cc.Class.extend
2 | start : ->
3 | describe 'playtime layer class test', ->
4 | @timeout 10000
5 | PlaytimeLayer = require '../../src/playtimeLayer'
6 | Timer = require '../../src/timer'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'initialize playtime and capture stats', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | size = cc.director.getWinSize()
17 | timer = new Timer()
18 |
19 | skin =
20 | src : '../res/numeral-font.png'
21 | width : 29.5
22 | height : 36.5
23 | scale : 0.35
24 | margin : 5
25 | minuite :
26 | x : size.width / 2 - 20
27 | y : size.height / 2
28 | second :
29 | x : size.width / 2 + 20
30 | y : size.height / 2
31 |
32 | playtime = new PlaytimeLayer skin, timer
33 |
34 | playtime.init()
35 | @addChild playtime
36 | playtime.start()
37 | timer.set 58000
38 | timer.start()
39 | setTimeout =>
40 | capture "test/capture/playtimeLayer/time" + capNum++
41 | done()
42 | , 5200
43 | cc.director.runScene new TestScene()
44 |
45 | module.exports = PlaytimeLayerTest
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/main.coffee:
--------------------------------------------------------------------------------
1 | window.bmsStart = (pathToBmsDir) ->
2 | cc.pathToBmsDir = pathToBmsDir
3 | cc.screenSize = window.parent.screen
4 | cc.game.run()
5 | cc.game.onStart = ->
6 | MenuScene = require './menuScene'
7 | resList = require './resource'
8 | .resList
9 | if not cc.sys.isNative and document.getElementById "cocosLoading"
10 | document.body.removeChild(document.getElementById "cocosLoading")
11 |
12 | cc.view.enableRetina off
13 | cc.view.adjustViewPort on
14 |
15 | if cc.sys.isMobile
16 | #height = cc.view.getFrameSize().height / cc.view.getFrameSize().width * 320
17 | #cc.view.setDesignResolutionSize 320, height, cc.ResolutionPolicy.SHOW_ALL
18 | cc.view.setDesignResolutionSize 320, 480, cc.ResolutionPolicy.SHOW_ALL
19 | cc.view.resizeWithBrowserSize on
20 | else
21 | screenSize = window.parent.screen
22 | cc.view.setDesignResolutionSize screenSize.width, screenSize.height, cc.ResolutionPolicy.SHOW_ALL
23 | #if window.innerWidth < 800 or window.innerHeight < 600
24 | # policy = new cc.ResolutionPolicy cc.ContainerStrategy.ORIGINAL_CONTAINER, cc.ContentStrategy.SHOW_ALL
25 | # cc.view.setDesignResolutionSize 800, 600, cc.ContainerStrategy.ORIGINAL_CONTAINER
26 | cc.view.resizeWithBrowserSize off
27 | cc.director.setProjection cc.Director.PROJECTION_2D
28 | cc.director.setContentScaleFactor 2
29 |
30 | require('./loaderScene').preload resList, ->
31 | cc.director.runScene new MenuScene()
32 | , this
33 |
34 |
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## bmsjs
2 |
3 | 
4 |
5 | *** work in progress ***
6 |
7 | browser bms player project.
8 |
9 | ### Dependencies
10 |
11 | * cocos2d-JS Full v3.6.1
12 | * CoffeeScript v1.9.2
13 | * Gulp v3.8.11
14 | * bower v1.3.12
15 |
16 | ### Installation
17 |
18 | 1. Install cocos2d-JS
19 | download here cocos2d-JS v3.6.1, and run ```setup.py```.
20 | http://www.cocos2d-x.org/download
21 |
22 | 2. Create cocos2d-JS project
23 |
24 | ```
25 | cocos new bmsjs -l js -d .
26 | ```
27 | 3. Clone this repository and overwrite to bmsjs(cocos2d-JS project) directory
28 |
29 | 4. Install packages
30 |
31 | ```
32 | npm i
33 | bower i
34 | ```
35 |
36 | 5. Build app
37 | build *.coffee to main.js
38 | ```
39 | gulp build
40 | ```
41 |
42 | 6. Run on browser
43 | ```
44 | cocos run -p web
45 | ```
46 |
47 | ### Run test
48 |
49 | #### Run test on PhantomJS
50 |
51 | ```
52 | gulp test
53 | ```
54 |
55 | #### Run test on your browser
56 |
57 | ```
58 | gulp build
59 | ```
60 |
61 | Access ```test/runner.html```.
62 |
63 |
64 | ### Online demo
65 |
66 | http://bokuweb.github.io/bmsjs
67 |
68 | ### License
69 |
70 | 
Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)
71 |
--------------------------------------------------------------------------------
/test/src/test-bpmLayer.coffee:
--------------------------------------------------------------------------------
1 | BpmLayerTest = cc.Class.extend
2 | start : ->
3 | describe 'bpm layer class test', ->
4 | @timeout 10000
5 | Bpm = require '../../src/bpmLayer'
6 | Timer = require '../../src/timer'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'bpm update test', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | size = cc.director.getWinSize()
17 | timer = new Timer()
18 | skin =
19 | src : '../res/numeral-font.png'
20 | width : 29.5
21 | height : 36.5
22 | scale : 0.35
23 | margin : 5
24 | x : size.width / 2
25 | y : size.height / 2
26 |
27 | bpms = [
28 | {timing : 500, val : 100}
29 | {timing : 1000, val : 200}
30 | {timing : 1500, val : 300}
31 | ]
32 |
33 | bpm = new Bpm skin, timer, bpms
34 | bpm.init()
35 | @addChild bpm
36 | bpm.start()
37 | timer.start()
38 |
39 | setTimeout =>
40 | capture "test/capture/BpmLayer/bmp" + capNum++
41 | , 750
42 |
43 | setTimeout =>
44 | capture "test/capture/BpmLayer/bmp" + capNum++
45 | , 1250
46 |
47 | setTimeout =>
48 | capture "test/capture/BpmLayer/bmp" + capNum++
49 | done()
50 | , 2500
51 |
52 | cc.director.runScene new TestScene()
53 |
54 | module.exports = BpmLayerTest
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/fallObj.coffee:
--------------------------------------------------------------------------------
1 | fallObj = cc.Sprite.extend
2 |
3 | ctor : (texture)->
4 | @_super texture
5 |
6 | start : -> @scheduleUpdate()
7 |
8 | update : ->
9 | time = @_timer.get()
10 | while time > @bpm.timing[@index]
11 | if @index < @bpm.timing.length - 1 then @index++
12 | else break
13 | diffTime = @bpm.timing[@index] - time
14 | diffDist = diffTime * @speed[@index]
15 | @y = @dstY[@index] + diffDist
16 |
17 | #
18 | # append BPM, speed, destination y coordinate list to falling object
19 | #
20 | appendFallParams : (bpms, time, fallDist)->
21 | size = cc.director.getWinSize()
22 | previousBpm = 0
23 | @dstY = []
24 | @index = 0
25 | @speed = []
26 | @bpm =
27 | timing : []
28 | val : []
29 |
30 | for v, i in bpms when time < v.timing < @timing
31 | @bpm.timing.push v.timing
32 | @bpm.val.push v.val
33 |
34 | # calculate bpm before object will be created
35 | if bpms[0].timing > time then previousBpm = bpms[0].val
36 | else previousBpm = v.val for v in bpms when v.timing <= time
37 |
38 | @dstY[@bpm.timing.length] = size.height - fallDist
39 | @bpm.timing.push @timing
40 |
41 | # calculate destination of Y coordinate
42 | for v, i in @bpm.timing by -1 when i < @bpm.timing.length - 1
43 | diffDist = (@bpm.timing[i+1] - v) * @calcSpeed(@bpm.val[i], fallDist)
44 | @dstY[i] = @dstY[i+1] + diffDist
45 | @bpm.val.splice 0, 0, previousBpm
46 |
47 | @speed.push @calcSpeed v, fallDist for v in @bpm.val
48 | return
49 |
50 | # return object speed [px/msec]
51 | calcSpeed : (bpm, fallDist) ->
52 | measureTime = 240000 / bpm
53 | fallDist / measureTime
54 |
55 | module.exports = fallObj
56 |
--------------------------------------------------------------------------------
/test/src/test-timer.coffee:
--------------------------------------------------------------------------------
1 | $ = require 'jquery'
2 |
3 | TimerTest = cc.Class.extend
4 | start : ->
5 | describe 'timer class test', ->
6 | @timeout 10000
7 | Timer = require '../../src/timer'
8 | expect = chai.expect
9 |
10 | it 'should timer.get() return 0 before start', ->
11 | time = @_timer.get()
12 | expect time
13 | .to.be.equal 0
14 |
15 | it 'set timer 1000msec, should get() return about 1000msec', (done)->
16 | @_timer.start()
17 | setTimeout =>
18 | time = @_timer.get()
19 | expect time
20 | .to.be.within 900, 1100
21 | @_timer.stop()
22 | done()
23 | , 1000
24 |
25 | it 'timer pause test, should timer return about 2000msec', (done)->
26 | @_timer.start()
27 | pause1secAfter = =>
28 | d = new $.Deferred
29 | setTimeout =>
30 | @_timer.pause()
31 | d.resolve()
32 | , 1000
33 | d.promise()
34 |
35 | restart1secAfter = =>
36 | d = new $.Deferred
37 | setTimeout =>
38 | @_timer.start()
39 | d.resolve()
40 | , 1000
41 | d.promise()
42 |
43 | check1secAfter = =>
44 | d = new $.Deferred
45 | setTimeout =>
46 | d.resolve()
47 | , 1000
48 | d.promise()
49 |
50 | pause1secAfter()
51 | .then restart1secAfter
52 | .then check1secAfter
53 | .then =>
54 | time = @_timer.get()
55 | expect time
56 | .to.be.within 1900, 2100
57 | done()
58 |
59 | before ->
60 | @_timer = new Timer()
61 |
62 | module.exports = TimerTest
63 |
64 |
65 |
--------------------------------------------------------------------------------
/test/src/test-keyEffectLayer.coffee:
--------------------------------------------------------------------------------
1 | keyEffectLayerTest = cc.Class.extend
2 | start : ->
3 | describe 'key effect layer class test', ->
4 | @timeout 3000
5 | $ = require 'jquery'
6 | KeyEffectLayer = require '../../src/keyEffectsLayer'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'key effect layer create and show test', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | xList = [41,63,80,102,119,141,158,0]
17 | skin =
18 | y : 160
19 | turntableKeydownImage :
20 | src : "../res/turntable-keydown.png"
21 | whiteKeydownImage :
22 | src : "../res/white-keydown.png"
23 | blackKeydownImage :
24 | src : "../res/black-keydown.png"
25 |
26 | keyEffectLayer = new KeyEffectLayer skin
27 | keyEffectLayer.init xList
28 | @addChild keyEffectLayer
29 | promise = null
30 | index = 0
31 | promise = do ->
32 | d = new $.Deferred
33 | id = setInterval ->
34 | keyEffectLayer.show index, 0.1
35 | index += 1
36 | console.log xList.length
37 | capture "test/capture/keyEffect/keyEffect" + capNum++
38 | if xList.length is index
39 | clearInterval id
40 | d.resolve()
41 | , 20
42 | d.promise()
43 | promise.then -> done()
44 |
45 | cc.director.runScene new TestScene()
46 |
47 | before ->
48 |
49 | after ->
50 |
51 |
52 | module.exports = keyEffectLayerTest
53 |
54 |
55 |
--------------------------------------------------------------------------------
/gulpfile.coffee:
--------------------------------------------------------------------------------
1 | gulp = require 'gulp'
2 | watchify = require 'gulp-watchify'
3 | plumber = require 'gulp-plumber'
4 | rename = require 'gulp-rename'
5 | mochaPhantomJS = require 'gulp-mocha-phantomjs'
6 | webserver = require 'gulp-webserver'
7 | #shell = require 'gulp-shell'
8 | cson = require 'gulp-cson'
9 |
10 | watching = off
11 |
12 | gulp.task 'enable-watch-mode', -> watching = on
13 |
14 | gulp.task 'build:app', watchify (watchify)->
15 | gulp.src 'src/main.coffee'
16 | .pipe plumber()
17 | .pipe watchify
18 | watch : watching
19 | extensions: ['.coffee', '.js']
20 | transform : ['coffeeify']
21 | .pipe rename
22 | extname: ".js"
23 | .pipe gulp.dest ''
24 |
25 | gulp.task 'build:test', watchify (watchify)->
26 | gulp.src 'test/src/test-main.coffee'
27 | .pipe plumber()
28 | .pipe watchify
29 | watch : watching
30 | extensions: ['.coffee', '.js']
31 | transform : ['coffeeify']
32 | .pipe rename
33 | basename: "test-all",
34 | extname: ".js"
35 | .pipe gulp.dest 'test'
36 |
37 | gulp.task 'cson', ->
38 | gulp.src 'bms.cson'
39 | .pipe cson()
40 | .pipe gulp.dest './'
41 |
42 | #gulp.task 'run', ['build:app'], ->
43 | # shell.task [
44 | # 'cocos run -p web'
45 | # ]
46 |
47 | gulp.task 'test', ['build:test'], ->
48 | gulp.src './test/runner.html'
49 | .pipe mochaPhantomJS
50 | phantomjs:
51 | viewportSize:
52 | width: 800
53 | height: 600
54 | dump:'test.xml'
55 |
56 | gulp.task 'webserver', ->
57 | gulp.src ''
58 | .pipe webserver
59 | directoryListing: true
60 | open: true
61 |
62 | gulp.task 'build', ['build:app', 'build:test']
63 |
64 | gulp.task 'watch:app', ['enable-watch-mode', 'build:app']
65 |
66 | gulp.task 'watch:test', ['enable-watch-mode', 'build:test']
67 |
68 | gulp.task 'watch', ['enable-watch-mode', 'build:test', 'build:app']
69 |
--------------------------------------------------------------------------------
/test/src/test-main.coffee:
--------------------------------------------------------------------------------
1 | GreatEffectTest = require './test-greatEffect'
2 | keyEffectLayerTest = require './test-keyEffectLayer'
3 | ParserTest = require './test-parser'
4 | TimerTest = require './test-timer'
5 | NoteTest = require './test-note'
6 | NumeralLayerTest = require './test-numeralLayer'
7 | StatsLayerTest = require './test-statsLayer'
8 | PlaytimeLayerTest = require './test-playtimeLayer'
9 | JudgementLayerTest = require './test-judgementLayer'
10 | AnimationLayerTest = require './test-animationLayer'
11 | BpmLayerTest = require './test-bpmLayer'
12 | RateLayerTest = require './test-rateLayer'
13 |
14 | window.onload = ->
15 | cc.game.onStart = ->
16 |
17 | cc.screenSize = window.parent.screen
18 |
19 | cc.view.enableRetina off
20 | cc.view.adjustViewPort on
21 | policy = new cc.ResolutionPolicy cc.ContainerStrategy.ORIGINAL_CONTAINER, cc.ContentStrategy.SHOW_ALL
22 | cc.view.setDesignResolutionSize 800, 600, policy
23 | cc.director.setContentScaleFactor 2
24 |
25 | rateLayerTest = new RateLayerTest()
26 | bpmLayerTest = new BpmLayerTest()
27 | animationLayerTest = new AnimationLayerTest()
28 | judgmentLayerTest = new JudgementLayerTest()
29 | playtimeLayerTest = new PlaytimeLayerTest()
30 | statsLayerTest = new StatsLayerTest()
31 | numeralLayerTest = new NumeralLayerTest()
32 | keyEffectLayerTest = new keyEffectLayerTest()
33 | greatEffectTest = new GreatEffectTest()
34 | parserTest = new ParserTest()
35 | timerTest = new TimerTest()
36 | noteTest = new NoteTest()
37 |
38 | rateLayerTest.start()
39 | bpmLayerTest.start()
40 | animationLayerTest.start()
41 | judgmentLayerTest.start()
42 | playtimeLayerTest.start()
43 | statsLayerTest.start()
44 | numeralLayerTest.start()
45 | keyEffectLayerTest.start()
46 | greatEffectTest.start()
47 | parserTest.start()
48 | timerTest.start()
49 | noteTest.start()
50 |
51 | if window.mochaPhantomJS
52 | mochaPhantomJS.run()
53 | else
54 | mocha.run()
55 |
56 |
57 | cc.game.run 'gameCanvas'
58 |
--------------------------------------------------------------------------------
/src/gameoverScene.coffee:
--------------------------------------------------------------------------------
1 | res = require './resource'
2 | .resObjs
3 |
4 |
5 | GameOverLayer = cc.Layer.extend
6 | ctor : (@_stats) ->
7 | @_super()
8 | @_addBackground()
9 | @_MenuScene = require './menuScene'
10 |
11 | toucheventListener = cc.EventListener.create
12 | event: cc.EventListener.TOUCH_ONE_BY_ONE
13 | swallowTouches: true
14 | onTouchBegan: @_onTouch.bind this
15 | cc.eventManager.addListener toucheventListener, this
16 |
17 | if 'keyboard' of cc.sys.capabilities
18 | cc.eventManager.addListener
19 | event : cc.EventListener.KEYBOARD
20 | onKeyPressed : @_onKeyPressed.bind this
21 | , this
22 |
23 | @_stats.score ?= 0
24 | label = new cc.LabelTTF "", "sapceage" , 48
25 | label.x = cc.director.getWinSize().width / 2
26 | label.y = cc.director.getWinSize().height / 2
27 | @addChild label, 5
28 |
29 | label.setString """
30 | SCORE : #{@_stats.score}
31 | MAX COMBO : #{@_stats.combo}
32 | PGREAT : #{@_stats.pgreat}
33 | GREAT : #{@_stats.great}
34 | GOOD : #{@_stats.good}
35 | BAD : #{@_stats.bad}
36 | POOR : #{@_stats.poor}
37 | """
38 |
39 | onExit : ->
40 | @_super()
41 | @removeAllChildren on
42 |
43 | _addBackground : ->
44 | bg = new cc.Sprite res.resultBgImage
45 | bg.x = cc.director.getWinSize().width / 2
46 | bg.y = cc.director.getWinSize().height / 2
47 | bg.scale = window.parent.screen.height / bg.height
48 | @addChild bg, 0
49 |
50 | _onTouch : (touch, event)->
51 | target = event.getCurrentTarget()
52 | locationInNode = target.convertToNodeSpace touch.getLocation()
53 | s = target.getContentSize()
54 | rect = cc.rect 0, 0, s.width, s.height
55 | if cc.rectContainsPoint rect, locationInNode
56 | cc.director.runScene new cc.TransitionFade(1.2, new @_MenuScene())
57 | return true
58 | return false
59 |
60 | _onKeyPressed : (key, event) ->
61 | cc.director.runScene new cc.TransitionFade(1.2, new @_MenuScene())
62 |
63 | GameOverScene = cc.Scene.extend
64 |
65 | ctor : (stats) ->
66 | @_super()
67 | layer = new GameOverLayer stats
68 | @addChild layer
69 |
70 | module.exports = GameOverScene
71 |
--------------------------------------------------------------------------------
/test/src/test-rateLayer.coffee:
--------------------------------------------------------------------------------
1 | skin =
2 | rate :
3 | z : 10
4 | meter :
5 | src : '../res/gauge.png'
6 | width : 4
7 | height : 12
8 | x : 122
9 | y : 207
10 | z : 10
11 | label :
12 | src : '../res/numeral-font.png'
13 | width : 29.5
14 | height : 36.5
15 | scale : 0.3
16 | margin : 3
17 | x : 362
18 | y : 210
19 |
20 | config =
21 | initRate : 20
22 | great : 1
23 | good : 0.5
24 | bad : -0.4
25 | poor : -0.4
26 | num : 50
27 | clearVal : 40
28 |
29 | RateLayerTest = cc.Class.extend
30 | start : ->
31 | describe 'rate layer class test', ->
32 | @timeout 10000
33 | RateLayer = require '../../src/rateLayer'
34 | capture = require './test-utils'
35 | .capture
36 | expect = chai.expect
37 | capNum = 0
38 |
39 | it 'initialize rate and capture', (done)->
40 | TestScene = cc.Scene.extend
41 | onEnter : ->
42 | @_super()
43 | size = cc.director.getWinSize()
44 | rate = new RateLayer skin.rate
45 | rate.init config
46 | @addChild rate, skin.rate.z
47 | rate.start()
48 |
49 | setTimeout =>
50 | expect(rate.get()).to.be.equal config.initRate
51 | capture "test/capture/StatsLayer/stats" + capNum++
52 | done()
53 | , 1000
54 | cc.director.runScene new TestScene()
55 |
56 | it 'update rate by great', (done)->
57 | TestScene = cc.Scene.extend
58 | onEnter : ->
59 | @_super()
60 | size = cc.director.getWinSize()
61 | rate = new RateLayer skin.rate
62 | rate.init config
63 | @addChild rate, skin.rate.z
64 | rate.start()
65 | num = ~~(100 - config.initRate / config.great) + 1
66 | console.log num
67 | for i in [0...num]
68 | rate.reflect 'pgreat'
69 |
70 | setTimeout =>
71 | expect(rate.get()).to.be.equal 100
72 | capture "test/capture/StatsLayer/stats" + capNum++
73 | done()
74 | , 1000
75 | cc.director.runScene new TestScene()
76 |
77 | module.exports = RateLayerTest
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/searchLayer.coffee:
--------------------------------------------------------------------------------
1 | EventObserver = require './eventObserver'
2 | SearchController = require './searchController'
3 |
4 | SearchLayer = cc.Layer.extend
5 | ctor : ->
6 | @_super()
7 | @_notifier = new EventObserver()
8 |
9 | init : (searchItems) ->
10 | @_oldTxt = null
11 | @_searchController = new SearchController searchItems
12 |
13 | if 'touches' of cc.sys.capabilities
14 | cc.eventManager.addListener
15 | event : cc.EventListener.TOUCH_ALL_AT_ONCE
16 | onTouchesEnded: @_onTouchesEnded
17 | , this
18 | else if 'mouse' of cc.sys.capabilities
19 | cc.eventManager.addListener
20 | event : cc.EventListener.MOUSE
21 | onMouseUp: @_onMouseUp.bind this
22 | , this
23 |
24 | @_textField = new cc.TextFieldTTF "search", "Arial", 20
25 | @addChild @_textField
26 | #@_textField.setDelegate this
27 | size = cc.director.getWinSize()
28 | @_textField.x = 120
29 | @_textField.y = 50
30 |
31 | addListener: (name, listner)->
32 | @_notifier.on name, listner
33 |
34 | start : -> @scheduleUpdate()
35 |
36 | update : ->
37 | txt = @_textField.getContentText()
38 | if @_oldTxt isnt txt
39 | @_oldTxt = txt
40 | @_notifier.trigger 'change', @_searchController.search(txt)
41 |
42 | #if txt is ""
43 | # @_textField.setPlaceHolder "search"
44 |
45 | # CCTextFieldDelegate
46 | onTextFieldAttachWithIME : (sender) ->
47 |
48 | onTextFieldDetachWithIME : (sender) ->
49 |
50 | onTextFieldInsertText : (sender, text, len) ->
51 |
52 | onTextFieldDeleteBackward : (sender, delText, len) ->
53 |
54 | _textInputGetRect : (node) ->
55 | r = cc.rect node.x, node.y, node.width, node.height
56 | r.x -= r.width / 2
57 | r.y -= r.height / 2
58 | r
59 |
60 | _onClickTrackNode : (clicked) ->
61 | #@_textField.setPlaceHolder ""
62 | if clicked
63 | @_textField.attachWithIME()
64 | else
65 | @_textField.detachWithIME()
66 |
67 | _onMouseUp : (event) ->
68 | target = event.getCurrentTarget()
69 | return unless target._textField
70 | point = event.getLocation()
71 | rect = target._textInputGetRect target._textField
72 | target._onClickTrackNode cc.rectContainsPoint(rect, point)
73 |
74 | onExit : ->
75 | @_super()
76 | @unscheduleUpdate()
77 | @removeAllChildren on
78 |
79 | module.exports = SearchLayer
80 |
--------------------------------------------------------------------------------
/test/src/test-judgementLayer.coffee:
--------------------------------------------------------------------------------
1 | JudgementLayerTest = cc.Class.extend
2 | start : ->
3 | describe 'judgement layer class test', ->
4 | @timeout 10000
5 | JudgementLayer = require '../../src/judgementLayer'
6 | $ = require 'jquery'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'show judgement test', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 | size = cc.director.getWinSize()
17 | judgement = new JudgementLayer
18 | src : '../res/judge-image.png'
19 | width : 51
20 | height : 15
21 | x : size.width / 2
22 | y : size.height / 2
23 | judgement.init()
24 | @addChild judgement
25 |
26 | showGreat = ->
27 | d = new $.Deferred
28 | judgement.show 0, 0, 0.5
29 | setTimeout ->
30 | capture "test/capture/judgementLayer/judgement" + capNum++
31 | d.resolve()
32 | , 400
33 | d.promise()
34 |
35 | showGood = ->
36 | d = new $.Deferred
37 | judgement.show 1, 0, 0.5
38 | setTimeout ->
39 | capture "test/capture/judgementLayer/judgement" + capNum++
40 | d.resolve()
41 | , 400
42 | d.promise()
43 |
44 | showBad = ->
45 | d = new $.Deferred
46 | judgement.show 2, 0, 0.5
47 | setTimeout ->
48 | capture "test/capture/judgementLayer/judgement" + capNum++
49 | d.resolve()
50 | , 400
51 | d.promise()
52 |
53 | showPoor = ->
54 | d = new $.Deferred
55 | judgement.show 3, 0, 0.5
56 | setTimeout ->
57 | capture "test/capture/judgementLayer/judgement" + capNum++
58 | d.resolve()
59 | , 400
60 | d.promise()
61 |
62 | showGreat()
63 | .then showGood
64 | .then showBad
65 | .then showPoor
66 | .then ->
67 | setTimeout ->
68 | done()
69 | , 500
70 |
71 | cc.director.runScene new TestScene()
72 |
73 | module.exports = JudgementLayerTest
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/rateLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayer = require './numeralLayer'
2 |
3 | RateLayer = cc.Layer.extend
4 | ctor : (@_skin) ->
5 | @_super()
6 | @_label = new NumeralLayer @_skin.label
7 | @_sprites = []
8 | @_count = 0
9 |
10 | init : (@_config) ->
11 | @_batchNode = new cc.SpriteBatchNode @_skin.meter.src
12 | @addChild @_batchNode
13 | @_frames = for i in [0...4]
14 | new cc.SpriteFrame @_batchNode.texture, cc.rect @_skin.meter.width * i, 0, @_skin.meter.width, @_skin.meter.height
15 |
16 | for i in [0...@_config.num]
17 | @_sprites[i] = new cc.Sprite()
18 | @_sprites[i].setSpriteFrame @_frames[0]
19 | @_sprites[i].x = cc.screenSize.width / 2 + @_skin.meter.x + i * @_skin.meter.width
20 | @_sprites[i].y = cc.screenSize.height - @_skin.meter.y
21 | @_batchNode.addChild @_sprites[i]
22 | @_rate = @_config.initRate
23 |
24 | @_label.init 3, 0
25 | @_label.x = cc.screenSize.width / 2 + @_skin.label.x
26 | @_label.y = cc.screenSize.height - @_skin.label.y
27 | @addChild @_label
28 | @_label.reflect ~~(@_rate.toFixed())
29 |
30 | console.log @_config.great
31 |
32 |
33 | get : -> ~~(@_rate.toFixed())
34 |
35 | start : -> @scheduleUpdate()
36 |
37 | update : ->
38 | @_count += 1
39 | return unless @_count % 4 is 0
40 | w = @_skin.meter.width
41 | h = @_skin.meter.height
42 | base = if @_rate - 6 then 0 else @_rate
43 | for i in [base...@_config.num]
44 | if i > @_config.clearVal
45 | if @_rate - 6 <= i * 2 < @_rate - 2
46 | @_sprites[i].setSpriteFrame @_frames[~~(Math.random() * 2) * 2]
47 | else if @_rate - 2 >= i * 2 then @_sprites[i].setSpriteFrame @_frames[0]
48 | else @_sprites[i].setSpriteFrame @_frames[2]
49 | else
50 | if @_rate - 6 <= i * 2 < @_rate - 2 then @_sprites[i].setSpriteFrame @_frames[~~(Math.random() * 2) * 2 + 1]
51 | else if @_rate - 2 >= i * 2 then @_sprites[i].setSpriteFrame @_frames[1]
52 | else @_sprites[i].setSpriteFrame @_frames[3]
53 | return
54 |
55 |
56 | reflect : (judge) ->
57 | switch judge
58 | when "pgreat", "great"
59 | if @_rate + @_config.great >= 100 then @_rate = 100 else @_rate += @_config.great
60 | when "good"
61 | if @_rate + @_config.good >= 100 then @_rate = 100 else @_rate += @_config.good
62 | when "bad"
63 | if @_rate + @_config.bad < 2 then @_rate = 2 else @_rate += @_config.bad
64 | when "poor"
65 | if @_rate + @_config.poor < 2 then @_rate = 2 else @_rate += @_config.poor
66 | when "epoor"
67 | @_rate = if @_rate + @_config.epoor < 2 then @_rate = 2 else @_rate += @_config.epoor
68 | else
69 |
70 | @_label.reflect ~~(@_rate.toFixed())
71 |
72 | module.exports = RateLayer
73 |
--------------------------------------------------------------------------------
/res/loading.js:
--------------------------------------------------------------------------------
1 | (function(){var createStyle=function(){return".cocosLoading{position:absolute;margin:-30px -60px;padding:0;top:50%;left:50%}"+".cocosLoading ul{margin:0;padding:0;}"+".cocosLoading span{color:#FFF;text-align:center;display:block;}"+".cocosLoading li{list-style:none;float:left;border-radius:15px;width:15px;height:15px;background:#FFF;margin:5px 0 0 10px}"+".cocosLoading li .ball,.cocosLoading li .unball{background-color:#2187e7;background-image:-moz-linear-gradient(90deg,#2187e7 25%,#a0eaff);background-image:-webkit-linear-gradient(90deg,#2187e7 25%,#a0eaff);width:15px;height:15px;border-radius:50px}"+".cocosLoading li .ball{transform:scale(0);-moz-transform:scale(0);-webkit-transform:scale(0);animation:showDot 1s linear forwards;-moz-animation:showDot 1s linear forwards;-webkit-animation:showDot 1s linear forwards}"+".cocosLoading li .unball{transform:scale(1);-moz-transform:scale(1);-webkit-transform:scale(1);animation:hideDot 1s linear forwards;-moz-animation:hideDot 1s linear forwards;-webkit-animation:hideDot 1s linear forwards}"+"@keyframes showDot{0%{transform:scale(0,0)}100%{transform:scale(1,1)}}"+"@-moz-keyframes showDot{0%{-moz-transform:scale(0,0)}100%{-moz-transform:scale(1,1)}}"+"@-webkit-keyframes showDot{0%{-webkit-transform:scale(0,0)}100%{-webkit-transform:scale(1,1)}}"+"@keyframes hideDot{0%{transform:scale(1,1)}100%{transform:scale(0,0)}}"+"@-moz-keyframes hideDot{0%{-moz-transform:scale(1,1)}100%{-moz-transform:scale(0,0)}}"+"@-webkit-keyframes hideDot{0%{-webkit-transform:scale(1,1)}100%{-webkit-transform:scale(0,0)}}"};var createDom=function(id,num){id=id||"cocosLoading";num=num||5;var i,item;var div=document.createElement("div");div.className="cocosLoading";div.id=id;var bar=document.createElement("ul");var list=[];for(i=0;i=list.length){direction=!direction;index=0;time=1000}else{time=300}animation()},time)};animation()};(function(){var bgColor=document.body.style.background;document.body.style.background="#000";var style=document.createElement("style");style.type="text/css";style.innerHTML=createStyle();document.head.appendChild(style);var list=createDom();startAnimation(list,function(){var div=document.getElementById("cocosLoading");if(!div){document.body.style.background=bgColor}return !!div})})()})();
--------------------------------------------------------------------------------
/test/src/test-numeralLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayerTest = cc.Class.extend
2 |
3 | start : ->
4 | describe 'numeral layer class test', ->
5 | @timeout 10000
6 | NumeralLayer = require '../../src/numeralLayer'
7 | capture = require './test-utils'
8 | .capture
9 | expect = chai.expect
10 | capNum = 0
11 |
12 | it 'numeral layer create and reflect test', (done)->
13 | TestScene = cc.Scene.extend
14 | onEnter : ->
15 | @_super()
16 |
17 | numeralLayer = new NumeralLayer
18 | src : '../res/numeral-font.png'
19 | width : 29.5
20 | height : 36.5
21 | scale : 0.35
22 | margin : 3
23 | numeralLayer.init 10, 0
24 | size = cc.director.getWinSize()
25 | numeralLayer.x = size.width / 2
26 | numeralLayer.y = size.height / 2
27 | @addChild numeralLayer
28 |
29 | expect @children.length
30 | .to.be.equal 1
31 |
32 | setTimeout =>
33 | numeralLayer.reflect 123456789
34 | capture "test/capture/numeralLayer/num" + capNum++
35 | , 1000
36 |
37 | setTimeout =>
38 | numeralLayer.reflect 9876543210
39 | capture "test/capture/numeralLayer/num" + capNum++
40 | , 2000
41 |
42 | setTimeout =>
43 | capture "test/capture/numeralLayer/num" + capNum++
44 | done()
45 | , 3000
46 |
47 | cc.director.runScene new TestScene()
48 |
49 | it 'numeral layer create and reflect test x2', (done)->
50 | TestScene = cc.Scene.extend
51 | onEnter : ->
52 | @_super()
53 |
54 | numeralLayer = new NumeralLayer
55 | src : '../res/numeral-font.png'
56 | width : 29.5
57 | height : 36.5
58 | scale : 0.7
59 | margin : 3
60 | numeralLayer.init 10, 0
61 | size = cc.director.getWinSize()
62 | numeralLayer.x = size.width / 2
63 | numeralLayer.y = size.height / 2
64 | @addChild numeralLayer
65 |
66 | expect @children.length
67 | .to.be.equal 1
68 |
69 | setTimeout =>
70 | numeralLayer.reflect 123456789
71 | capture "test/capture/notes/notes" + capNum++
72 | , 1000
73 |
74 | setTimeout =>
75 | numeralLayer.reflect 9876543210
76 | capture "test/capture/notes/notes" + capNum++
77 | , 2000
78 |
79 | setTimeout =>
80 | capture "test/capture/notes/notes" + capNum++
81 | done()
82 | , 3000
83 |
84 | cc.director.runScene new TestScene()
85 |
86 | before ->
87 |
88 | after ->
89 |
90 | module.exports = NumeralLayerTest
91 |
92 |
93 |
--------------------------------------------------------------------------------
/test/src/test-parser.coffee:
--------------------------------------------------------------------------------
1 | ParserTest = cc.Class.extend
2 |
3 | start : ->
4 | expect = chai.expect
5 | Parser = require '../../src/parser'
6 |
7 | describe 'Parser class test', ->
8 | parser = null
9 |
10 | it 'parse WAV', ->
11 | text = """
12 | #WAV00 test1.ogg
13 | #WAV01 test2.ogg
14 | #WAV02 test3.ogg
15 | #WAV04 test4.ogg
16 | """
17 | parser = new Parser()
18 | result = parser.parse(text)
19 | expect(result.wav[0]).to.be.equal('test1.ogg')
20 | expect(result.wav[1]).to.be.equal('test2.ogg')
21 | expect(result.wav[2]).to.be.equal('test3.ogg')
22 | expect(result.wav[4]).to.be.equal('test4.ogg')
23 |
24 | it 'parse BMP', ->
25 | text = """
26 | #BMP00 test1.bmp
27 | #BMP01 test2.bmp
28 | #BMP02 test3.bmp
29 | #BMP04 test4.bmp
30 | """
31 | parser = new Parser()
32 | result = parser.parse(text)
33 | expect(result.bmp[0]).to.be.equal('test1.bmp')
34 | expect(result.bmp[1]).to.be.equal('test2.bmp')
35 | expect(result.bmp[2]).to.be.equal('test3.bmp')
36 | expect(result.bmp[4]).to.be.equal('test4.bmp')
37 |
38 | it 'parse property', ->
39 | text = """
40 | #PLAYER 1
41 | #GENRE hoge
42 | #BPM 55
43 | """
44 | parser = new Parser()
45 | result = parser.parse(text)
46 | expect(result.player).to.be.equal('1')
47 | expect(result.genre).to.be.equal('hoge')
48 | expect(result.bpm).to.be.equal('55')
49 |
50 | it 'parse channel message', ->
51 | text = """
52 | #00011:11111111
53 | #00011:0022332255224400
54 | #00011:0066
55 | """
56 | parser = new Parser()
57 | result = parser.parse(text)
58 |
59 | expect(result.data[0].note.key[0].id[0]).to.be.equal(parseInt('11', 36))
60 | expect(result.data[0].note.key[0].id[1]).to.be.equal(parseInt('22', 36))
61 | expect(result.data[0].note.key[0].id[2]).to.be.equal(parseInt('33', 36))
62 | expect(result.data[0].note.key[0].id[3]).to.be.equal(parseInt('22', 36))
63 | expect(result.data[0].note.key[0].id[4]).to.be.equal(parseInt('66', 36))
64 | expect(result.data[0].note.key[0].id[5]).to.be.equal(parseInt('22', 36))
65 | expect(result.data[0].note.key[0].id[6]).to.be.equal(parseInt('44', 36))
66 |
67 | expect(result.totalNote).to.be.equal(7)
68 |
69 | it 'parse WAV', ->
70 | text = """
71 | #PLAYER 1
72 | #GENRE hoge
73 | #BPM 60
74 |
75 | #00001:6F
76 | #00001:0007000700070007
77 | #00001:3B
78 | """
79 | parser = new Parser()
80 | result = parser.parse(text)
81 |
82 | #FIXME: 上2つは同時なので順序が入れ替わる可能性がある
83 | expect(result.data[0].wav.id[0]).to.be.equal(parseInt('6F', 36))
84 | expect(result.data[0].wav.id[1]).to.be.equal(parseInt('3B', 36))
85 | expect(result.data[0].wav.id[2]).to.be.equal(parseInt('07', 36))
86 | expect(result.data[0].wav.id[3]).to.be.equal(parseInt('07', 36))
87 | expect(result.data[0].wav.id[4]).to.be.equal(parseInt('07', 36))
88 | expect(result.data[0].wav.id[5]).to.be.equal(parseInt('07', 36))
89 |
90 | it 'parse BMP', ->
91 | text = """
92 | #00004:11111111
93 | #00004:0022332255224400
94 | #00004:0066
95 | """
96 | parser = new Parser()
97 | result = parser.parse(text)
98 |
99 | expect(result.data[0].bmp.id[0]).to.be.equal(parseInt('11', 36))
100 | expect(result.data[0].bmp.id[1]).to.be.equal(parseInt('22', 36))
101 | expect(result.data[0].bmp.id[2]).to.be.equal(parseInt('33', 36))
102 | expect(result.data[0].bmp.id[3]).to.be.equal(parseInt('22', 36))
103 | expect(result.data[0].bmp.id[4]).to.be.equal(parseInt('66', 36))
104 | expect(result.data[0].bmp.id[5]).to.be.equal(parseInt('22', 36))
105 | expect(result.data[0].bmp.id[6]).to.be.equal(parseInt('44', 36))
106 |
107 | it 'calc total note', ->
108 | text = """
109 | #PLAYER 1
110 | #GENRE hoge
111 | #BPM 60
112 |
113 | #00011:1111
114 | #00012:0022332255224400
115 | #00013:0066
116 |
117 | #00111:1212
118 | #00211:13
119 | """
120 | parser = new Parser()
121 | result = parser.parse(text)
122 |
123 | expect(result.totalNote).to.be.equal(12)
124 |
125 |
126 | module.exports = ParserTest
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/statsLayer.coffee:
--------------------------------------------------------------------------------
1 | NumeralLayer = require './numeralLayer'
2 | JudgementLayer = require './judgementLayer'
3 |
4 | StatsLayer = cc.Layer.extend
5 | ctor: (@_skin) ->
6 | @_super()
7 | @_scoreLabel = new NumeralLayer @_skin.score
8 | @_pgreatLabel = new NumeralLayer @_skin.pgreatNum
9 | @_greatLabel = new NumeralLayer @_skin.greatNum
10 | @_goodLabel = new NumeralLayer @_skin.goodNum
11 | @_badLabel = new NumeralLayer @_skin.badNum
12 | @_poorLabel = new NumeralLayer @_skin.poorNum
13 | @_comboLabel = new NumeralLayer @_skin.comboNum
14 | @_judgement = new JudgementLayer @_skin.judge
15 | @addChild @_scoreLabel
16 | @addChild @_pgreatLabel
17 | @addChild @_greatLabel
18 | @addChild @_goodLabel
19 | @addChild @_badLabel
20 | @addChild @_poorLabel
21 | @addChild @_comboLabel
22 | @addChild @_judgement
23 |
24 | init : (@_noteNum, maxScore) ->
25 | @_score = 0
26 | @_dispScore = 0
27 | @_maxCombo = 0
28 | @_combo = 0
29 | @_pgreatNum = 0
30 | @_greatNum = 0
31 | @_goodNum = 0
32 | @_badNum = 0
33 | @_poorNum = 0
34 | @_comboPoint = 0
35 | @_pgreatIncVal = maxScore.pgreat / @_noteNum
36 | @_greatIncVal = maxScore.great / @_noteNum
37 | @_goodIncVal = maxScore.good / @_noteNum
38 | @_comboBonusFactor = maxScore.combo / (10 * (@_noteNum - 1) - 55)
39 | @_incValonUpdate = maxScore.pgreat / @_noteNum / 2
40 | @_judgement.init()
41 |
42 | @_scoreLabel.init @_getDigits(maxScore.pgreat + maxScore.combo), 0
43 | @_scoreLabel.x = cc.screenSize.width / 2 + @_skin.score.x
44 | @_scoreLabel.y = cc.screenSize.height - @_skin.score.y
45 | #@_pgreatLabel = new cc.LabelTTF ' 0', "Arial", 6, cc.size(40, 0), cc.TEXT_ALIGNMENT_LEFT
46 | @_pgreatLabel.init 4, 0
47 | @_pgreatLabel.x = cc.screenSize.width / 2 + @_skin.pgreatNum.x
48 | @_pgreatLabel.y = cc.screenSize.height - @_skin.pgreatNum.y
49 | #@_greatLabel = new cc.LabelTTF ' 0', "Arial", 6, cc.size(40, 0), cc.TEXT_ALIGNMENT_LEFT
50 | @_greatLabel.init 4, 0
51 | @_greatLabel.x = cc.screenSize.width / 2 + @_skin.greatNum.x
52 | @_greatLabel.y = cc.screenSize.height - @_skin.greatNum.y
53 | #@_goodLabel = new cc.LabelTTF ' 0', "Arial", 6, cc.size(40, 0), cc.TEXT_ALIGNMENT_LEFT
54 | @_goodLabel.init 4, 0
55 | @_goodLabel.x = cc.screenSize.width / 2 + @_skin.goodNum.x
56 | @_goodLabel.y = cc.screenSize.height - @_skin.goodNum.y
57 | #@_badLabel = new cc.LabelTTF ' 0', "Arial", 6, cc.size(40, 0), cc.TEXT_ALIGNMENT_LEFT
58 | @_badLabel.init 4, 0
59 | @_badLabel.x = cc.screenSize.width / 2 + @_skin.badNum.x
60 | @_badLabel.y = cc.screenSize.height - @_skin.badNum.y
61 | #@_poorLabel = new cc.LabelTTF ' 0', "Arial", 6, cc.size(40, 0), cc.TEXT_ALIGNMENT_LEFT
62 | @_poorLabel.init 4, 0
63 | @_poorLabel.x = cc.screenSize.width / 2 + @_skin.poorNum.x
64 | @_poorLabel.y = cc.screenSize.height - @_skin.poorNum.y
65 | @_comboLabel.init 4, 0
66 | @_comboLabel.x = cc.screenSize.width / 2 + @_skin.comboNum.x
67 | @_comboLabel.y = cc.screenSize.height - @_skin.comboNum.y
68 |
69 | get : ->
70 | score : ~~(@_score.toFixed())
71 | combo : @_maxCombo
72 | pgreat : @_pgreatNum
73 | great : @_greatNum
74 | good : @_goodNum
75 | bad : @_badNum
76 | poor : @_poorNum
77 |
78 | start : -> @scheduleUpdate()
79 |
80 | reflect : (judge) ->
81 | switch judge
82 | when "pgreat"
83 | @_score += @_pgreatIncVal
84 | @_combo++
85 | @_pgreatNum++
86 | #@_pgreatLabel.setString " #{@_pgreatNum}"
87 | @_pgreatLabel.reflect @_pgreatNum
88 | @_judgement.show 0, 0, 1
89 |
90 | when "great"
91 | @_score += @_greatIncVal
92 | @_combo++
93 | @_greatNum++
94 | #@_greatLabel.setString " #{@_greatNum}"
95 | @_greatLabel.reflect @_greatNum
96 | @_judgement.show 1, 0, 0.5
97 |
98 | when "good"
99 | @_score += @_goodIncVal
100 | @_combo++
101 | @_goodNum++
102 | #@_goodLabel.setString " #{@_goodNum}"
103 | @_goodLabel.reflect @_goodNum
104 | @_judgement.show 2, 0, 0.5
105 |
106 | when "bad"
107 | @_score += @_comboBonusFactor * @_comboPoint
108 | @_combo = 0
109 | @_comboPoint = 0
110 | @_badNum++
111 | #@_badLabel.setString " #{@_badNum}"
112 | @_badLabel.reflect @_badNum
113 | @_judgement.show 3, 0, 0.5
114 |
115 | else # poor or epoor
116 | @_score += @_comboBonusFactor * @_comboPoint
117 | @_combo = 0
118 | @_comboPoint = 0
119 | @_poorNum++
120 | #@_poorLabel.setString " #{@_poorNum}"
121 | @_poorLabel.reflect @_poorNum
122 | @_judgement.show 4, 0, 0.5
123 |
124 | # full combo
125 | if @_combo is @_noteNum
126 | @_score += @_comboBonusFactor * @_comboPoint
127 | @_comboPoint = 0
128 | @_incValonUpdate = @_incValonUpdate * 5
129 |
130 | if 0 < @_combo <= 10
131 | @_comboPoint += @_combo - 1
132 | else if @_combo > 10
133 | @_comboPoint += 10
134 |
135 | if @_combo > @_maxCombo
136 | @_maxCombo = @_combo
137 | @_comboLabel.reflect @_maxCombo
138 |
139 | #@_dispScore = ~~(@_score.toFixed())
140 | #@_scoreLabel.reflect @_dispScore
141 |
142 | update : ->
143 | if @_dispScore < ~~(@_score.toFixed())
144 | @_dispScore += @_incValonUpdate
145 | @_dispScore = if @_dispScore > ~~(@_score.toFixed()) then ~~(@_score.toFixed()) else @_dispScore
146 | @_scoreLabel.reflect @_dispScore
147 |
148 | _getDigits : (num)-> Math.log(num) / Math.log(10) + 1 | 0
149 |
150 | module.exports = StatsLayer
151 |
--------------------------------------------------------------------------------
/src/menuScene.coffee:
--------------------------------------------------------------------------------
1 | AppScene = require './app'
2 | Parser = require './parser'
3 | SearchLayer = require './searchLayer'
4 | LevelFont = require './numeralLayer'
5 | res = require './resource'
6 | .resObjs
7 |
8 | MenuBaseLayer = cc.Layer.extend
9 | ctor : ->
10 | @_super()
11 | if window?
12 | window.addEventListener 'resize', ->
13 | screenSize = window.parent.screen
14 | cc.view.setDesignResolutionSize screenSize.width, screenSize.height, cc.ResolutionPolicy.SHOW_ALL
15 |
16 | start : ->
17 | if cc.sys.isMobile
18 | message = """
19 | 申し訳ありません
20 | 現在PCにのみ対応しております
21 |
22 | """
23 | pconly = new cc.LabelTTF message , "Arial" , 16
24 | pconly.x = cc.screenSize.width / 2
25 | pconly.y = cc.screenSize.height / 2
26 | @addChild pconly, 100
27 | return
28 | @_addBackground()
29 | cc.loader.loadJson cc.pathToBmsDir + 'bms.json', (error, data) =>
30 | menu = new MenuController data
31 | menu.init data, cc.director.getWinSize().width / 2 + 200, 70
32 | @addChild menu
33 |
34 | onExit : ->
35 | @_super()
36 | @removeAllChildren on
37 |
38 | _addBackground : ->
39 | bg = new cc.Sprite res.menuBgImage
40 | bg.x = cc.director.getWinSize().width / 2
41 | bg.y = cc.director.getWinSize().height / 2
42 | console.log "scree height #{window.parent.screen.height} bg.height = #{bg.height}"
43 | #if bg.height < window.parent.screen.height
44 | bg.scale = window.parent.screen.height / bg.height
45 | @addChild bg, 0
46 |
47 | MenuController = cc.Layer.extend
48 | ctor : (data) ->
49 | @_super()
50 | @_offsetY = 0
51 | @_menuList = data
52 |
53 | init : (list, x, @_linespace) ->
54 | director = cc.director
55 | size = director.getWinSize()
56 | @_itemMenu = new cc.Menu()
57 | for v, i in list when v.TITLE?
58 |
59 | item = new cc.Sprite res.itemBgImage
60 | title = if v.TITLE.length > 26 then v.TITLE.substr(0, 26)+'...' else v.TITLE
61 | label = new cc.LabelTTF title, "Arial", 22, cc.size(item.width, 0), cc.TEXT_ALIGNMENT_LEFT
62 | label.x = 320
63 | label.y = 38
64 | item.addChild label
65 |
66 | # TODO : to cson
67 | level = new LevelFont
68 | src : res.levelFontImage
69 | width : 26.2
70 | height : 16
71 | scale : 1
72 | margin : 0
73 | level.x = 34
74 | level.y = 39
75 |
76 | item.addChild level
77 | digits = if ~~(v.level / 10) > 0 then 2 else 1
78 | level.init digits, v.PLAYLEVEL
79 | menuItem = new cc.MenuItemSprite item, null, null, @_onMenuCallback, this
80 | @_itemMenu.addChild menuItem, i + 10000
81 | menuItem.x = x
82 | menuItem.y = size.height - (i + 1) * @_linespace
83 | menuItem.title = v.TITLE
84 |
85 | @_itemMenu.width = size.width
86 | @_itemMenu.height = (list.length + 1) * @_linespace
87 | @_itemMenu.x = 0
88 | @_itemMenu.y = (@_itemMenu.height - size.height) / 2
89 | @addChild @_itemMenu
90 |
91 | search = new SearchLayer()
92 | search.init @_itemMenu.children
93 | search.start()
94 | search.addListener 'change', @_onChanged.bind this
95 | @addChild search
96 |
97 | # 'browser' can use touches or mouse.
98 | # The benefit of using 'touches' in a browser, is that it works both with mouse events or touches events
99 | if 'touches' of cc.sys.capabilities
100 | cc.eventManager.addListener
101 | event : cc.EventListener.TOUCH_ALL_AT_ONCE
102 | onTouchesMoved : (touches, event) ->
103 | target = event.getCurrentTarget()
104 | delta = touches[0].getDelta()
105 | target._moveMenu delta
106 | return true
107 | , this
108 | else if 'mouse' of cc.sys.capabilities
109 | cc.eventManager.addListener
110 | event : cc.EventListener.MOUSE
111 | onMouseMove : (event) ->
112 | if event.getButton() is cc.EventMouse.BUTTON_LEFT
113 | event.getCurrentTarget()._moveMenu event.getDelta()
114 | onMouseScroll : (event) ->
115 | deltaY = if cc.sys.isNative then event.getScrollY() * 6 else -event.getScrollY()
116 | event.getCurrentTarget()._moveMenu
117 | y : deltaY
118 | , this
119 |
120 | onExit : ->
121 | @_super()
122 | @removeAllChildren on
123 |
124 | _moveMenu : (delta) ->
125 | newY = @_itemMenu.y + delta.y
126 | size = cc.director.getWinSize()
127 | if @_itemMenu.height < size.height
128 | newY = (@_itemMenu.height - size.height) / 2
129 | else
130 | if newY < 0
131 | @_itemMenu.y = 0
132 | move = cc.moveBy 0.05, 0, 20
133 | else if newY > @_itemMenu.height - size.height
134 | @_itemMenu.y = @_itemMenu.height - size.height
135 | else
136 | @_itemMenu.y = newY
137 |
138 | _getPrefix : (url)->
139 | m = /^.+\//.exec url
140 | m[0] if m
141 |
142 | _onMenuCallback : (sender) ->
143 | @_offsetY = @_itemMenu.y
144 | id = sender.getLocalZOrder() - 10000
145 | url = @_menuList[id].url
146 | prefix = @_getPrefix url
147 |
148 | cc.loader.loadTxt cc.pathToBmsDir + url, (err, text) =>
149 | parser = new Parser()
150 | bms = parser.parse text
151 | resources = []
152 | for k, v of bms.wav then resources.push (prefix + encodeURIComponent(v))
153 | #for k, v of bms.bmp then resources.push prefix + v
154 |
155 | require('./loaderScene').preload resources, ->
156 | cc.director.runScene new AppScene bms, prefix
157 | , this
158 |
159 | _onChanged : (name, visibleItems) ->
160 | size = cc.director.getWinSize()
161 |
162 | for item in @_itemMenu.children
163 | item.runAction cc.spawn cc.fadeOut(0.2), cc.scaleTo(0.2, 0)
164 |
165 | for item, i in visibleItems
166 | item.stopAllActions()
167 | destY = size.height - (i + 1) * @_linespace
168 | item.runAction(
169 | cc.spawn(
170 | cc.fadeIn 0.2
171 | cc.scaleTo 0.2, 1
172 | cc.moveTo 0.2, cc.p(size.width / 2 + 200, destY)
173 | )
174 | )
175 |
176 | @_itemMenu.height = (visibleItems.length + 1) * @_linespace
177 | @_itemMenu.y = (@_itemMenu.height - size.height) / 2
178 |
179 | MenuScene = cc.Scene.extend
180 | ctor : ->
181 | @_super()
182 | layer = new MenuBaseLayer()
183 | @addChild layer
184 | layer.start()
185 |
186 | onExit : ->
187 | @_super()
188 | @removeAllChildren on
189 |
190 | module.exports = MenuScene
191 |
--------------------------------------------------------------------------------
/src/notesLayer.coffee:
--------------------------------------------------------------------------------
1 | EventObserver = require './eventObserver'
2 | Judge = require './judge'
3 | Note = require './note'
4 | GreatEffectsLayer = require './greatEffectsLayer'
5 | KeyEffectsLayer = require './keyEffectsLayer'
6 | MeasureNode = require './measureNode'
7 |
8 | NotesLayer = cc.Layer.extend
9 | ctor : (@_skin, @_timer, @_config)->
10 | @_super()
11 | @_notifier = new EventObserver()
12 | @_judge = new Judge @_config.judge
13 | @_greatEffectsLayer = new GreatEffectsLayer @_skin.greatEffect
14 | @_keyEffectsLayer = new KeyEffectsLayer @_skin.keyEffect
15 | @_notes = []
16 | @_nodes = []
17 | @_genTime = []
18 |
19 | #
20 | # create notes
21 | #
22 | init : (bms)->
23 | time = 0
24 | @_index = 0
25 | @_notes.length = 0
26 | @_nodes.length = 0
27 | @_genTime.length = 0
28 |
29 | for v, i in bms.data
30 | node = new MeasureNode @_skin.nodeImage.src, @_timer
31 | node.x = cc.screenSize.width / 2 + @_skin.nodeImage.x
32 | node.y = -node.height
33 | node.timing = v.timing
34 | node.appendFallParams bms.bpms, time, @_skin.fallDist
35 | @_genTime.push time
36 | time = @_getGenTime node, @_skin.fallDist
37 | @_nodes.push node
38 | node.retain()
39 |
40 | @_genTime.sort (a, b) -> a - b
41 |
42 | bg = new cc.Sprite @_skin.bgImage.src
43 | bg.setAnchorPoint cc.p(0.5, 0)
44 | bg.x = cc.screenSize.width / 2 + @_skin.bgImage.x
45 | bg.y = cc.screenSize.height - @_skin.bgImage.y
46 | bg.setOpacity 180
47 | @addChild bg, 0
48 | @_greatEffectsLayer.init bms.totalNote
49 | @addChild @_greatEffectsLayer, 200
50 |
51 | @_generate bms, measure, time for time, measure in @_genTime
52 | xList = for i in [0...@_skin.keyNum] then @_calcNoteXCoordinate i
53 | @_keyEffectsLayer.init xList
54 | @addChild @_keyEffectsLayer, 0
55 |
56 | addListener: (name, listner)->
57 | @_notifier.on name, listner
58 |
59 | #
60 | # generate and pool note
61 | #
62 | _generate : (bms, measure, time)->
63 | turntable = @_skin.noteTurntableImage
64 | white = @_skin.noteWhiteImage
65 | black = @_skin.noteBlackImage
66 | fallDist = @_skin.fallDist
67 | bpms = bms.bpms
68 | @_notes[measure] ?= []
69 |
70 | @_batchNodes = {}
71 | @_batchNodes["white"] = new cc.SpriteBatchNode white.src
72 | @_batchNodes["black"] = new cc.SpriteBatchNode black.src
73 | @_batchNodes["turntable"] = new cc.SpriteBatchNode turntable.src
74 | @addChild v, 100 for k, v of @_batchNodes
75 |
76 | return unless bms.data[measure]?
77 | for key, i in bms.data[measure].note.key
78 | for timing, j in key.timing
79 | switch i
80 | when 0, 2, 4, 6 then type = "white"
81 | when 1, 3, 5 then type = "black"
82 | when 7 then type = "turntable"
83 | else throw new Error "error unlnown note"
84 |
85 | note = new Note @_batchNodes[type].getTexture(), @_timer, @_config.removeTime
86 | note.type = type
87 | note.x = @_calcNoteXCoordinate i
88 | note.y = -note.height
89 | note.setAnchorPoint cc.p(0.5,0)
90 | note.timing = timing
91 | note.wav = key.id[j]
92 | note.key = i
93 | note.clear = false
94 | note.addListener 'remove', @_onRemove.bind this
95 | note.appendFallParams bpms, time, fallDist
96 | note.retain()
97 | @_notes[measure].push note
98 | return
99 |
100 | #
101 | # calculate
102 | #
103 | _calcNoteXCoordinate : (id)->
104 | turntable = @_skin.noteTurntableImage
105 | white = @_skin.noteWhiteImage
106 | black = @_skin.noteBlackImage
107 | offset = cc.screenSize.width / 2 + @_skin.offsetX
108 | margin = (id + 1) * @_skin.marginX
109 | switch id
110 | when 0, 2, 4, 6
111 | ~~(id / 2) * (black.width + white.width) + (turntable.width + white.width) / 2 + offset + margin
112 | when 1, 3, 5
113 | ~~(id / 2) * (black.width + white.width) + (turntable.width + black.width) / 2 + offset + margin + white.width
114 | when 7
115 | offset
116 | else throw new Error "error unlnown note"
117 |
118 | #
119 | # start note update
120 | #
121 | # @param isAuto -
122 | #
123 | start : (autoplay = false)->
124 | @scheduleUpdate()
125 | @_isAuto = autoplay
126 |
127 | onTouch : (key, time)->
128 | return if @_isAuto
129 | @_keyEffectsLayer.show key, 0.5
130 | for batchNode in @children
131 | for note in batchNode.children when note.key is key
132 | diffTime = note.timing - time
133 | unless note.clear
134 | if -@_config.reactionTime < diffTime < @_config.reactionTime
135 | note.clear = true
136 | @_notifier.trigger 'hit', note.wav
137 | judgement = @_judge.exec diffTime
138 | @_notifier.trigger 'judge', judgement
139 | if judgement is 'pgreat' or 'great'
140 | size = cc.director.getWinSize()
141 | y = size.height - @_skin.fallDist
142 | @_greatEffectsLayer.run note.x, y
143 | return
144 | else
145 | @_notifier.trigger 'judge', 'epoor'
146 | return
147 | return
148 |
149 | #
150 | # add note to game scene
151 | # @attention - _add called by window
152 | #
153 | update : ->
154 | if @_isAuto
155 | for batchNode in @children
156 | for note in batchNode.children when note.clear is false
157 | if @_timer.get() >= note.timing
158 | @_keyEffectsLayer.show note.key, 0.5
159 | note.clear = true
160 | y = cc.director.getWinSize().height - @_skin.fallDist
161 | @_greatEffectsLayer.run note.x, y
162 | @_notifier.trigger 'hit', note.wav
163 | @_notifier.trigger 'judge', 'pgreat'
164 |
165 | unless @_genTime[@_index]?
166 | #@_notifier.trigger 'end'
167 | return
168 |
169 | return unless @_genTime[@_index] <= @_timer.get()
170 | @addChild @_nodes[@_index], 99
171 | @_nodes[@_index].start()
172 | for note in @_notes[@_index]
173 | @_batchNodes[note.type].addChild note, 99
174 | note.start()
175 | @_index++
176 |
177 | _onRemove : (event, note) ->
178 | @_notifier.trigger 'judge', 'poor' unless note.clear
179 |
180 | #
181 | # get time when node y coordinate will be game.height
182 | # to generate next node
183 | #
184 | _getGenTime : (obj, fallDist)->
185 | size = cc.director.getWinSize()
186 | for v, i in obj.dstY when v < size.height
187 | return ~~(obj.bpm.timing[i] - (v / obj.calcSpeed(obj.bpm.val[i], fallDist)))
188 | return 0
189 |
190 | module.exports = NotesLayer
191 |
--------------------------------------------------------------------------------
/test/src/test-statsLayer.coffee:
--------------------------------------------------------------------------------
1 | skin =
2 | z : 10
3 | judge :
4 | src : '../res/judge-image.png'
5 | width : 51
6 | height : 15
7 | x : 216
8 | y : 340
9 | score :
10 | src : '../res/numeral-font.png'
11 | width : 29.5
12 | height : 36.5
13 | scale : 0.35
14 | margin : 3
15 | x : 202
16 | y : 175
17 | pgreatNum :
18 | src : '../res/numeral-font.png'
19 | width : 29.5
20 | height : 36.5
21 | scale : 0.35
22 | margin : 3
23 | x : 296
24 | y : 174
25 | greatNum :
26 | src : '../res/numeral-font.png'
27 | width : 29.5
28 | height : 36.5
29 | scale : 0.35
30 | margin : 2
31 | x : 296
32 | y : 165
33 | goodNum :
34 | src : '../res/numeral-font.png'
35 | width : 29.5
36 | height : 36.5
37 | scale : 0.35
38 | margin : 3
39 | x : 296
40 | y : 156
41 | badNum :
42 | src : '../res/numeral-font.png'
43 | width : 29.5
44 | height : 36.5
45 | scale : 0.35
46 | margin : 3
47 | x : 297
48 | y : 147
49 | poorNum :
50 | src : '../res/numeral-font.png'
51 | width : 29.5
52 | height : 36.5
53 | scale : 0.35
54 | margin : 3
55 | x : 297
56 | y : 138
57 | comboNum :
58 | src : '../res/numeral-font.png'
59 | width : 29.5
60 | height : 36.5
61 | scale : 0.35
62 | margin : 3
63 | x : 211
64 | y : 156
65 |
66 |
67 | StatsLayerTest = cc.Class.extend
68 | start : ->
69 | describe 'stats layer class test', ->
70 | TEST_NOTE_NUM = 30
71 | @timeout 10000
72 | StatsLayer = require '../../src/statsLayer'
73 | capture = require './test-utils'
74 | .capture
75 | expect = chai.expect
76 | capNum = 0
77 |
78 | config =
79 | pgreat : 150000
80 | great : 100000
81 | good : 20000
82 | combo : 50000
83 |
84 | it 'initialize stats and capture stats', (done)->
85 | TestScene = cc.Scene.extend
86 | onEnter : ->
87 | @_super()
88 | size = cc.director.getWinSize()
89 | stats = new StatsLayer skin
90 | stats.init TEST_NOTE_NUM, config
91 | @addChild stats
92 | expect(stats.get().score).to.be.equal 0
93 | expect(stats.get().combo).to.be.equal 0
94 | expect(stats.get().pgreat).to.be.equal 0
95 | expect(stats.get().great).to.be.equal 0
96 | expect(stats.get().good).to.be.equal 0
97 | expect(stats.get().bad).to.be.equal 0
98 | expect(stats.get().poor).to.be.equal 0
99 | setTimeout =>
100 | capture "test/capture/StatsLayer/stats" + capNum++
101 | done()
102 | , 1000
103 | cc.director.runScene new TestScene()
104 |
105 | it 'score should be 150000 + 50000 when all pgreat', (done)->
106 | TestScene = cc.Scene.extend
107 | onEnter : ->
108 | @_super()
109 | size = cc.director.getWinSize()
110 | stats = new StatsLayer skin
111 | stats.init TEST_NOTE_NUM, config
112 | @addChild stats
113 | stats.reflect 'pgreat' for i in [0...TEST_NOTE_NUM]
114 | expect(stats.get().score).to.be.equal config.pgreat + config.combo
115 | expect(stats.get().combo).to.be.equal TEST_NOTE_NUM
116 | expect(stats.get().pgreat).to.be.equal TEST_NOTE_NUM
117 | expect(stats.get().great).to.be.equal 0
118 | expect(stats.get().good).to.be.equal 0
119 | expect(stats.get().bad).to.be.equal 0
120 | expect(stats.get().poor).to.be.equal 0
121 | setTimeout =>
122 | capture "test/capture/StatsLayer/stats" + capNum++
123 | done()
124 | , 1000
125 | cc.director.runScene new TestScene()
126 |
127 | it 'score should be 100000 + 50000 when all great', (done)->
128 | TestScene = cc.Scene.extend
129 | onEnter : ->
130 | @_super()
131 | size = cc.director.getWinSize()
132 | stats = new StatsLayer skin
133 | stats.init TEST_NOTE_NUM, config
134 | @addChild stats
135 | stats.reflect 'great' for i in [0...TEST_NOTE_NUM]
136 | expect(stats.get().score).to.be.equal config.great + config.combo
137 | expect(stats.get().combo).to.be.equal TEST_NOTE_NUM
138 | expect(stats.get().pgreat).to.be.equal 0
139 | expect(stats.get().great).to.be.equal TEST_NOTE_NUM
140 | expect(stats.get().good).to.be.equal 0
141 | expect(stats.get().bad).to.be.equal 0
142 | expect(stats.get().poor).to.be.equal 0
143 | setTimeout =>
144 | capture "test/capture/StatsLayer/stats" + capNum++
145 | done()
146 | , 1000
147 | cc.director.runScene new TestScene()
148 |
149 | it 'score should be 20000 + 50000 when all good', (done)->
150 | TestScene = cc.Scene.extend
151 | onEnter : ->
152 | @_super()
153 | size = cc.director.getWinSize()
154 | stats = new StatsLayer skin
155 | stats.init TEST_NOTE_NUM, config
156 | @addChild stats
157 | stats.reflect 'good' for i in [0...TEST_NOTE_NUM]
158 | expect(stats.get().score).to.be.equal config.good + config.combo
159 | expect(stats.get().combo).to.be.equal TEST_NOTE_NUM
160 | expect(stats.get().pgreat).to.be.equal 0
161 | expect(stats.get().great).to.be.equal 0
162 | expect(stats.get().good).to.be.equal TEST_NOTE_NUM
163 | expect(stats.get().bad).to.be.equal 0
164 | expect(stats.get().poor).to.be.equal 0
165 | setTimeout =>
166 | capture "test/capture/StatsLayer/stats" + capNum++
167 | done()
168 | , 1000
169 | cc.director.runScene new TestScene()
170 |
171 | it 'score is 0 when all bad', (done)->
172 | TestScene = cc.Scene.extend
173 | onEnter : ->
174 | @_super()
175 | size = cc.director.getWinSize()
176 | stats = new StatsLayer skin
177 | stats.init TEST_NOTE_NUM, config
178 | @addChild stats
179 | stats.reflect 'bad' for i in [0...TEST_NOTE_NUM]
180 | expect(stats.get().score).to.be.equal 0
181 | expect(stats.get().combo).to.be.equal 0
182 | expect(stats.get().pgreat).to.be.equal 0
183 | expect(stats.get().great).to.be.equal 0
184 | expect(stats.get().good).to.be.equal 0
185 | expect(stats.get().bad).to.be.equal TEST_NOTE_NUM
186 | expect(stats.get().poor).to.be.equal 0
187 | setTimeout =>
188 | capture "test/capture/StatsLayer/stats" + capNum++
189 | done()
190 | , 1000
191 | cc.director.runScene new TestScene()
192 |
193 | it 'score is 0 when all poor', (done)->
194 | TestScene = cc.Scene.extend
195 | onEnter : ->
196 | @_super()
197 | size = cc.director.getWinSize()
198 | stats = new StatsLayer skin
199 | stats.init TEST_NOTE_NUM, config
200 | @addChild stats
201 | stats.reflect 'poor' for i in [0...TEST_NOTE_NUM]
202 | expect(stats.get().score).to.be.equal 0
203 | expect(stats.get().combo).to.be.equal 0
204 | expect(stats.get().pgreat).to.be.equal 0
205 | expect(stats.get().great).to.be.equal 0
206 | expect(stats.get().good).to.be.equal 0
207 | expect(stats.get().bad).to.be.equal 0
208 | expect(stats.get().poor).to.be.equal TEST_NOTE_NUM
209 | setTimeout =>
210 | capture "test/capture/StatsLayer/stats" + capNum++
211 | done()
212 | , 1000
213 | cc.director.runScene new TestScene()
214 |
215 | ###
216 | it 'all judge num is 6', (done)->
217 | TestScene = cc.Scene.extend
218 | onEnter : ->
219 | @_super()
220 | size = cc.director.getWinSize()
221 | stats = new StatsLayer skin
222 | stats.init TEST_NOTE_NUM, config
223 | @addChild stats
224 | for i in [0...TEST_NOTE_NUM / 5]
225 | stats.reflect 'pgreat'
226 | stats.reflect 'great'
227 | stats.reflect 'good'
228 | stats.reflect 'bad'
229 | stats.reflect 'poor'
230 | expect(stats.get().score).to.be.equal ~~((MAX_SCORE / TEST_NOTE_NUM * 13.2).toFixed())
231 | expect(stats.get().combo).to.be.equal 3
232 | expect(stats.get().pgreat).to.be.equal 6
233 | expect(stats.get().great).to.be.equal 6
234 | expect(stats.get().good).to.be.equal 6
235 | expect(stats.get().bad).to.be.equal 6
236 | expect(stats.get().poor).to.be.equal 6
237 | setTimeout =>
238 | capture "test/capture/StatsLayer/stats" + capNum++
239 | done()
240 | , 1000
241 | cc.director.runScene new TestScene()
242 | ###
243 | module.exports = StatsLayerTest
244 |
245 |
246 |
--------------------------------------------------------------------------------
/src/parser.coffee:
--------------------------------------------------------------------------------
1 | #_ = require 'lodash'
2 |
3 | Parser = cc.Class.extend
4 | ctor: ->
5 | @bms =
6 | player : null
7 | genre : null
8 | title : null
9 | artist : null
10 | bpm : null
11 | playLevel : null
12 | rank : null
13 | total : null
14 | sategFile : null
15 | keyNum : null
16 | difficulty : null
17 | wav : {}
18 | bmp : {}
19 | data : []
20 | exbpm : {}
21 | stop : {}
22 | totalNote : 0
23 | # OPTIMIZE:
24 | bgms : []
25 | animations : []
26 | bpms : []
27 | stopTiming : []
28 | endTime : 0
29 |
30 | @wavMessages = []
31 |
32 |
33 | parse : (bms_text) ->
34 | @_parse row for row in bms_text.split '\n'
35 | @_modifyAfterParse()
36 | # OPTIMIZE:bpm,bmp,wavは小節に依存しないよう配列に詰めなおす
37 | @bms.bpms[0] =
38 | timing : 0
39 | val : @bms.bpm
40 | @_serialize @bms.bpms, "bpm", @bms.data
41 | @_serialize @bms.animations, "bmp", @bms.data
42 | @_serialize @bms.bgms, "wav", @bms.data
43 | @_serialize @bms.stopTiming, "stop", @bms.data
44 |
45 | console.log "stopTiming"
46 | console.dir @bms.stopTiming
47 |
48 | @bms.totalNote = @_calcTotalNote()
49 |
50 | # total 省略時
51 | unless @bms.total?
52 | @bms.total = 200 + @bms.totalNote
53 | @bms
54 |
55 | _parse : (row) ->
56 | return if row.substring(0, 1) isnt '#'
57 |
58 | wav = /^#WAV(\w{2}) +(.*)/.exec(row)
59 | if wav?
60 | @_parseWAV wav
61 | return
62 |
63 | bmp = /^#BMP(\w{2}) +(.*)/.exec(row)
64 | if bmp?
65 | @_parseBMP bmp
66 | return
67 |
68 | stop = /^#STOP(\w{2}) +(.*)/.exec(row)
69 | if stop?
70 | @_parseSTOP stop
71 | return
72 |
73 | exbpm = /^#BPM(\w{2}) +(.*)/.exec(row)
74 | if exbpm?
75 | @_parseBPM exbpm
76 | return
77 |
78 | channelMsg = /^#([0-9]{3})([0-9]{2}):([\w\.]+)/.exec(row)
79 | if channelMsg?
80 | @_parseChannelMsg channelMsg
81 | return
82 |
83 | property = /^#(\w+) +(.+)/.exec(row)
84 | if property?
85 | @_parseProperty property
86 | return
87 |
88 | _parseWAV : (wav) ->
89 | index = parseInt wav[1], 36
90 | @bms.wav[index] = wav[2]
91 |
92 | _parseBMP : (bmp) ->
93 | index = parseInt bmp[1], 36
94 | @bms.bmp[index] = bmp[2]
95 |
96 | _parseSTOP : (stop) ->
97 | index = parseInt stop[1], 36
98 | @bms.stop[index] = stop[2]
99 |
100 | _parseBPM : (exbpm) ->
101 | index = parseInt exbpm[1], 36
102 | @bms.exbpm[index] = exbpm[2]
103 |
104 | _parseProperty : (property) ->
105 | @bms[property[1].toLowerCase()] = property[2]
106 |
107 | _createBar : ->
108 | timing: 0.0
109 | wav :
110 | message: []
111 | timing: []
112 | id : []
113 | bmp :
114 | message: []
115 | timing : []
116 | id : []
117 | bpm :
118 | message: []
119 | timing : []
120 | val : []
121 | stop :
122 | message: []
123 | timing : []
124 | id : []
125 | meter: 1.0
126 | note :
127 | key : ({ message: [], timing : [], id : [] } for i in [0..8])
128 |
129 | _parseChannelMsg : (msg) ->
130 | measureNum = parseInt msg[1]
131 | ch = parseInt msg[2]
132 | data = msg[3]
133 |
134 | unless @bms.data[measureNum]?
135 | @bms.data[measureNum] = @_createBar()
136 |
137 | switch ch
138 | when 1 # WAV
139 | @_storeWAV data, @bms.data[measureNum].wav, measureNum
140 | when 2 # Meter
141 | meter = parseFloat(data)
142 | if meter > 0
143 | @bms.data[measureNum].meter = meter
144 | when 3 # BPM
145 | @_storeBPM data, @bms.data[measureNum].bpm
146 | when 4 # BMP
147 | @_storeData data, @bms.data[measureNum].bmp
148 | when 8 # EXBPM
149 | @_storeEXBPM data, @bms.data[measureNum].bpm
150 | when 9 # STOP
151 | @_storeSTOP data, @bms.data[measureNum].stop
152 | when 11, 12, 13, 14, 15
153 | @_storeData data, @bms.data[measureNum].note.key[ch - 11]
154 | when 16, 17
155 | @_storeData data, @bms.data[measureNum].note.key[ch - 9]
156 | when 18, 19
157 | @_storeData data, @bms.data[measureNum].note.key[ch - 13]
158 | else
159 |
160 | _storeWAV : (msg, array, measureNum) ->
161 | @wavMessages[measureNum] ?= []
162 | @wavMessages[measureNum].push (parseInt(msg[i..i+1],36) for i in [0..msg.length-1] by 2)
163 |
164 | _storeData : (msg, array) ->
165 | data = (parseInt(msg[i..i+1],36) for i in [0..msg.length-1] by 2)
166 | array.message = _merge(array.message, data)
167 |
168 | _storeSTOP : (msg, array) ->
169 | data = (parseInt(msg[i..i+1],16) for i in [0..msg.length-1] by 2)
170 | array.message = _merge(array.message, data)
171 |
172 | _storeBPM : (msg, bpm) ->
173 | bpm.message = (parseInt(msg[i..i+1],16) for i in [0..msg.length-1] by 2)
174 |
175 | _storeEXBPM : (msg, bpm) ->
176 | bpm.message = for i in [0..msg.length-1] by 2
177 | if @bms.exbpm[parseInt(msg[i..i+1],16)]?
178 | parseFloat @bms.exbpm[parseInt(msg[i..i+1],16)]
179 | else 0
180 | console.log bpm.message
181 |
182 |
183 | _lcm = (a,b) ->
184 | gcm = (x,y) ->
185 | if y==0 then x else gcm(y, x % y)
186 | return a / gcm(a,b) * b
187 |
188 | # ex. expand([1,2,3],6) == [1,0,2,0,3,0]
189 | _expand = (array, length) ->
190 | return (0 for i in [0..length-1]) if array.length is 0
191 | interval = length / array.length
192 | return ((if i % interval == 0 then array[i / interval] else 0) \
193 | for i in [0..length-1])
194 |
195 | # ex. merge([1,2,3], [0,4,0]) == [1,4,3]
196 | _merge = (ary1, ary2) ->
197 | return ary2 if ary1.length is 0
198 | lcm = _lcm(ary1.length, ary2.length)
199 | ret = _expand(ary1, lcm)
200 | for value, i in _expand(ary2, lcm)
201 | continue if value == 0
202 | ret[i] = value
203 | return ret
204 |
205 | # 全体をパースした後でtiming等を修正
206 | _modifyAfterParse : () ->
207 | bpm = @bms.bpm
208 | time = 0
209 | for bar, i in @bms.data
210 | if not bar?
211 | @bms.data[i] = @_createBar()
212 | @bms.data[i].timing = time
213 | time += (240000 / bpm)
214 | continue
215 |
216 | bar.timing = time
217 | if bar.bpm.message.length == 0
218 | bar.bpm.message = [0]
219 |
220 | @_noteTiming time, bar, bpm
221 | @_bmpTiming time, bar, bpm
222 | @_stopTiming time, bar, bpm
223 | @_wavTiming time, bar, bpm, @wavMessages[i]
224 |
225 | l = bar.bpm.message.length
226 | for val, i in bar.bpm.message
227 | if val != 0
228 | bar.bpm.val.push(val)
229 | bar.bpm.timing.push(time)
230 | bpm = val
231 | time += (240000 / bpm) * (1 / l) * bar.meter
232 |
233 | _calcTiming : (time, objects, bpmobj, bpm, meter) ->
234 | bl = bpmobj.message.length
235 | ol = objects.message.length
236 | lcm = _lcm(bl, ol)
237 | bpms = _expand(bpmobj.message, lcm)
238 | objs = _expand(objects.message, lcm)
239 | t = 0
240 | b = bpm
241 | objects.timing = []
242 | objects.id = []
243 | for val, i in bpms
244 | if objs[i] isnt 0
245 | objects.timing.push(time + t)
246 | objects.id.push(objs[i])
247 | if @bms.endTime < time + t
248 | @bms.endTime = time + t
249 |
250 | b = val if val isnt 0 # change bpm
251 | t += (240000 / b) * (1 / lcm) * meter
252 | return
253 |
254 | _noteTiming : (time, bar, bpm) ->
255 | l = bar.bpm.message.length
256 | for n in bar.note.key when n.message.length isnt 0
257 | @_calcTiming(time, n, bar.bpm, bpm, bar.meter)
258 | return
259 |
260 | _bmpTiming : (time, bar, bpm) ->
261 | @_calcTiming time, bar.bmp, bar.bpm, bpm, bar.meter
262 |
263 | _stopTiming : (time, bar, bpm) ->
264 | @_calcTiming time, bar.stop, bar.bpm, bpm, bar.meter
265 |
266 | _wavTiming : (time, bar, bpm, wavss) ->
267 | return if not wavss?
268 | l = bar.bpm.message.length
269 | result = []
270 | for ws in wavss
271 | wl = ws.length
272 | lcm = _lcm(l, wl)
273 | bpms = _expand(bar.bpm.message, lcm)
274 | wavs = _expand(ws, lcm)
275 | t = 0
276 | b = bpm
277 | for val, i in bpms
278 | if wavs[i] isnt 0
279 | result.push { timing: time + t, id: wavs[i]}
280 | if @bms.endTime < time + t
281 | @bms.endTime = time + t
282 | if val isnt 0 # change bpm
283 | b = val
284 | t += (240000 / b) * (1 / lcm) * bar.meter
285 |
286 | for w in result.sort( (a,b) -> a['timing'] - b['timing'])
287 | bar.wav.timing.push w.timing
288 | bar.wav.id.push w.id
289 |
290 | # OPTIMIZE: bpm,bmp,wavは小節に依存しないよう配列に詰めなおす
291 | _serialize : (arr, name, bms_data) ->
292 | for v, i in bms_data
293 | for t, j in v[name].timing when t?
294 | if v[name].val?
295 | arr.push
296 | timing : t
297 | val : v[name].val[j]
298 | else if v[name].id?
299 | arr.push
300 | timing : t
301 | id : v[name].id[j]
302 |
303 | _calcTotalNote : ->
304 | @bms.data.reduce ( (t, d) -> t +
305 | d.note.key.reduce ((nt, k) -> nt + k.id.length), 0), 0
306 |
307 | module.exports = Parser
308 |
--------------------------------------------------------------------------------
/src/app.coffee:
--------------------------------------------------------------------------------
1 | KeyboardService = require './keyboardService'
2 | NotesLayer = require './notesLayer'
3 | RateLayer = require './rateLayer'
4 | StatsLayer = require './statsLayer'
5 | BpmLayer = require './bpmLayer'
6 | PlaytimeLayer = require './playtimeLayer'
7 | AnimeLayer = require './animationLayer'
8 | Timer = require './timer'
9 | Audio = require './audio'
10 | GameoverScene = require './gameoverScene'
11 | res = require './resource'
12 | .resObjs
13 |
14 | # TODO : move
15 | skin =
16 | body :
17 | bgImage :
18 | src : res.bgImage
19 | turntable :
20 | src : res.turntableImage
21 | x : -274
22 | y : 348
23 | z : 10
24 | notes :
25 | fallDist : 320
26 | keyNum : 8
27 | offsetX : -266
28 | marginX : 1.95
29 | z : 4
30 | nodeImage :
31 | src : res.nodeImage
32 | width : 194
33 | height : 1
34 | x : -190
35 | noteTurntableImage :
36 | src : res.noteTurntableImage
37 | width : 41
38 | height : 6
39 | noteWhiteImage :
40 | src : res.noteWhiteImage
41 | width : 22
42 | height : 6
43 | noteBlackImage :
44 | src : res.noteBlackImage
45 | width : 17
46 | height : 6
47 | bgImage :
48 | src : res.noteBgImage
49 | x : -190
50 | y : 320
51 | greatEffect :
52 | src : res.greatEffectImage
53 | width : 80
54 | height : 80
55 | row : 6
56 | colum : 3
57 | delay : 0.02
58 | z : 5
59 | keyEffect :
60 | y : 162
61 | turntableKeydownImage :
62 | src : res.turntableKeydownImage
63 | whiteKeydownImage :
64 | src : res.whiteKeydownImage
65 | blackKeydownImage :
66 | src : res.blackKeydownImage
67 | rate :
68 | z : 10
69 | meter :
70 | src : res.meterImage
71 | width : 4
72 | height : 12
73 | x : -292
74 | y : 386
75 | z : 10
76 | label :
77 | src : res.numeralImage
78 | width : 26.2
79 | height : 16
80 | scale : 0.5
81 | margin : 0
82 | x : -68
83 | y : 384
84 | stats :
85 | z : 10
86 | judge :
87 | src : './res/judge-image.png'
88 | width : 153
89 | height : 38.8
90 | x : -188
91 | y : 260
92 | score :
93 | src : res.numeralImage
94 | width : 26.2
95 | height : 16
96 | scale : 0.8
97 | margin : 0
98 | x : -122
99 | y : 429
100 | pgreatNum :
101 | src : res.numeralImage
102 | width : 26.2
103 | height : 16
104 | scale : 0.5
105 | margin : 0
106 | x : 18
107 | y : 415
108 | greatNum :
109 | src : res.numeralImage
110 | width : 26.2
111 | height : 16
112 | scale : 0.5
113 | margin : 0
114 | x : 18
115 | y : 428
116 | goodNum :
117 | src : res.numeralImage
118 | width : 26.2
119 | height : 16
120 | scale : 0.5
121 | margin : 0
122 | x : 18
123 | y : 439
124 | badNum :
125 | src : res.numeralImage
126 | width : 26.2
127 | height : 16
128 | scale : 0.5
129 | margin : 0
130 | x : 18
131 | y : 451
132 | poorNum :
133 | src : res.numeralImage
134 | width : 26.2
135 | height : 16
136 | scale : 0.5
137 | margin : 0
138 | x : 18
139 | y : 462
140 | comboNum :
141 | src : res.numeralImage
142 | width : 26.2
143 | height : 16
144 | scale : 0.8
145 | margin : 0
146 | x : -102
147 | y : 451
148 | bpm :
149 | src : res.numeralImage
150 | width : 26.2
151 | height : 16
152 | scale : 0.6
153 | margin : 0
154 | x : 78
155 | y : 450
156 | z : 10
157 | playtime :
158 | src : res.numeralImage
159 | width : 26.2
160 | height : 16
161 | scale : 0.6
162 | margin : 0
163 | z : 10
164 | minuite :
165 | x : 39
166 | y : 393
167 | second :
168 | x : 73
169 | y : 393
170 | bmp :
171 | x : 106
172 | y : 186
173 |
174 | AppLayer = cc.Layer.extend
175 | ctor : (@_bms, prefix)->
176 | @_super()
177 | @_timer = new Timer()
178 |
179 | # TODO :
180 | @_stopIndex = 0
181 |
182 | @_addBackground()
183 | @_audio = new Audio @_timer, @_bms.bgms
184 | @_audio.init @_bms.wav, prefix
185 | @addChild @_audio
186 |
187 | @_keyboard = new KeyboardService @_timer
188 |
189 | # FIXME : move to argument
190 | keyConfig = [
191 | 'Z'.charCodeAt(0)
192 | 'S'.charCodeAt(0)
193 | 'X'.charCodeAt(0)
194 | 'D'.charCodeAt(0)
195 | 'C'.charCodeAt(0)
196 | 'F'.charCodeAt(0)
197 | 'V'.charCodeAt(0)
198 | 16
199 | ]
200 |
201 | @_keyboard.init()
202 | @_keyboard.addListener v, @_onKeydown.bind this, id for v, id in keyConfig
203 | @_keyboard.addListener 27, @_onEscKeydown.bind this
204 | @addChild @_keyboard
205 |
206 | # FIXME : move to argument
207 | config =
208 | reactionTime : 200
209 | removeTime : 200
210 | judge :
211 | pgreat : 20
212 | great : 40
213 | good : 105
214 | bad : 150
215 | poor : 200
216 |
217 | @_notesLayer = new NotesLayer skin.notes, @_timer, config
218 | @_notesLayer.init @_bms
219 | @_notesLayer.addListener 'hit', @_onHit.bind this
220 | @_notesLayer.addListener 'judge', @_onJudge.bind this
221 | #@_notesLayer.addListener 'end', @_onEnd.bind this
222 | @addChild @_notesLayer, skin.notes.z
223 |
224 | @_rate = new RateLayer skin.rate
225 | @_rate.init
226 | # FIXME : move to argument
227 | ###
228 | http://2nd.geocities.jp/yoshi_65c816/bms/LR2.html
229 | t=#TOTAL n=total notes
230 | ゲージの種類 PGERAT GREAT GOOD POOR BAD 空POOR
231 | GROOVE t/n t/n (t/n)/2 -6 -4 -2
232 | EASY t/n*1.2 t/n*1.2 (t/n*1.2)/2 -4.8 -3.2 -1.6
233 | HARD 0.1※2 0.1※2 0.05※2 -10※ -6※ -2※
234 | 段位 0.1 0.1 0.05? -3 -2 -2
235 | 本家GROOVE a a a/2 -6 -2 -2
236 | 本家EASY a a a/2 -4.8 -1.6 -1.6
237 | 本家HARD 0.16 0.16 0 -9 -5 5
238 | 本家段位 0.16 0.16 0.04 -2.5 -1.5 -1.5
239 | ###
240 | initRate : 20
241 | great : @_bms.total / @_bms.totalNote * 1.2
242 | good : @_bms.total / @_bms.totalNote * 0.6
243 | bad : -3.2
244 | poor : -4.8
245 | epoor : -1.6
246 | num : 50
247 | clearVal : 40
248 | @addChild @_rate, skin.rate.z
249 |
250 | @_stats = new StatsLayer skin.stats
251 | @_stats.init @_bms.totalNote,
252 | pgreat : 150000
253 | great : 100000
254 | good : 20000
255 | combo : 50000
256 |
257 | @addChild @_stats, skin.stats.z
258 |
259 | @_bpm = new BpmLayer skin.bpm, @_timer, @_bms.bpms
260 | @_bpm.init()
261 | @addChild @_bpm, skin.bpm.z
262 | @_playtime = new PlaytimeLayer skin.playtime, @_timer
263 | @_playtime.init()
264 | @addChild @_playtime, skin.playtime.z
265 |
266 | @_animeLayer = new AnimeLayer skin.bmp, @_timer
267 | console.dir @_bms.bmp
268 | console.dir @_bms.animations
269 | @_animeLayer.init @_bms.bmp, @_bms.animations, prefix
270 | @addChild @_animeLayer
271 | # FIXME
272 | if @_bms.animations.length is 0 or @_bms.bmp[1]?.match(/mpg$/)?
273 | soundonly = new cc.LabelTTF "Sound Only", "sapceage" , 32
274 | soundonly.x = cc.screenSize.width / 2 + 100
275 | soundonly.y = cc.screenSize.height - 200
276 | soundonly.setOpacity 200
277 | @addChild soundonly, 100
278 |
279 | start : ->
280 | @_notesLayer.start off
281 | @_audio.startBgm()
282 | @_rate.start()
283 | @_bpm.start()
284 | @_playtime.start()
285 | @_animeLayer.start()
286 | @_stats.start()
287 | @_timer.start()
288 | @scheduleUpdate()
289 |
290 | update : ->
291 | time = @_timer.get()
292 |
293 | # TODO : to class
294 | if @_bms.stopTiming[@_stopIndex]?
295 | if time >= @_bms.stopTiming[@_stopIndex].timing
296 | #console.log "stop id=#{@_bms.stopTiming[@_stopIndex].id}, val =#{@_bms.stop[@_bms.stopTiming[@_stopIndex].id]}"
297 | measureTime = 240000 / @_bpm.get()
298 | stopTime = @_bms.stop[@_bms.stopTiming[@_stopIndex].id] / 192 * measureTime
299 | console.log "stop time = #{stopTime}, bpm = #{@_bpm.get()}"
300 | @_timer.pause()
301 | @scheduleOnce ->
302 | @_timer.start()
303 | , stopTime / 1000
304 | @_stopIndex++
305 |
306 | @_exitGame() if time > @_bms.endTime + 5000
307 |
308 | onExit : ->
309 | @_super()
310 | @removeAllChildren on
311 |
312 | _exitGame : ->
313 | @unscheduleUpdate()
314 | @_timer.stop()
315 | cc.director.runScene new cc.TransitionFade(1.2, new GameoverScene(@_stats.get()))
316 |
317 | _onKeydown : (id, key, time) ->
318 | @_notesLayer.onTouch id, time
319 |
320 | _onEscKeydown : (id, key, time) ->
321 | # FIXME :先頭でrequireするとerror
322 | MenuScene = require './menuScene'
323 | @unscheduleUpdate()
324 | @_timer.stop()
325 | cc.director.runScene new cc.TransitionFade(1.2, new MenuScene())
326 |
327 | _onHit : (event, wavId) ->
328 | @_audio.play wavId
329 |
330 | _onEnd : (event) ->
331 | @scheduleOnce @_changeSceneToGameOver, 5
332 |
333 | _onJudge : (event, judge) ->
334 | @_rate.reflect judge
335 | @_stats.reflect judge
336 |
337 | @_animeLayer.onPoor() if judge is 'poor' or judge is 'epoor'
338 |
339 | _addBackground : ->
340 | bg = new cc.Sprite res.bgImage
341 | bg.x = cc.director.getWinSize().width / 2
342 | bg.y = cc.director.getWinSize().height / 2
343 | bg.scale = window.parent.screen.height / bg.height
344 | @addChild bg, 0
345 |
346 | # test image
347 | bg = new cc.Sprite "res/test.png"
348 | bg.x = cc.director.getWinSize().width / 2
349 | bg.y = cc.director.getWinSize().height - 240
350 | @addChild bg, 1
351 |
352 | turntable = new cc.Sprite res.turntableImage
353 | turntable.x = cc.screenSize.width / 2 + skin.body.turntable.x
354 | turntable.y = cc.screenSize.height - skin.body.turntable.y
355 | turntable.setOpacity 200
356 | @addChild turntable, skin.body.turntable.z
357 | turntable.runAction new cc.RepeatForever new cc.RotateBy(5, 360)
358 |
359 | #window.onblur = ->
360 | # window.stop();
361 |
362 |
363 | AppScene = cc.Scene.extend
364 |
365 | ctor : (bms, prefix)->
366 | @_super()
367 | layer = new AppLayer bms, prefix
368 | @addChild layer
369 | layer.start()
370 |
371 | onExit : -> @removeAllChildren on
372 |
373 | module.exports = AppScene
374 |
--------------------------------------------------------------------------------
/bms.cson:
--------------------------------------------------------------------------------
1 | # jsbで読む場合ファイルはutf-8の*.txtである必要がある
2 | # txtはresディレクトリの下に配置する必要あり
3 | [
4 | {url : "bms/SHK_new04_Reality/Reality_5_Easy.bms" , title : "Reality [5key Easy]" , artist : '' , level : 2}
5 | {url : "bms/SHK_new04_Reality/Reality_5_Hard2.bms" , title : "Reality [5key Hard2]" , artist : '' , level : 7}
6 | {url : "bms/SHK_new04_Reality/Reality_5_Normal.bms" , title : "Reality [5key Normal]" , artist : '' , level : 4}
7 | {url : "bms/SHK_new04_Reality/Reality_5_SuperHard.bms" , title : "Reality [5key Super Hard]" , artist : '' , level : 11}
8 | {url : "bms/SHK_new04_Reality/Reality_5_veryHard.bms" , title : "Reality [5Key very Hard]" , artist : '' , level : 7}
9 |
10 | {url : "bms/SHK_new04_Reality/Reality_7_Easy1.bms" , title : "Reality [7keys Easy1]" , artist : '' , level : 3}
11 | {url : "bms/SHK_new04_Reality/Reality_7_Easy2.bms" , title : "Reality [7keys Easy2]" , artist : '' , level : 2}
12 | {url : "bms/SHK_new04_Reality/Reality_7_Hard.bms" , title : "Reality [7keys Hard]" , artist : '' , level : 8}
13 | {url : "bms/SHK_new04_Reality/Reality_7_Normal.bms" , title : "Reality [7keys Normal]" , artist : '' , level : 3}
14 | {url : "bms/SHK_new04_Reality/Reality_7_SuperHard.bms" , title : "Reality [7keys Super Hard]" , artist : '' , level : 11}
15 |
16 |
17 | {url : "bms/ninth/386.bms" , title : "ninth" , artist : ' sta' , level : 6}
18 | {url : "bms/ninth/6502.bme" , title : "ninth" , artist : ' sta' , level : 7}
19 | {url : "bms/sq_07-01/sq_07-01.bms" , title : "千年女王[Normal]" , artist : ' しらいし' , level : 11}
20 | {url : "bms/sq_07-01/sq_07-02.bms" , title : "千年女王[Hyper]" , artist : ' しらいし' , level : 12}
21 | # if sequence {url : "bms/Declinin/declinin.bms" , title : "Declinin'" , artist : ' ' , level : 4}
22 | {url : "bms/Odin/_Odin_07-1.bms" , title : "Odin[Normal]" , artist : ' しらいし' , level : 6}
23 | {url : "bms/Odin/_Odin_07-2.bms" , title : "Odin[Hyper]" , artist : ' しらいし' , level : 9}
24 | {url : "bms/Odin/_Odin_07-3.bms" , title : "Odin[Another]" , artist : ' しらいし' , level : 11}
25 | {url : "bms/Odin/_Odin_07-4.bms" , title : "Odin[Black Another]" , artist : ' しらいし' , level : 12}
26 |
27 | {url : "bms/sweez/niraikanai7_n_short_bmssp7b.bme" , title : "ニライカナイ(short ver.) [7keys Beginner]", artist : ' sweez & Meine Meinung / BMSSP' , level : 2}
28 | {url : "bms/sweez/niraikanai7_n.bme" , title : "ニライカナイ" , artist : ' sweez & Meine Meinung' , level : 8}
29 | {url : "bms/under_the_moonlight/under_the_moonlight_7n.bme" , title : "under the moonlight [7keys Normal]" , artist : ' Yamajet' , level : 4}
30 | {url : "bms/under_the_moonlight/under_the_moonlight_7h.bme" , title : "under the moonlight [7keys Hyper]" , artist : ' Yamajet' , level : 8}
31 | {url : "bms/under_the_moonlight/under_the_moonlight_7a.bme" , title : "under the moonlight [7keys Another]" , artist : ' Yamajet' , level : 8}
32 | {url : "bms/SAMBISTA/sambista.bms" , title : "SAMBISTA" , artist : ' DOT96' , level : 6}
33 | {url : "bms/SAMBISTA/sambista_bmssp5e.bms" , title : "SAMBISTA[Easy]" , artist : ' DOT96' , level : 2}
34 | {url : "bms/RadioOrganico/01_radio_organico[light7].bme" , title : "Radio Organico[LIGHT7]" , artist : ' Team:SASAKURATION' , level : 2}
35 | {url : "bms/RadioOrganico/02_radio_organico[7keys].bme" , title : "Radio Organico[7KEYS]" , artist : ' Team:SASAKURATION' , level : 4}
36 | {url : "bms/RadioOrganico/03_radio_organico[Another].bme" , title : "Radio Organico[ANOTHER]" , artist : ' Team:SASAKURATION' , level : 6}
37 | {url : "bms/Quark/quark01.bme" , title : "Quark" , artist : ' Hate vs Brilliance' , level : 6}
38 | {url : "bms/Quark/quark02.bme" , title : "Quark [Hyper]" , artist : ' Hate vs Brilliance' , level : 10}
39 | {url : "bms/Quark/quark03.bme" , title : "Quark [Another]" , artist : ' Hate vs Brilliance' , level : 12}
40 | {url : "bms/oceanbird/oceanbird_7_normal.bms" , title : "oceanbird" , artist : ' sXacla / TOHRU MiTSUHASHi' , level : 3}
41 | {url : "bms/oceanbird/oceanbird_7_hyper.bms" , title : "oceanbird [Hyper]" , artist : ' sXacla / TOHRU MiTSUHASHi' , level : 6}
42 | {url : "bms/oceanbird/oceanbird_7_another.bms" , title : "oceanbird [Another]" , artist : ' sXacla / TOHRU MiTSUHASHi' , level : 9}
43 | {url : "bms/moonscape/ms_bmssp7n.bme" , title : "Moonscape [7keys Normal]" , artist : ' syatten / BMSSP' , level : 3}
44 | {url : "bms/moonscape/ms_sph.bme" , title : "Moonscape (SP HYPER)" , artist : ' syatten / BMSSP' , level : 8}
45 | {url : "bms/moonscape/ms_spa.bme" , title : "Moonscape (SP ANOTHER)" , artist : ' syatten / BMSSP' , level : 10}
46 | {url : "bms/Lightstep/lightstep_5e.bms" , title : "Lightstep [5keys Easy]" , artist : ' Kaede a.k.a. fen / BMSSP' , level : 4}
47 | {url : "bms/Lightstep/lightstep_5.bms" , title : "Lightstep" , artist : ' Kaede a.k.a. fen / BMSSP' , level : 6}
48 | {url : "bms/mommy/I'll_forget_you_you'll_never_forget_me_7N.bme", title : "I'll forget you, you'll never forget me.[7key,Normal]" , artist : ' mommy' , level : 6}
49 | {url : "bms/mommy/I'll_forget_you_you'll_never_forget_me_7H.bme", title : "I'll forget you, you'll never forget me.[7key,Hyper]" , artist : ' mommy' , level : 8}
50 | {url : "bms/mommy/I'll_forget_you_you'll_never_forget_me_7A.bme", title : "I'll forget you, you'll never forget me.[7key,Another]" , artist : ' mommy' , level : 11}
51 | {url : "bms/HEisanEnergizer/heiseng7l.bme" , title : 'HE is an Energizer(7keys EASY)' , artist : ' Mr.ABC' , level : 5}
52 | {url : "bms/HEisanEnergizer/heiseng7.bme" , title : 'HE is an Energizer(7keys)' , artist : ' Mr.ABC' , level : 7}
53 | {url : "bms/gy_greens/grsl_7.bme" , title : 'Greensleeves[7key]' , artist : ' BMS:G-Y / MIDI:Haven' , level : 1}
54 | {url : "bms/gy_greens/grsl_7h.bme" , title : 'Greensleeves[7key Hyper]' , artist : ' BMS:G-Y / MIDI:Haven' , level : 5}
55 | {url : "bms/gy_greens/grsl_7a.bme" , title : 'Greensleeves[7key Another]' , artist : ' BMS:G-Y / MIDI:Haven' , level : 8}
56 | {url : "bms/gi_MTM/MTM_7e.bme" , title : 'Maple Town Memories[7key-Easy]' , artist : ' BMS/GYAON 作曲/井上' , level : 4}
57 | {url : "bms/gi_MTM/MTM_7n.bme" , title : 'Maple Town Memories[7key] ' , artist : ' BMS/GYAON 作曲/井上' , level : 6}
58 | {url : "bms/gi_MTM/MTM_7a.bme" , title : 'Maple Town Memories[7key-Another]' , artist : ' BMS/GYAON 作曲/井上' , level : 6}
59 | {url : "bms/evangelize_radio edit/evangelize_spn.bme" , title : 'Evangelize (Radio Edit) (SP NORMAL)' , artist : ' syatten + 140' , level : 5}
60 | {url : "bms/evangelize_radio edit/evangelize_sph.bme" , title : 'Evangelize (Radio Edit) (SP HYPER)' , artist : ' syatten + 140' , level : 7}
61 | {url : "bms/evangelize_radio edit/evangelize_spb.bme" , title : 'Evangelize (Radio Edit) (SP BEGINNER)' , artist : ' syatten + 140' , level : 1}
62 | {url : "bms/evangelize_radio edit/evangelize_spa.bme" , title : 'Evangelize (Radio Edit) (SP ANOTHER)' , artist : ' syatten + 140' , level : 11}
63 | {url : "bms/evangelize/_blurryimages.bms" , title : 'evangelize (blurry images)' , artist : ' stereoberry (original:syatten BGA:ƒÎ=72)' , level : 5}
64 | {url : "bms/AVALON/01_avalon[light7].bme" , title : 'AVALON [light]' , artist : ' Team:SASAKURATION' , level : 5}
65 | {url : "bms/AVALON/02_avalon[7key].bme" , title : 'AVALON [Normal]' , artist : ' Team:SASAKURATION' , level : 10}
66 | {url : "bms/AVALON/03_avalon[Another].bme" , title : 'AVALON [Another]' , artist : ' Team:SASAKURATION' , level : 12}
67 | {url : "bms/AVALON/04_avalon_[IIDX].bme" , title : 'AVALON [IIDX]' , artist : ' Team:SASAKURATION' , level : 0}
68 | {url : "bms/bellydance/a_bga_bmssp_e.bms" , title : 'belly dance (Consistently_Drinkin_remix)' , artist : ' Kotira Sample' , level : 2}
69 | {url : "bms/bellydance/a_bga.bms" , title : 'belly dance (Consistently_Drinkin_remix)' , artist : ' Kotira Sample' , level : 4}
70 | {url : "bms/atonement/ayy2.bms" , title : 'atonement you you' , artist : ' ' , level : 6}
71 | {url : "bms/AbsurdGaff/_abs07_00_bmssp7e.bme" , title : 'Absurd Gaff [7keys Easy]' , artist : ' siromaru / BMSSP' , level : 3}
72 | {url : "bms/AbsurdGaff/_ms_abs07_01.bme" , title : 'Absurd Gaff [Normal]' , artist : ' siromaru / Mentalstock' , level : 8}
73 | {url : "bms/AbsurdGaff/_ms_abs07_02.bme" , title : 'Absurd Gaff [Hyper]' , artist : ' siromaru / Mentalstock' , level : 10}
74 | {url : "bms/AbsurdGaff/_ms_abs07_03.bme" , title : 'Absurd Gaff [Another]' , artist : ' siromaru / Mentalstock' , level : 21}
75 | {url : "bms/Lapis - SHIKI/lapis7key.bme" , title : 'Lapis' , artist : ' SHIKI' , level : 8}
76 | {url : "bms/Lapis - SHIKI/lapis7keya.bme" , title : 'Lapis [Another]' , artist : ' SHIKI' , level : 10}
77 | {url : "bms/Lapis - SHIKI/lapis7keyb.bme" , title : 'Lapis [beginner]' , artist : ' SHIKI' , level : 2}
78 | {url : "bms/Lapis - SHIKI/lapis7keyl.bme" , title : 'Lapis [Light]' , artist : ' SHIKI' , level : 5}
79 | ]
80 |
--------------------------------------------------------------------------------
/res/va.txt:
--------------------------------------------------------------------------------
1 | *---------------------- HEADER FIELD
2 | #PLAYER 1
3 | #GENRE retrogressive
4 | #TITLE V(SOFT LANDING PARADISE)
5 | #ARTIST オサムイモン (SUGI & OSAM) feat. VAKA
6 | #BPM 450
7 | #PLAYLEVEL 0
8 | #RANK 3
9 | #TOTAL 1000
10 | #STAGEFILE
11 | %EMAIL
12 | %URL
13 |
14 | #WAV12 17.wav
15 | #WAV14 19.wav
16 | #WAV15 20.wav
17 | #WAV16 21.wav
18 | #WAV17 22.wav
19 | #WAV18 23.wav
20 | #WAV19 24.wav
21 | #WAV1A 25.wav
22 | #WAV1B 26.wav
23 | #WAV1C 27.wav
24 | #WAV1D 28.wav
25 | #WAV1E 29.wav
26 | #WAV20 31.wav
27 | #WAV21 32.wav
28 | #WAV22 33.wav
29 | #WAV23 34.wav
30 | #WAV25 36.wav
31 | #WAV26 37.wav
32 | #WAV27 38.wav
33 | #WAV28 39.wav
34 | #WAV29 40.wav
35 | #WAV2A 41.wav
36 | #WAV2C 43.wav
37 | #WAV2D 44.wav
38 | #WAV2E 45.wav
39 | #WAV2F 46.wav
40 | #WAV30 47.wav
41 | #WAV31 48.wav
42 | #WAV32 49.wav
43 | #WAV33 50.wav
44 | #WAV34 51.wav
45 | #WAV36 53.wav
46 | #WAV37 54.wav
47 | #WAV38 55.wav
48 |
49 | *---------------------- MAIN DATA FIELD
50 |
51 |
52 | #00202:1.05
53 |
54 | #00302:1.1
55 | #00312:1414141414141414
56 |
57 | #00402:1.2
58 | #00412:1414141414141414
59 | #00415:1A1A1A1A1A1A1A1A
60 |
61 | #00502:1.3
62 | #00512:1414141414141414
63 | #00515:1A1A1A1A1A1A1A1A
64 | #00519:2323232323232323
65 |
66 | #00602:1.4
67 | #00612:1414141414141414
68 | #00615:1A1A1A1A1A1A1A1A
69 | #00619:2323232323232323
70 |
71 | #00702:1.5
72 | #00711:0000000012121212
73 | #00713:1515151500000000
74 | #00714:1919191919191919
75 | #00718:2121212121212121
76 |
77 | #00802:1.6
78 | #00811:1212121212121212
79 | #00813:1717171717171717
80 | #00815:1A1A1A1A1A1A1A1A
81 |
82 | #00902:1.7
83 | #00912:1616161616161616
84 | #00914:1919191919191919
85 | #00918:1C1C1C1C1C1C1C1C
86 |
87 | #01002:1.8
88 | #01011:0014141414140000
89 | #01013:1818181818181818
90 | #01015:1B1B1B1B1B1B1B1B
91 |
92 | #01102:1.9
93 | #01112:1616161616161616
94 | #01114:1919191919191919
95 | #01118:1C1C1C1C1C1C1C1C
96 |
97 | #01202:2
98 | #01203:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000181A1C1E202224272A2D3033
99 | #01211:1414141414141414
100 | #01213:0000000018181818
101 | #01214:1919191900000000
102 | #01215:1B1B1B1B1B1B1B1B
103 |
104 | #01303:36393C3F42454800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004900000000000000000000004A00000000000000000000004B00000000000000000000004C00000000000000000000004D00000000000000000000004E00000000000000000000004F0000000000000000000000500000000000000000000000510000000000000000000000
105 | #01311:2500000000000025250000000000002525000000000000002500000000000000
106 | #01312:0000000000000000000000000000000000000000000000260000000000000026
107 | #01313:1900000000282800000000000028280000000000000028000000000000002800
108 | #01314:0000000000000000000000000000000000000000002A000000000000002A0000
109 | #01315:0000002C2C0000000000002C2C000000000000002C000000000000002C000000
110 | #01318:000000000000000000000000000000000000002D000000000000002D00000000
111 | #01319:0031310000000000003131000000000000002F000000000000002F0000000000
112 | #01316:0000000000000000000000000000000000310000000000000031000000000000
113 |
114 | #01403:520000000000000000000000000000000000005300000000000000000000000000000000000054000000000000000000000000000000000000005500000000000000000000000000000000000056000000000000000000000000000000000000570000000000000000000000000000000000005800000000000000000000000000000000000059000000000000000000000000000000000000005A0000000000000000000000000000000000005B000000000000000000000000000000000000
115 | #01411:0000000000000000000000000000000019190019191900191919000019000000
116 | #01412:00000000000000001A1A1A1A1A000000
117 | #01413:0020000000200000002000000020000000000000000000000000000000000000
118 | #01414:000000001C1C1C1C
119 | #01415:25252525252525252000200020002000
120 | #01418:0000002800000028000000280000002800000000000000000000000000000000
121 |
122 | #01503:5C0000000000000000000000000000000000005D0000000000000000000000000000000000005E000000000000000000000000000000000000005F00000000000000000000000000000000000060000000000000000000000000000000000000610000000000000000000000000000000000006200000000000000000000000000000000000063000000000000000000000000000000000000006400000000000000000000000000000000000065000000000000000000000000000000000000
123 | #01511:1900000019000000190000001900000019000000000000282800000000000028
124 | #01513:0000000000000000000000000000000000000000002C2C0000000000002C2C00
125 | #01514:1C1C1C1C1C000000
126 | #01515:2000000020000000200000002000000020000031310000000000003131000000
127 | #01518:0028
128 | #01519:0000000000000000000000000000000000343400000000000034340000000000
129 |
130 | #01603:66000000000000000000000000000000000000670000000000000000000000000000000000006800000000000000000000000000000000000000690000000000000000000000000000000000006A0000000000000000000000000000000000006B0000000000000000000000000000000000006C0000000000000000000000000000000000006D000000000000000000000000000000000000006E0000000000000000000000000000000000006F000000000000000000000000000000000000
131 | #01611:28280000
132 | #01612:000000000000002A000000000000002A00000000000000000000000000000000
133 | #01613:0000000000002C000000000000002C0000250000002500000025000000250000
134 | #01614:00000000002E000000000000002E000028002800280028002800280028002800
135 | #01615:0030003000000000
136 | #01618:0000003100000000000000310000000000000000000000000000000000000000
137 | #01619:000033000000000000003300000000000000002C0000002C0000002C0000002C
138 | #01616:0034000000000000003400000000000000000000000000000000000000000000
139 |
140 | #01703:700000000000000000000000000000000000007100000000000000000000000000000000000072000000000000000000000000000000000000007300000000000000000000000000000000000074000000000000000000000000000000000000750000000000000000000000000000000000007600000000000000000000000000000000000077000000000000000000000000000000000000007800000000000000000000000000000000000079000000000000000000000000000000000000
141 | #01711:1919191919191919
142 | #01713:1C1C001C1C1C001C1C1C00001C0000001C0000001C0000001C0000001C000000
143 | #01714:1E1E1E1E1E0000000000000000000000
144 | #01718:2020202020202020
145 |
146 | #01803:7A0000000000000000000000000000000000007B0000000000000000000000000000000000007C000000000000000000000000000000000000007D0000000000000000000000000000000000007E0000000000000000000000000000000000007F0000000000000000000000000000000000008000000000000000000000000000000000000081000000000000000000000000000000000000008200000000000000000000000000000000000083000000000000000000000000000000000000
147 | #01811:190000000000002C2C0000000000002C2C000000000000002C00000000000000
148 | #01812:2C000000000000000000000000000000000000000000002E000000000000002E
149 | #01813:0000000000313100000000000031310000000000000030000000000000003000
150 | #01814:0000000000000000000000000000000000000000003100000000000000310000
151 | #01815:0000003434000000000000343400000000000000330000000000000033000000
152 | #01818:2000000000000000000000000000000000000034000000000000003400000000
153 | #01819:0038380000000000003838000000000000003600000000000000360000000000
154 | #01816:0000000000000000000000000000000000380000000000000038000000000000
155 |
156 | #01903:840000000000000000000000000000000000008500000000000000000000000000000000000086000000000000000000000000000000000000008700000000000000000000000000000000000088000000000000000000000000000000000000890000000000000000000000000000000000008A0000000000000000000000000000000000008B000000000000000000000000000000000000008C0000000000000000000000000000000000008D000000000000000000000000000000000000
157 | #01914:0028000000280000002800000028000025250025252500252525000025000000
158 | #01915:2C2C2C2C2C2C2C2C0000000000000000
159 | #01918:00000000000000002727272727000000
160 | #01919:0000003100000031000000310000003100000000000000000000000000000000
161 |
162 | #02003:8E0000000000000000000000000000000000008F00000000000000000000000000000000000090000000000000000000000000000000000000009100000000000000000000000000000000000092000000000000000000000000000000000000930000000000000000000000000000000000009400000000000000000000000000000000000095000000000000000000000000000000000000009600000000000000000000000000000000000097000000000000000000000000000000000000
163 | #02013:0000000023232323
164 | #02014:2525252500000000
165 | #02015:2626262600000000
166 | #02018:0000000029292929
167 |
168 | #02103:98000000000000000000000000000000000000990000000000000000000000000000000000009A000000000000000000000000000000000000009B0000000000000000000000000000000000009C0000000000000000000000000000000000009D0000000000000000000000000000000000009E0000000000000000000000000000000000009F00000000000000000000000000000000000000A0000000000000000000000000000000000000A1000000000000000000000000000000000000
169 | #02111:001E1E1E1E1E1E1E1E1E1E1E1E1E1E1E
170 | #02112:2121212100000000
171 | #02114:0000000023232323
172 | #02119:2A
173 |
174 | #02203:A2000000000000000000000000000000000000A3000000000000000000000000000000000000A400000000000000000000000000000000000000A5000000000000000000000000000000000000A6000000000000000000000000000000000000A7000000000000000000000000000000000000A8000000000000000000000000000000000000A900000000000000000000000000000000000000AA000000000000000000000000000000000000AB000000000000000000000000000000000000
175 | #02211:1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E
176 | #02215:2525252500000000
177 | #02218:0000000026262626
178 | #02219:2A
179 |
180 | #02303:AC000000000000000000000000000000000000AD000000000000000000000000000000000000AE00000000000000000000000000000000000000AF000000000000000000000000000000000000B000000000000000ABA29990877E0075006C0063005A005100480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
181 | #02311:1E1E1E1E1E1E1E1E1D00000000000000
182 | #02313:0020
183 | #02314:0000000000000000000000000000000000002929292929292900290029002900
184 | #02318:2600000026000000260000002600000000002C2C2C2C2C2C2C002C002C002C00
185 |
186 | #02411:00210021002100210000000000000000
187 | #02413:0000250000002500000025000000250026002626262626262600260026002600
188 | #02415:2A0000002A0000002A0000002A0000002A002A2A2A2A2A2A2A002A002A002A00
189 | #02419:2D2D2D2D00000000
190 |
191 | #02512:00230023002300230000000000000000
192 | #02513:0000000000000000000000000000000025002525252525252500250025002500
193 | #02514:00260026002600260000000000000000
194 | #02515:2800000028000000280000002800000028002828282828282800280028002800
195 | #02519:2C2C2C2C00000000
196 |
197 | #02611:00210021002100210000000000000000
198 | #02612:0000000000000000000000000000000023002323232323232300230023002300
199 | #02613:00250025002500250000000000000000
200 | #02614:2600000026000000260000002600000026002626262626262600260026002600
201 | #02618:2A2A2A2A00000000
202 |
203 | #02711:00200020002000201E001E001D001D00
204 | #02712:0000230000002300000023000000230000290000000029000000000000000000
205 | #02713:250000002500000025000000250000002A002A002A00002A002A000000002A00
206 | #02714:000000000000000000000000000000000000002C002C00002C002C002C00002C
207 | #02715:2900000029000000290000002900000000000000000000000000002D002D0000
208 |
209 | #02811:1E1E000000000000
210 | #02812:0000202000000000
211 | #02813:0000000021212121
212 | #02814:002C000000002C00000000000000000000000000002D0000002D0000002D0000
213 | #02815:2D002D002D00002D002D000000002D000000000000002F0000002F0000002F00
214 | #02818:0000002F002F00002F002F002F00002F00000000310000310000003100000031
215 | #02819:0000000000000000000000310031000031000000000000003200000032000000
216 |
217 | #02911:0000000021212121
218 | #02913:212121212A002A00
219 | #02914:00000031000000310000003100000031002C000031000000002C000031000000
220 | #02915:0000320000003200000032000000320000002D000032000000002D0000320000
221 | #02918:003400000034000000340000003400000000002F000034000000002F00003400
222 | #02919:3600000036000000360000003600000000000000000000360000000000000036
223 |
224 | #03012:0000202020202020
225 | #03013:2323000000000000
226 | #03014:00000000002F0000002F0000002F00000000002F0000002F0000002F0000002F
227 | #03015:00000031003100310031003100310031
228 | #03018:3200000032000032000000320000003200320000003200000032000000320000
229 | #03019:0000343434343434
230 |
231 | #03112:2020202000001E1E
232 | #03113:2800280021210000
233 | #03114:002A00002F000000002A00002F00000000000000002D0000002D0000002D0000
234 | #03115:00002C000031000000002C00003100000000000000002F0000002F0000002F00
235 | #03118:0000002D000032000000002D0000320031000000310000310000003100000031
236 | #03119:0000000000000034000000000000003400000000000000003200000032000000
237 |
238 | #03211:0000000000001B1A
239 | #03212:1E0000001E0000001E0000001E0000001D0000001C0000002A00002A0000002A
240 | #03213:000000000000000000000000000000002C00002C0000002C00002C0000002C00
241 | #03214:0000002D0000002D0000002D0000002D00002D0000002D00002D0000002D0000
242 | #03215:00002F0000002F0000002F0000002F00002F0000002F0000000000002F000000
243 | #03218:0031000000310000003100000031000000000000310000000000000000000000
244 | #03219:3232323200000000
245 |
246 | #03311:1919191919191919
247 | #03312:0020000000200000
248 | #03313:00230023000000000023002300000000
249 | #03314:0025002500250025000000000000000000250025002500250000000000000000
250 | #03315:29000000292A002A29000000292A002A
251 | #03318:0000000000000000002C002C002C002C0000000000000000002C002C002C002C
252 | #03319:0000002F0000002F
253 |
254 | #03403:48
255 | #03411:191919191C000000
256 | #03412:0000000000000000000000001D0000001D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D
257 | #03413:000000002300001E0000000000000000
258 | #03414:2900000029000000000025000020002000000000000000000000000000000000
259 | #03415:0000000000002A00002600260000000023232323232323232323232323232323
260 | #03418:00002D00002C002C000000000000000000000000000000000000000000000000
261 | #03419:002F002F00000000000000000000000000000000000000000000000000000000
262 |
263 | #03513:1E
264 | #03514:2100000021000000000000002100000028282828282828282828282828282828
265 | #03515:000023000000230000002300000023002E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E
266 | #03518:0025002500250025002500250025002500000000000000000000000000000000
267 | #03519:002A0000
268 |
269 | #03611:00230000
270 | #03612:00250025002500250000000000000000
271 | #03613:2727002700270027002700270027002700000000000000000000000000000000
272 | #03615:000000002A000000000000002A0000002A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A
273 | #03618:2F00000000000000000000000000000030303030303030303030303030303030
274 |
275 | #03712:0000000000000000000000000000002500000000000000000000000000000000
276 | #03713:0000270000002700000027000000270021212121212121212121212121212121
277 | #03714:2828002800280028002800280028000027272727272727272727272727272727
278 | #03718:002C000000000000
279 | #03719:3100312C00000000
280 |
281 | #03811:00001E0000001E0000001E0000001E001E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E
282 | #03812:2020002000200020002000200020002000000000000000000000000000000000
283 | #03815:2800000028000000280000002800000028282828282828282828282828282828
284 |
285 | #03902:0.5
286 | #03911:1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E
287 | #03914:27272727272727272727272727272727
288 |
289 | #04002:0.125
290 | #04003:09
291 | #04012:20
292 | #04015:28
293 |
294 | #04102:0.5
295 | #04103:48D8000049D900004ADA00004BDB0000
296 | #04113:21212121
297 |
298 | #04203:4CDC00004DDD00004EDE00004FDF000050E0000051E1000052E2000053E30000
299 | #04213:2121212121212121
300 | #04214:2323232323232323
301 |
302 | #04303:54E4000055E5000056E6000057E7000058E8000059E900005AEA00005BEB0000
303 | #04312:2020202020202020
304 | #04314:2323232300000000
305 | #04315:00000000000000002626262626262626
306 |
307 | #04403:5CEC00005DED00005EEE00005FEF000060F0000061F1000062F2000063F30000
308 | #04411:1C1C1C1C00000000
309 | #04413:0000000022222222
310 | #04414:2525252500000000
311 | #04418:00000000000000002828282828282828
312 |
313 | #04503:64F4000065F5000066F6000067F7000068F8000069F900006AFA00006BFB0000
314 | #04511:1E1E1E1E00000000
315 | #04515:272727272A2A2A2A
316 | #04519:00000000000000002D2D2D2D2D2D2D2D
317 |
318 | #04603:6C0000000000FC00000000000000000000000000000000006D0000000000FD00000000000000000000000000000000006E0000000000FE00000000000000000000000000000000006F0000000000FF0000000000000000000000000000000000710000000000FF0000000000000000000000000000000000730000000000FF00000000000000000000000000000000007500000000FF0000000000000000000000000000000000007700000000FF000000000000000000000000000000000000
319 | #04612:0000001C
320 | #04613:0020
321 | #04614:00000000000000282800000000000000
322 | #04615:2C000000002C2C0000002C0000000000
323 | #04618:0000002F2F000000000000002F000000
324 | #04619:00343400000000000000000000003200
325 |
326 | #04703:7900FF0000000000000000007B00FF0000000000000000007D00FF0000000000000000007F00FF0000000000000000008100FF0000000000000000008300FF0000000000000000008500FF000000000000000000870000FF0000000000000000
327 | #04711:15
328 | #04712:0000001E
329 | #04713:0021
330 | #04714:000000000000002A2A00000000000000
331 | #04715:00000000002E2E0000002E0000000000
332 | #04718:31000031310000000000000031000000
333 | #04719:00363600000000000000000000003400
334 |
335 | #04803:890000FF00000000000000000000000000000000000000008B0000FF00000000000000000000000000000000000000008D0000FF00000000000000000000000000000000000000008F0000FF0000000000000000000000000000000000000000910000FF0000000000000000000000000000000000000000930000FF0000000000000000000000000000000000000000950000FF0000000000000000000000000000000000000000970000FF0000000000000000000000000000000000000912
336 | #04811:17
337 | #04812:00000020
338 | #04813:0023
339 | #04814:000000000000002C2C00000000000000
340 | #04815:00000000003030000000300000000000
341 | #04818:33000033330000000000000033000000
342 | #04819:00383800000000000000000000003600
343 |
344 | #04902:0.5
345 | #04903:24
346 | #04911:1900000000000000000000000000000000000000000000000000000000310000
347 | #04912:3100000000000000000000000000000000000000000000000000000031330000
348 | #04913:3431000000000000000000000000000000000000000000000000003133000000
349 | #04914:0034310000000000000000000000000000000000000000000000313300000000
350 | #04915:0000343100000000000000000000000000000000000000000031330000003131
351 | #04918:0000003431313131313131313131313131313131313131313133000000000000
352 | #04919:0000000034343434343434343434343433333333333333333300000000003333
353 |
354 | #05002:0.5
355 | #05011:000000000000000000000000000000000000000000000000000000000000002F
356 | #05012:2F00000000000000000000000000000000000000000000000000000000002F38
357 | #05013:312F2F00000000000000000000000000000000000000000000000000002F3800
358 | #05014:0031312F2F2F2F2F2F2F2F2F2F2F2F2F0000000000000000000000002F380000
359 | #05015:0000003131313131313131313131313100000000000000000000002F38000000
360 | #05018:000000000000000000000000000000002F2F2F2F2F2F2F2F2F2F2F3800000000
361 | #05019:0000000000000000000000000000000038383838383838383838380000000000
362 |
363 | #05102:0.5
364 | #05112:2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
365 | #05113:0000000000000000000000000000000000000000000000000000000036363636
366 | #05114:0000000000000000000000000000000000000000003636363636363600000000
367 | #05115:0000000000000000000000000000383836363636360000000000000000000000
368 | #05118:0000000000000038383838383838000000000000000000000000000000000000
369 | #05119:3838383838383800000000000000000000000000000000000000000000000000
370 |
371 | #05202:0.5
372 | #05211:2C2C2C2C2C2C2C2C2C2C2C2C2C2C2C2C31313131313131313131313131313131
373 | #05212:0000000000000000000000000000000034340000000000000000000000000000
374 | #05213:0000000000000000000000000000363600003434000000000000000000000000
375 | #05214:0000000000000000000000003636000000000000343434340000000000000000
376 | #05215:0000000000000000363636360000000000000000000000003434343400000000
377 | #05218:0000000036363636000000000000000000000000000000000000000034343434
378 | #05219:3636363600000000000000000000000000000000000000000000000000000000
379 |
380 | #05302:0.5
381 | #05312:31313131313131312F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2D2D2D2D2D2D2D2D
382 | #05313:0000000000000000000000000000000000000000000000000000000031313131
383 | #05314:0000000000000000000000000000000000000000003131313131313100000000
384 | #05315:0000000000000000000000000000323231313131310000000000000000000000
385 | #05318:0000000000000032323232323232000000000000000000000000000000000000
386 | #05319:3232323232323200000000000000000000000000000000000000000000000000
387 |
388 | #05402:0.5
389 | #05412:0000000000000000000000000000000000000000000000002A2A2A2A2A2A2A2A
390 | #05413:000000000000000000000000000000002C2C2C2C2C2C2C2C0000000000000000
391 | #05414:00000000000000002C2C2C2C2C2C2C2C00000000000000000000000000000000
392 | #05415:2D2D2D2D2D2D2D2D000000000000000000000000000000000000000000000000
393 | #05418:2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F00000000000000000000000000000000
394 | #05419:000000000000000000000000000000002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
395 |
396 | #05502:0.5
397 | #05512:002A2A2A2A2A2A2A000000000000000000000000000000000000000000000000
398 | #05513:2A
399 | #05514:2C00000000000000282828282828282828282828282828282626262626262626
400 | #05515:002C2C2C2C2C2C2C2C2C2C2C2C2C2C2C2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A
401 |
402 | #05602:0.5
403 | #05603:12
404 | #05611:25252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525
405 | #05613:29292929292929290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
406 | #05614:00000000000000002A2A2A2A2A2A2A2A00000000000000000000000000000000000000000000000000000000000000000000000000000000002A2A2A2A2A2A2A
407 | #05615:000000000000000000000000000000002C2C2C2C2C2C2C2C0000000000000000000000000000000000000000000000002C2C2C2C2C2C2C2C2C00000000000000
408 | #05618:0000000000000000000000000000000000000000000000002D2D2D2D2D2D2D2D00000000000000002D2D2D2D2D2D2D2D00000000000000000000000000000000
409 | #05619:00000000000000000000000000000000000000000000000000000000000000002F2F2F2F2F2F2F2F000000000000000000000000000000000000000000000000
410 |
411 | #05703:48
412 | #05711:25
413 | #05712:20000000000000000025002500250025
414 | #05713:2900292929292929290029002900290000000000000000000000000000000000
415 | #05715:00002C2C2C2C2C2C2C002C002C002C002A0000002A0000002A0000002A000000
416 | #05718:000000002D2D2D2D
417 |
418 | #05811:00000000000000000023002300230023
419 | #05813:2600262626262626260026002600260000002600000026000000260000002600
420 | #05814:0000000028282828
421 | #05815:2A002A2A2A2A2A2A2A002A002A002A0000000000000000000000000000000000
422 | #05818:000000002C2C2C2C
423 |
424 | #05911:00000000000000000021002100210021
425 | #05912:2500252525252525250025002500250000002500000025000000250000002500
426 | #05913:0000000026262626
427 | #05914:2800282828282828280028002800280000000000000000000000000000000000
428 | #05915:000000002A2A2A2A
429 |
430 | #06011:0000000025252525
431 | #06012:2300232323232323230023002300230000000000000000000000000000000000
432 | #06013:2600262626262626260026002600260029290029292900292929002929290029
433 | #06015:00000000000000000000000000000000002C2C2C002C2C2C002C2C2C002C2C2C
434 | #06019:0000000000000000002F002F002F002F
435 |
436 | #06114:2A002A2A2A2A2A2A2A002A002A002A002A002A2A2A2A2A2A2A002A002A002A00
437 | #06118:000000000000000000000000000000002C002C2C2C2C2C2C2C002C002C002C00
438 | #06119:2D002D2D2D2D2D2D2D002D002D002D0000000000000000000000000000000000
439 |
440 | #06212:0000000000000000000000000000000000001E1E1E1E1E1E1E001E001E001E00
441 | #06213:2900292929292929290029002900290000000000000000000000000000000000
442 | #06214:0000000000000000000000000000000000002121212121212100210021002100
443 | #06215:002A
444 | #06218:2C002C2C2C2C2C2C2C002C002C002C0000000000000000000000000000000000
445 |
446 | #06303:000000000000000000000000000000000000000000000000000000004600440042003E003900350030002B00260020001A00000014000F000A00050001FF01FF
447 | #06311:000000000000000000000000000000001D001D1D1D1D1D1D1D001D001D001D00
448 | #06312:1E001E1E1E1E1E1E1E001E001E001E0000000000000000000000000000000000
449 | #06313:2000202020202020200020002000200020002020202020202000200020002000
450 |
451 | #06402:2
452 | #06412:1E
453 |
454 | #06502:0.25
455 | #06511:00000000000000000000003700370037
456 | #06512:00000000003700370037000000000000
457 | #06513:00370037000000000000000000000000
458 | #06514:37
459 | #06515:0037370000000000
460 | #06518:0000003737370000
461 | #06519:0000000000003737
462 |
463 |
--------------------------------------------------------------------------------