├── .generators
├── component
│ ├── actions.coffee.hbs
│ ├── generator.coffee
│ ├── index.coffee.hbs
│ ├── template.jade.hbs
│ └── test.coffee.hbs
├── generator
│ ├── default-generator.coffee.hbs
│ ├── dummy.json.hbs
│ └── generator.coffee
└── scene
│ ├── aggregator.coffee.hbs
│ ├── generator.coffee
│ ├── index.coffee.hbs
│ ├── subscriber.coffee.hbs
│ └── test.coffee.hbs
├── .gitignore
├── README.md
├── deploy
├── bundle.js
├── index.html
└── style.css
├── docs
├── dev-guide.md
└── intro.md
├── domains
├── battlefield
│ ├── .gitignore
│ ├── gulpfile.coffee
│ ├── package.json
│ ├── src
│ │ ├── behaviours
│ │ │ └── constant-friction.coffee
│ │ ├── core.ts
│ │ ├── entities
│ │ │ ├── battlers
│ │ │ │ ├── battler.ts
│ │ │ │ ├── enemies
│ │ │ │ │ └── enemy.ts
│ │ │ │ └── player.ts
│ │ │ ├── entity.ts
│ │ │ └── objects
│ │ │ │ ├── block.ts
│ │ │ │ ├── bullets
│ │ │ │ └── bullet.ts
│ │ │ │ ├── polygon.ts
│ │ │ │ └── traps
│ │ │ │ └── bullet-trap.ts
│ │ ├── entry.ts
│ │ ├── stages
│ │ │ ├── battle-stage.ts
│ │ │ ├── stage.ts
│ │ │ └── task-runner.ts
│ │ ├── tasks
│ │ │ ├── create-bullet-trap.ts
│ │ │ ├── create-bullet.ts
│ │ │ ├── death-checker.ts
│ │ │ ├── remove-entity.ts
│ │ │ ├── simple-spawner.ts
│ │ │ └── task.ts
│ │ ├── types.d.ts
│ │ ├── utils
│ │ │ └── serialize.ts
│ │ └── values
│ │ │ ├── group-id.ts
│ │ │ └── priority.ts
│ └── test
│ │ └── stages
│ │ └── stage-test.coffee
└── map-editor
│ ├── debug.html
│ ├── index.js
│ └── src
│ ├── component
│ ├── actions.coffee
│ ├── index.coffee
│ └── template.jade
│ ├── index.js
│ └── scene
│ ├── aggregator.coffee
│ ├── index.coffee
│ └── subscriber.coffee
├── dtsm.json
├── gulpfile.coffee
├── package.json
├── public
└── index.html
├── scripts
├── build
└── watch
├── src
├── components
│ ├── field
│ │ ├── actions.coffee
│ │ ├── index.coffee
│ │ └── template.jade
│ ├── menu
│ │ ├── actions.coffee
│ │ ├── index.coffee
│ │ └── template.jade
│ └── opening
│ │ ├── actions.coffee
│ │ ├── index.coffee
│ │ └── template.jade
├── index.coffee
├── router.coffee
├── scenes
│ ├── field
│ │ ├── aggregator.coffee
│ │ ├── index.coffee
│ │ └── subscriber.coffee
│ ├── menu
│ │ ├── aggregator.coffee
│ │ ├── index.coffee
│ │ └── subscriber.coffee
│ └── opening
│ │ ├── aggregator.coffee
│ │ ├── index.coffee
│ │ └── subscriber.coffee
└── setup.coffee
├── styles
├── mixins.scss
├── style.scss
└── variables.scss
├── test
├── components
│ ├── menu-test.coffee
│ └── opening-test.coffee
├── scenes
│ ├── menu-test.coffee
│ └── opening-test.coffee
└── test-helper.coffee
└── webpack.config.js
/.generators/component/actions.coffee.hbs:
--------------------------------------------------------------------------------
1 | module.exports =
2 | onClick: ->
3 | @emit '{{$1}}:event', {}
4 |
--------------------------------------------------------------------------------
/.generators/component/generator.coffee:
--------------------------------------------------------------------------------
1 | changeCase = require 'change-case'
2 | module.exports = (g, {$1}) ->
3 | g.gen "index.coffee.hbs", "src/components/#{$1}/index.coffee"
4 | g.gen "template.jade.hbs", "src/components/#{$1}/template.jade"
5 | g.gen "actions.coffee.hbs", "src/components/#{$1}/actions.coffee"
6 | g.gen "test.coffee.hbs", "test/components/#{$1}-test.coffee"
7 |
--------------------------------------------------------------------------------
/.generators/component/index.coffee.hbs:
--------------------------------------------------------------------------------
1 | template = require './template.jade'
2 | actions = require './actions'
3 | extend = require 'extend'
4 |
5 | module.exports = React.createClass
6 | mixins: [Overworld.mixinFor(-> app), actions]
7 | render: ->
8 | template extend {}, @, @props, @state
9 |
--------------------------------------------------------------------------------
/.generators/component/template.jade.hbs:
--------------------------------------------------------------------------------
1 | .{{$1}}
2 | span {{$1}}
3 |
--------------------------------------------------------------------------------
/.generators/component/test.coffee.hbs:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | component = require '../../src/components/{{$1}}'
3 | element = React.createFactory component
4 |
5 | describe 'components/{{$1}}', ->
6 | describe '#render', ->
7 | it 'should validate output', ->
8 | rendered = React.renderToString(element {})
9 |
--------------------------------------------------------------------------------
/.generators/generator/default-generator.coffee.hbs:
--------------------------------------------------------------------------------
1 | module.exports = (g, {$1}) ->
2 | g.gen "{{$1}}.json.hbs", "app/{{$1}}.json"
--------------------------------------------------------------------------------
/.generators/generator/dummy.json.hbs:
--------------------------------------------------------------------------------
1 | {"name": "{{$1}}"}
--------------------------------------------------------------------------------
/.generators/generator/generator.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (g, {$1}) ->
2 | g.gen 'default-generator.coffee.hbs', ".generators/#{$1}/generator.coffee"
3 | g.gen 'dummy.json.hbs', ".generators/#{$1}/#{$1}.json.hbs"
--------------------------------------------------------------------------------
/.generators/scene/aggregator.coffee.hbs:
--------------------------------------------------------------------------------
1 | module.exports =
2 | initState: (props) -> {}
3 | aggregate: (props, state) -> {}
4 |
--------------------------------------------------------------------------------
/.generators/scene/generator.coffee:
--------------------------------------------------------------------------------
1 | changeCase = require 'change-case'
2 | module.exports = (g, {$1}) ->
3 | g.gen "index.coffee.hbs", "src/scenes/#{$1}/index.coffee"
4 | g.gen "aggregator.coffee.hbs", "src/scenes/#{$1}/aggregator.coffee"
5 | g.gen "subscriber.coffee.hbs", "src/scenes/#{$1}/subscriber.coffee"
6 | g.gen "test.coffee.hbs", "test/scenes/#{$1}-test.coffee"
7 |
--------------------------------------------------------------------------------
/.generators/scene/index.coffee.hbs:
--------------------------------------------------------------------------------
1 | module.exports =
2 | class extends Overworld.World
3 | @component : require '../../components/{{$1}}'
4 | @aggregator: require './aggregator'
5 | @subscriber: require './subscriber'
6 |
--------------------------------------------------------------------------------
/.generators/scene/subscriber.coffee.hbs:
--------------------------------------------------------------------------------
1 | module.exports = (subscribe) ->
2 | subscribe '{{$1}}:update', (context) -> (args...) ->
3 | context.update {}
4 |
--------------------------------------------------------------------------------
/.generators/scene/test.coffee.hbs:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | Scene = require '../../src/scenes/{{$1}}'
3 |
4 | describe 'scenes/{{$1}}', ->
5 | it 'should be written', ->
6 | new Scene
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/d866fb556184cc1edffd9d0f1ca205fe1916a7f6/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 |
7 | # Runtime data
8 | pids
9 | *.pid
10 | *.seed
11 |
12 | # Directory for instrumented libs generated by jscoverage/JSCover
13 | lib-cov
14 |
15 | # Coverage directory used by tools like istanbul
16 | coverage
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
29 | node_modules
30 |
31 |
32 | ### https://raw.github.com/github/gitignore/d866fb556184cc1edffd9d0f1ca205fe1916a7f6/Global/OSX.gitignore
33 |
34 | .DS_Store
35 | .AppleDouble
36 | .LSOverride
37 |
38 | # Icon must end with two \r
39 | Icon
40 |
41 | # Thumbnails
42 | ._*
43 |
44 | # Files that might appear on external disk
45 | .Spotlight-V100
46 | .Trashes
47 |
48 | # Directories potentially created on remote AFP share
49 | .AppleDB
50 | .AppleDesktop
51 | Network Trash Folder
52 | Temporary Items
53 | .apdisk
54 | .tmp
55 | public/bundle.js
56 | public/style.css
57 | lib
58 | typings
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Actrogue2
2 |
3 | Hack and Slash written by javascript
4 |
5 | See docs/intro.md
6 |
7 | ## Development
8 |
9 | Build
10 |
11 | ```shell
12 | npm install -g Microsoft/typescript # Install typescript 1.4
13 | npm install
14 | ./scripts/build
15 | open public/index.html
16 | ```
17 |
18 | Watch
19 |
20 | ```
21 | ./scripts/build
22 | ```
23 |
--------------------------------------------------------------------------------
/deploy/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AR
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/deploy/style.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 | /* FONT PATH
6 | * -------------------------- */
7 | @font-face {
8 | font-family: 'FontAwesome';
9 | src: url('../node_modules/font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0');
10 | src: url('../node_modules/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../node_modules/font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../node_modules/font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../node_modules/font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
11 | font-weight: normal;
12 | font-style: normal; }
13 |
14 | .fa {
15 | display: inline-block;
16 | font: normal normal normal 14px/1 FontAwesome;
17 | font-size: inherit;
18 | text-rendering: auto;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale; }
21 |
22 | /* makes the font 33% larger relative to the icon container */
23 | .fa-lg {
24 | font-size: 1.33333em;
25 | line-height: 0.75em;
26 | vertical-align: -15%; }
27 |
28 | .fa-2x {
29 | font-size: 2em; }
30 |
31 | .fa-3x {
32 | font-size: 3em; }
33 |
34 | .fa-4x {
35 | font-size: 4em; }
36 |
37 | .fa-5x {
38 | font-size: 5em; }
39 |
40 | .fa-fw {
41 | width: 1.28571em;
42 | text-align: center; }
43 |
44 | .fa-ul {
45 | padding-left: 0;
46 | margin-left: 2.14286em;
47 | list-style-type: none; }
48 | .fa-ul > li {
49 | position: relative; }
50 |
51 | .fa-li {
52 | position: absolute;
53 | left: -2.14286em;
54 | width: 2.14286em;
55 | top: 0.14286em;
56 | text-align: center; }
57 | .fa-li.fa-lg {
58 | left: -1.85714em; }
59 |
60 | .fa-border {
61 | padding: 0.2em 0.25em 0.15em;
62 | border: solid 0.08em #eee;
63 | border-radius: 0.1em; }
64 |
65 | .pull-right {
66 | float: right; }
67 |
68 | .pull-left {
69 | float: left; }
70 |
71 | .fa.pull-left {
72 | margin-right: 0.3em; }
73 | .fa.pull-right {
74 | margin-left: 0.3em; }
75 |
76 | .fa-spin {
77 | -webkit-animation: fa-spin 2s infinite linear;
78 | animation: fa-spin 2s infinite linear; }
79 |
80 | @-webkit-keyframes fa-spin {
81 | 0% {
82 | -webkit-transform: rotate(0deg);
83 | transform: rotate(0deg); }
84 |
85 | 100% {
86 | -webkit-transform: rotate(359deg);
87 | transform: rotate(359deg); } }
88 |
89 | @keyframes fa-spin {
90 | 0% {
91 | -webkit-transform: rotate(0deg);
92 | transform: rotate(0deg); }
93 |
94 | 100% {
95 | -webkit-transform: rotate(359deg);
96 | transform: rotate(359deg); } }
97 |
98 | .fa-rotate-90 {
99 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
100 | -webkit-transform: rotate(90deg);
101 | -ms-transform: rotate(90deg);
102 | transform: rotate(90deg); }
103 |
104 | .fa-rotate-180 {
105 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
106 | -webkit-transform: rotate(180deg);
107 | -ms-transform: rotate(180deg);
108 | transform: rotate(180deg); }
109 |
110 | .fa-rotate-270 {
111 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
112 | -webkit-transform: rotate(270deg);
113 | -ms-transform: rotate(270deg);
114 | transform: rotate(270deg); }
115 |
116 | .fa-flip-horizontal {
117 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
118 | -webkit-transform: scale(-1, 1);
119 | -ms-transform: scale(-1, 1);
120 | transform: scale(-1, 1); }
121 |
122 | .fa-flip-vertical {
123 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
124 | -webkit-transform: scale(1, -1);
125 | -ms-transform: scale(1, -1);
126 | transform: scale(1, -1); }
127 |
128 | :root .fa-rotate-90, :root .fa-rotate-180, :root .fa-rotate-270, :root .fa-flip-horizontal, :root .fa-flip-vertical {
129 | filter: none; }
130 |
131 | .fa-stack {
132 | position: relative;
133 | display: inline-block;
134 | width: 2em;
135 | height: 2em;
136 | line-height: 2em;
137 | vertical-align: middle; }
138 |
139 | .fa-stack-1x, .fa-stack-2x {
140 | position: absolute;
141 | left: 0;
142 | width: 100%;
143 | text-align: center; }
144 |
145 | .fa-stack-1x {
146 | line-height: inherit; }
147 |
148 | .fa-stack-2x {
149 | font-size: 2em; }
150 |
151 | .fa-inverse {
152 | color: #fff; }
153 |
154 | /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
155 | readers do not read off random characters that represent icons */
156 | .fa-glass:before {
157 | content: "\f000"; }
158 |
159 | .fa-music:before {
160 | content: "\f001"; }
161 |
162 | .fa-search:before {
163 | content: "\f002"; }
164 |
165 | .fa-envelope-o:before {
166 | content: "\f003"; }
167 |
168 | .fa-heart:before {
169 | content: "\f004"; }
170 |
171 | .fa-star:before {
172 | content: "\f005"; }
173 |
174 | .fa-star-o:before {
175 | content: "\f006"; }
176 |
177 | .fa-user:before {
178 | content: "\f007"; }
179 |
180 | .fa-film:before {
181 | content: "\f008"; }
182 |
183 | .fa-th-large:before {
184 | content: "\f009"; }
185 |
186 | .fa-th:before {
187 | content: "\f00a"; }
188 |
189 | .fa-th-list:before {
190 | content: "\f00b"; }
191 |
192 | .fa-check:before {
193 | content: "\f00c"; }
194 |
195 | .fa-remove:before, .fa-close:before, .fa-times:before {
196 | content: "\f00d"; }
197 |
198 | .fa-search-plus:before {
199 | content: "\f00e"; }
200 |
201 | .fa-search-minus:before {
202 | content: "\f010"; }
203 |
204 | .fa-power-off:before {
205 | content: "\f011"; }
206 |
207 | .fa-signal:before {
208 | content: "\f012"; }
209 |
210 | .fa-gear:before, .fa-cog:before {
211 | content: "\f013"; }
212 |
213 | .fa-trash-o:before {
214 | content: "\f014"; }
215 |
216 | .fa-home:before {
217 | content: "\f015"; }
218 |
219 | .fa-file-o:before {
220 | content: "\f016"; }
221 |
222 | .fa-clock-o:before {
223 | content: "\f017"; }
224 |
225 | .fa-road:before {
226 | content: "\f018"; }
227 |
228 | .fa-download:before {
229 | content: "\f019"; }
230 |
231 | .fa-arrow-circle-o-down:before {
232 | content: "\f01a"; }
233 |
234 | .fa-arrow-circle-o-up:before {
235 | content: "\f01b"; }
236 |
237 | .fa-inbox:before {
238 | content: "\f01c"; }
239 |
240 | .fa-play-circle-o:before {
241 | content: "\f01d"; }
242 |
243 | .fa-rotate-right:before, .fa-repeat:before {
244 | content: "\f01e"; }
245 |
246 | .fa-refresh:before {
247 | content: "\f021"; }
248 |
249 | .fa-list-alt:before {
250 | content: "\f022"; }
251 |
252 | .fa-lock:before {
253 | content: "\f023"; }
254 |
255 | .fa-flag:before {
256 | content: "\f024"; }
257 |
258 | .fa-headphones:before {
259 | content: "\f025"; }
260 |
261 | .fa-volume-off:before {
262 | content: "\f026"; }
263 |
264 | .fa-volume-down:before {
265 | content: "\f027"; }
266 |
267 | .fa-volume-up:before {
268 | content: "\f028"; }
269 |
270 | .fa-qrcode:before {
271 | content: "\f029"; }
272 |
273 | .fa-barcode:before {
274 | content: "\f02a"; }
275 |
276 | .fa-tag:before {
277 | content: "\f02b"; }
278 |
279 | .fa-tags:before {
280 | content: "\f02c"; }
281 |
282 | .fa-book:before {
283 | content: "\f02d"; }
284 |
285 | .fa-bookmark:before {
286 | content: "\f02e"; }
287 |
288 | .fa-print:before {
289 | content: "\f02f"; }
290 |
291 | .fa-camera:before {
292 | content: "\f030"; }
293 |
294 | .fa-font:before {
295 | content: "\f031"; }
296 |
297 | .fa-bold:before {
298 | content: "\f032"; }
299 |
300 | .fa-italic:before {
301 | content: "\f033"; }
302 |
303 | .fa-text-height:before {
304 | content: "\f034"; }
305 |
306 | .fa-text-width:before {
307 | content: "\f035"; }
308 |
309 | .fa-align-left:before {
310 | content: "\f036"; }
311 |
312 | .fa-align-center:before {
313 | content: "\f037"; }
314 |
315 | .fa-align-right:before {
316 | content: "\f038"; }
317 |
318 | .fa-align-justify:before {
319 | content: "\f039"; }
320 |
321 | .fa-list:before {
322 | content: "\f03a"; }
323 |
324 | .fa-dedent:before, .fa-outdent:before {
325 | content: "\f03b"; }
326 |
327 | .fa-indent:before {
328 | content: "\f03c"; }
329 |
330 | .fa-video-camera:before {
331 | content: "\f03d"; }
332 |
333 | .fa-photo:before, .fa-image:before, .fa-picture-o:before {
334 | content: "\f03e"; }
335 |
336 | .fa-pencil:before {
337 | content: "\f040"; }
338 |
339 | .fa-map-marker:before {
340 | content: "\f041"; }
341 |
342 | .fa-adjust:before {
343 | content: "\f042"; }
344 |
345 | .fa-tint:before {
346 | content: "\f043"; }
347 |
348 | .fa-edit:before, .fa-pencil-square-o:before {
349 | content: "\f044"; }
350 |
351 | .fa-share-square-o:before {
352 | content: "\f045"; }
353 |
354 | .fa-check-square-o:before {
355 | content: "\f046"; }
356 |
357 | .fa-arrows:before {
358 | content: "\f047"; }
359 |
360 | .fa-step-backward:before {
361 | content: "\f048"; }
362 |
363 | .fa-fast-backward:before {
364 | content: "\f049"; }
365 |
366 | .fa-backward:before {
367 | content: "\f04a"; }
368 |
369 | .fa-play:before {
370 | content: "\f04b"; }
371 |
372 | .fa-pause:before {
373 | content: "\f04c"; }
374 |
375 | .fa-stop:before {
376 | content: "\f04d"; }
377 |
378 | .fa-forward:before {
379 | content: "\f04e"; }
380 |
381 | .fa-fast-forward:before {
382 | content: "\f050"; }
383 |
384 | .fa-step-forward:before {
385 | content: "\f051"; }
386 |
387 | .fa-eject:before {
388 | content: "\f052"; }
389 |
390 | .fa-chevron-left:before {
391 | content: "\f053"; }
392 |
393 | .fa-chevron-right:before {
394 | content: "\f054"; }
395 |
396 | .fa-plus-circle:before {
397 | content: "\f055"; }
398 |
399 | .fa-minus-circle:before {
400 | content: "\f056"; }
401 |
402 | .fa-times-circle:before {
403 | content: "\f057"; }
404 |
405 | .fa-check-circle:before {
406 | content: "\f058"; }
407 |
408 | .fa-question-circle:before {
409 | content: "\f059"; }
410 |
411 | .fa-info-circle:before {
412 | content: "\f05a"; }
413 |
414 | .fa-crosshairs:before {
415 | content: "\f05b"; }
416 |
417 | .fa-times-circle-o:before {
418 | content: "\f05c"; }
419 |
420 | .fa-check-circle-o:before {
421 | content: "\f05d"; }
422 |
423 | .fa-ban:before {
424 | content: "\f05e"; }
425 |
426 | .fa-arrow-left:before {
427 | content: "\f060"; }
428 |
429 | .fa-arrow-right:before {
430 | content: "\f061"; }
431 |
432 | .fa-arrow-up:before {
433 | content: "\f062"; }
434 |
435 | .fa-arrow-down:before {
436 | content: "\f063"; }
437 |
438 | .fa-mail-forward:before, .fa-share:before {
439 | content: "\f064"; }
440 |
441 | .fa-expand:before {
442 | content: "\f065"; }
443 |
444 | .fa-compress:before {
445 | content: "\f066"; }
446 |
447 | .fa-plus:before {
448 | content: "\f067"; }
449 |
450 | .fa-minus:before {
451 | content: "\f068"; }
452 |
453 | .fa-asterisk:before {
454 | content: "\f069"; }
455 |
456 | .fa-exclamation-circle:before {
457 | content: "\f06a"; }
458 |
459 | .fa-gift:before {
460 | content: "\f06b"; }
461 |
462 | .fa-leaf:before {
463 | content: "\f06c"; }
464 |
465 | .fa-fire:before {
466 | content: "\f06d"; }
467 |
468 | .fa-eye:before {
469 | content: "\f06e"; }
470 |
471 | .fa-eye-slash:before {
472 | content: "\f070"; }
473 |
474 | .fa-warning:before, .fa-exclamation-triangle:before {
475 | content: "\f071"; }
476 |
477 | .fa-plane:before {
478 | content: "\f072"; }
479 |
480 | .fa-calendar:before {
481 | content: "\f073"; }
482 |
483 | .fa-random:before {
484 | content: "\f074"; }
485 |
486 | .fa-comment:before {
487 | content: "\f075"; }
488 |
489 | .fa-magnet:before {
490 | content: "\f076"; }
491 |
492 | .fa-chevron-up:before {
493 | content: "\f077"; }
494 |
495 | .fa-chevron-down:before {
496 | content: "\f078"; }
497 |
498 | .fa-retweet:before {
499 | content: "\f079"; }
500 |
501 | .fa-shopping-cart:before {
502 | content: "\f07a"; }
503 |
504 | .fa-folder:before {
505 | content: "\f07b"; }
506 |
507 | .fa-folder-open:before {
508 | content: "\f07c"; }
509 |
510 | .fa-arrows-v:before {
511 | content: "\f07d"; }
512 |
513 | .fa-arrows-h:before {
514 | content: "\f07e"; }
515 |
516 | .fa-bar-chart-o:before, .fa-bar-chart:before {
517 | content: "\f080"; }
518 |
519 | .fa-twitter-square:before {
520 | content: "\f081"; }
521 |
522 | .fa-facebook-square:before {
523 | content: "\f082"; }
524 |
525 | .fa-camera-retro:before {
526 | content: "\f083"; }
527 |
528 | .fa-key:before {
529 | content: "\f084"; }
530 |
531 | .fa-gears:before, .fa-cogs:before {
532 | content: "\f085"; }
533 |
534 | .fa-comments:before {
535 | content: "\f086"; }
536 |
537 | .fa-thumbs-o-up:before {
538 | content: "\f087"; }
539 |
540 | .fa-thumbs-o-down:before {
541 | content: "\f088"; }
542 |
543 | .fa-star-half:before {
544 | content: "\f089"; }
545 |
546 | .fa-heart-o:before {
547 | content: "\f08a"; }
548 |
549 | .fa-sign-out:before {
550 | content: "\f08b"; }
551 |
552 | .fa-linkedin-square:before {
553 | content: "\f08c"; }
554 |
555 | .fa-thumb-tack:before {
556 | content: "\f08d"; }
557 |
558 | .fa-external-link:before {
559 | content: "\f08e"; }
560 |
561 | .fa-sign-in:before {
562 | content: "\f090"; }
563 |
564 | .fa-trophy:before {
565 | content: "\f091"; }
566 |
567 | .fa-github-square:before {
568 | content: "\f092"; }
569 |
570 | .fa-upload:before {
571 | content: "\f093"; }
572 |
573 | .fa-lemon-o:before {
574 | content: "\f094"; }
575 |
576 | .fa-phone:before {
577 | content: "\f095"; }
578 |
579 | .fa-square-o:before {
580 | content: "\f096"; }
581 |
582 | .fa-bookmark-o:before {
583 | content: "\f097"; }
584 |
585 | .fa-phone-square:before {
586 | content: "\f098"; }
587 |
588 | .fa-twitter:before {
589 | content: "\f099"; }
590 |
591 | .fa-facebook:before {
592 | content: "\f09a"; }
593 |
594 | .fa-github:before {
595 | content: "\f09b"; }
596 |
597 | .fa-unlock:before {
598 | content: "\f09c"; }
599 |
600 | .fa-credit-card:before {
601 | content: "\f09d"; }
602 |
603 | .fa-rss:before {
604 | content: "\f09e"; }
605 |
606 | .fa-hdd-o:before {
607 | content: "\f0a0"; }
608 |
609 | .fa-bullhorn:before {
610 | content: "\f0a1"; }
611 |
612 | .fa-bell:before {
613 | content: "\f0f3"; }
614 |
615 | .fa-certificate:before {
616 | content: "\f0a3"; }
617 |
618 | .fa-hand-o-right:before {
619 | content: "\f0a4"; }
620 |
621 | .fa-hand-o-left:before {
622 | content: "\f0a5"; }
623 |
624 | .fa-hand-o-up:before {
625 | content: "\f0a6"; }
626 |
627 | .fa-hand-o-down:before {
628 | content: "\f0a7"; }
629 |
630 | .fa-arrow-circle-left:before {
631 | content: "\f0a8"; }
632 |
633 | .fa-arrow-circle-right:before {
634 | content: "\f0a9"; }
635 |
636 | .fa-arrow-circle-up:before {
637 | content: "\f0aa"; }
638 |
639 | .fa-arrow-circle-down:before {
640 | content: "\f0ab"; }
641 |
642 | .fa-globe:before {
643 | content: "\f0ac"; }
644 |
645 | .fa-wrench:before {
646 | content: "\f0ad"; }
647 |
648 | .fa-tasks:before {
649 | content: "\f0ae"; }
650 |
651 | .fa-filter:before {
652 | content: "\f0b0"; }
653 |
654 | .fa-briefcase:before {
655 | content: "\f0b1"; }
656 |
657 | .fa-arrows-alt:before {
658 | content: "\f0b2"; }
659 |
660 | .fa-group:before, .fa-users:before {
661 | content: "\f0c0"; }
662 |
663 | .fa-chain:before, .fa-link:before {
664 | content: "\f0c1"; }
665 |
666 | .fa-cloud:before {
667 | content: "\f0c2"; }
668 |
669 | .fa-flask:before {
670 | content: "\f0c3"; }
671 |
672 | .fa-cut:before, .fa-scissors:before {
673 | content: "\f0c4"; }
674 |
675 | .fa-copy:before, .fa-files-o:before {
676 | content: "\f0c5"; }
677 |
678 | .fa-paperclip:before {
679 | content: "\f0c6"; }
680 |
681 | .fa-save:before, .fa-floppy-o:before {
682 | content: "\f0c7"; }
683 |
684 | .fa-square:before {
685 | content: "\f0c8"; }
686 |
687 | .fa-navicon:before, .fa-reorder:before, .fa-bars:before {
688 | content: "\f0c9"; }
689 |
690 | .fa-list-ul:before {
691 | content: "\f0ca"; }
692 |
693 | .fa-list-ol:before {
694 | content: "\f0cb"; }
695 |
696 | .fa-strikethrough:before {
697 | content: "\f0cc"; }
698 |
699 | .fa-underline:before {
700 | content: "\f0cd"; }
701 |
702 | .fa-table:before {
703 | content: "\f0ce"; }
704 |
705 | .fa-magic:before {
706 | content: "\f0d0"; }
707 |
708 | .fa-truck:before {
709 | content: "\f0d1"; }
710 |
711 | .fa-pinterest:before {
712 | content: "\f0d2"; }
713 |
714 | .fa-pinterest-square:before {
715 | content: "\f0d3"; }
716 |
717 | .fa-google-plus-square:before {
718 | content: "\f0d4"; }
719 |
720 | .fa-google-plus:before {
721 | content: "\f0d5"; }
722 |
723 | .fa-money:before {
724 | content: "\f0d6"; }
725 |
726 | .fa-caret-down:before {
727 | content: "\f0d7"; }
728 |
729 | .fa-caret-up:before {
730 | content: "\f0d8"; }
731 |
732 | .fa-caret-left:before {
733 | content: "\f0d9"; }
734 |
735 | .fa-caret-right:before {
736 | content: "\f0da"; }
737 |
738 | .fa-columns:before {
739 | content: "\f0db"; }
740 |
741 | .fa-unsorted:before, .fa-sort:before {
742 | content: "\f0dc"; }
743 |
744 | .fa-sort-down:before, .fa-sort-desc:before {
745 | content: "\f0dd"; }
746 |
747 | .fa-sort-up:before, .fa-sort-asc:before {
748 | content: "\f0de"; }
749 |
750 | .fa-envelope:before {
751 | content: "\f0e0"; }
752 |
753 | .fa-linkedin:before {
754 | content: "\f0e1"; }
755 |
756 | .fa-rotate-left:before, .fa-undo:before {
757 | content: "\f0e2"; }
758 |
759 | .fa-legal:before, .fa-gavel:before {
760 | content: "\f0e3"; }
761 |
762 | .fa-dashboard:before, .fa-tachometer:before {
763 | content: "\f0e4"; }
764 |
765 | .fa-comment-o:before {
766 | content: "\f0e5"; }
767 |
768 | .fa-comments-o:before {
769 | content: "\f0e6"; }
770 |
771 | .fa-flash:before, .fa-bolt:before {
772 | content: "\f0e7"; }
773 |
774 | .fa-sitemap:before {
775 | content: "\f0e8"; }
776 |
777 | .fa-umbrella:before {
778 | content: "\f0e9"; }
779 |
780 | .fa-paste:before, .fa-clipboard:before {
781 | content: "\f0ea"; }
782 |
783 | .fa-lightbulb-o:before {
784 | content: "\f0eb"; }
785 |
786 | .fa-exchange:before {
787 | content: "\f0ec"; }
788 |
789 | .fa-cloud-download:before {
790 | content: "\f0ed"; }
791 |
792 | .fa-cloud-upload:before {
793 | content: "\f0ee"; }
794 |
795 | .fa-user-md:before {
796 | content: "\f0f0"; }
797 |
798 | .fa-stethoscope:before {
799 | content: "\f0f1"; }
800 |
801 | .fa-suitcase:before {
802 | content: "\f0f2"; }
803 |
804 | .fa-bell-o:before {
805 | content: "\f0a2"; }
806 |
807 | .fa-coffee:before {
808 | content: "\f0f4"; }
809 |
810 | .fa-cutlery:before {
811 | content: "\f0f5"; }
812 |
813 | .fa-file-text-o:before {
814 | content: "\f0f6"; }
815 |
816 | .fa-building-o:before {
817 | content: "\f0f7"; }
818 |
819 | .fa-hospital-o:before {
820 | content: "\f0f8"; }
821 |
822 | .fa-ambulance:before {
823 | content: "\f0f9"; }
824 |
825 | .fa-medkit:before {
826 | content: "\f0fa"; }
827 |
828 | .fa-fighter-jet:before {
829 | content: "\f0fb"; }
830 |
831 | .fa-beer:before {
832 | content: "\f0fc"; }
833 |
834 | .fa-h-square:before {
835 | content: "\f0fd"; }
836 |
837 | .fa-plus-square:before {
838 | content: "\f0fe"; }
839 |
840 | .fa-angle-double-left:before {
841 | content: "\f100"; }
842 |
843 | .fa-angle-double-right:before {
844 | content: "\f101"; }
845 |
846 | .fa-angle-double-up:before {
847 | content: "\f102"; }
848 |
849 | .fa-angle-double-down:before {
850 | content: "\f103"; }
851 |
852 | .fa-angle-left:before {
853 | content: "\f104"; }
854 |
855 | .fa-angle-right:before {
856 | content: "\f105"; }
857 |
858 | .fa-angle-up:before {
859 | content: "\f106"; }
860 |
861 | .fa-angle-down:before {
862 | content: "\f107"; }
863 |
864 | .fa-desktop:before {
865 | content: "\f108"; }
866 |
867 | .fa-laptop:before {
868 | content: "\f109"; }
869 |
870 | .fa-tablet:before {
871 | content: "\f10a"; }
872 |
873 | .fa-mobile-phone:before, .fa-mobile:before {
874 | content: "\f10b"; }
875 |
876 | .fa-circle-o:before {
877 | content: "\f10c"; }
878 |
879 | .fa-quote-left:before {
880 | content: "\f10d"; }
881 |
882 | .fa-quote-right:before {
883 | content: "\f10e"; }
884 |
885 | .fa-spinner:before {
886 | content: "\f110"; }
887 |
888 | .fa-circle:before {
889 | content: "\f111"; }
890 |
891 | .fa-mail-reply:before, .fa-reply:before {
892 | content: "\f112"; }
893 |
894 | .fa-github-alt:before {
895 | content: "\f113"; }
896 |
897 | .fa-folder-o:before {
898 | content: "\f114"; }
899 |
900 | .fa-folder-open-o:before {
901 | content: "\f115"; }
902 |
903 | .fa-smile-o:before {
904 | content: "\f118"; }
905 |
906 | .fa-frown-o:before {
907 | content: "\f119"; }
908 |
909 | .fa-meh-o:before {
910 | content: "\f11a"; }
911 |
912 | .fa-gamepad:before {
913 | content: "\f11b"; }
914 |
915 | .fa-keyboard-o:before {
916 | content: "\f11c"; }
917 |
918 | .fa-flag-o:before {
919 | content: "\f11d"; }
920 |
921 | .fa-flag-checkered:before {
922 | content: "\f11e"; }
923 |
924 | .fa-terminal:before {
925 | content: "\f120"; }
926 |
927 | .fa-code:before {
928 | content: "\f121"; }
929 |
930 | .fa-mail-reply-all:before, .fa-reply-all:before {
931 | content: "\f122"; }
932 |
933 | .fa-star-half-empty:before, .fa-star-half-full:before, .fa-star-half-o:before {
934 | content: "\f123"; }
935 |
936 | .fa-location-arrow:before {
937 | content: "\f124"; }
938 |
939 | .fa-crop:before {
940 | content: "\f125"; }
941 |
942 | .fa-code-fork:before {
943 | content: "\f126"; }
944 |
945 | .fa-unlink:before, .fa-chain-broken:before {
946 | content: "\f127"; }
947 |
948 | .fa-question:before {
949 | content: "\f128"; }
950 |
951 | .fa-info:before {
952 | content: "\f129"; }
953 |
954 | .fa-exclamation:before {
955 | content: "\f12a"; }
956 |
957 | .fa-superscript:before {
958 | content: "\f12b"; }
959 |
960 | .fa-subscript:before {
961 | content: "\f12c"; }
962 |
963 | .fa-eraser:before {
964 | content: "\f12d"; }
965 |
966 | .fa-puzzle-piece:before {
967 | content: "\f12e"; }
968 |
969 | .fa-microphone:before {
970 | content: "\f130"; }
971 |
972 | .fa-microphone-slash:before {
973 | content: "\f131"; }
974 |
975 | .fa-shield:before {
976 | content: "\f132"; }
977 |
978 | .fa-calendar-o:before {
979 | content: "\f133"; }
980 |
981 | .fa-fire-extinguisher:before {
982 | content: "\f134"; }
983 |
984 | .fa-rocket:before {
985 | content: "\f135"; }
986 |
987 | .fa-maxcdn:before {
988 | content: "\f136"; }
989 |
990 | .fa-chevron-circle-left:before {
991 | content: "\f137"; }
992 |
993 | .fa-chevron-circle-right:before {
994 | content: "\f138"; }
995 |
996 | .fa-chevron-circle-up:before {
997 | content: "\f139"; }
998 |
999 | .fa-chevron-circle-down:before {
1000 | content: "\f13a"; }
1001 |
1002 | .fa-html5:before {
1003 | content: "\f13b"; }
1004 |
1005 | .fa-css3:before {
1006 | content: "\f13c"; }
1007 |
1008 | .fa-anchor:before {
1009 | content: "\f13d"; }
1010 |
1011 | .fa-unlock-alt:before {
1012 | content: "\f13e"; }
1013 |
1014 | .fa-bullseye:before {
1015 | content: "\f140"; }
1016 |
1017 | .fa-ellipsis-h:before {
1018 | content: "\f141"; }
1019 |
1020 | .fa-ellipsis-v:before {
1021 | content: "\f142"; }
1022 |
1023 | .fa-rss-square:before {
1024 | content: "\f143"; }
1025 |
1026 | .fa-play-circle:before {
1027 | content: "\f144"; }
1028 |
1029 | .fa-ticket:before {
1030 | content: "\f145"; }
1031 |
1032 | .fa-minus-square:before {
1033 | content: "\f146"; }
1034 |
1035 | .fa-minus-square-o:before {
1036 | content: "\f147"; }
1037 |
1038 | .fa-level-up:before {
1039 | content: "\f148"; }
1040 |
1041 | .fa-level-down:before {
1042 | content: "\f149"; }
1043 |
1044 | .fa-check-square:before {
1045 | content: "\f14a"; }
1046 |
1047 | .fa-pencil-square:before {
1048 | content: "\f14b"; }
1049 |
1050 | .fa-external-link-square:before {
1051 | content: "\f14c"; }
1052 |
1053 | .fa-share-square:before {
1054 | content: "\f14d"; }
1055 |
1056 | .fa-compass:before {
1057 | content: "\f14e"; }
1058 |
1059 | .fa-toggle-down:before, .fa-caret-square-o-down:before {
1060 | content: "\f150"; }
1061 |
1062 | .fa-toggle-up:before, .fa-caret-square-o-up:before {
1063 | content: "\f151"; }
1064 |
1065 | .fa-toggle-right:before, .fa-caret-square-o-right:before {
1066 | content: "\f152"; }
1067 |
1068 | .fa-euro:before, .fa-eur:before {
1069 | content: "\f153"; }
1070 |
1071 | .fa-gbp:before {
1072 | content: "\f154"; }
1073 |
1074 | .fa-dollar:before, .fa-usd:before {
1075 | content: "\f155"; }
1076 |
1077 | .fa-rupee:before, .fa-inr:before {
1078 | content: "\f156"; }
1079 |
1080 | .fa-cny:before, .fa-rmb:before, .fa-yen:before, .fa-jpy:before {
1081 | content: "\f157"; }
1082 |
1083 | .fa-ruble:before, .fa-rouble:before, .fa-rub:before {
1084 | content: "\f158"; }
1085 |
1086 | .fa-won:before, .fa-krw:before {
1087 | content: "\f159"; }
1088 |
1089 | .fa-bitcoin:before, .fa-btc:before {
1090 | content: "\f15a"; }
1091 |
1092 | .fa-file:before {
1093 | content: "\f15b"; }
1094 |
1095 | .fa-file-text:before {
1096 | content: "\f15c"; }
1097 |
1098 | .fa-sort-alpha-asc:before {
1099 | content: "\f15d"; }
1100 |
1101 | .fa-sort-alpha-desc:before {
1102 | content: "\f15e"; }
1103 |
1104 | .fa-sort-amount-asc:before {
1105 | content: "\f160"; }
1106 |
1107 | .fa-sort-amount-desc:before {
1108 | content: "\f161"; }
1109 |
1110 | .fa-sort-numeric-asc:before {
1111 | content: "\f162"; }
1112 |
1113 | .fa-sort-numeric-desc:before {
1114 | content: "\f163"; }
1115 |
1116 | .fa-thumbs-up:before {
1117 | content: "\f164"; }
1118 |
1119 | .fa-thumbs-down:before {
1120 | content: "\f165"; }
1121 |
1122 | .fa-youtube-square:before {
1123 | content: "\f166"; }
1124 |
1125 | .fa-youtube:before {
1126 | content: "\f167"; }
1127 |
1128 | .fa-xing:before {
1129 | content: "\f168"; }
1130 |
1131 | .fa-xing-square:before {
1132 | content: "\f169"; }
1133 |
1134 | .fa-youtube-play:before {
1135 | content: "\f16a"; }
1136 |
1137 | .fa-dropbox:before {
1138 | content: "\f16b"; }
1139 |
1140 | .fa-stack-overflow:before {
1141 | content: "\f16c"; }
1142 |
1143 | .fa-instagram:before {
1144 | content: "\f16d"; }
1145 |
1146 | .fa-flickr:before {
1147 | content: "\f16e"; }
1148 |
1149 | .fa-adn:before {
1150 | content: "\f170"; }
1151 |
1152 | .fa-bitbucket:before {
1153 | content: "\f171"; }
1154 |
1155 | .fa-bitbucket-square:before {
1156 | content: "\f172"; }
1157 |
1158 | .fa-tumblr:before {
1159 | content: "\f173"; }
1160 |
1161 | .fa-tumblr-square:before {
1162 | content: "\f174"; }
1163 |
1164 | .fa-long-arrow-down:before {
1165 | content: "\f175"; }
1166 |
1167 | .fa-long-arrow-up:before {
1168 | content: "\f176"; }
1169 |
1170 | .fa-long-arrow-left:before {
1171 | content: "\f177"; }
1172 |
1173 | .fa-long-arrow-right:before {
1174 | content: "\f178"; }
1175 |
1176 | .fa-apple:before {
1177 | content: "\f179"; }
1178 |
1179 | .fa-windows:before {
1180 | content: "\f17a"; }
1181 |
1182 | .fa-android:before {
1183 | content: "\f17b"; }
1184 |
1185 | .fa-linux:before {
1186 | content: "\f17c"; }
1187 |
1188 | .fa-dribbble:before {
1189 | content: "\f17d"; }
1190 |
1191 | .fa-skype:before {
1192 | content: "\f17e"; }
1193 |
1194 | .fa-foursquare:before {
1195 | content: "\f180"; }
1196 |
1197 | .fa-trello:before {
1198 | content: "\f181"; }
1199 |
1200 | .fa-female:before {
1201 | content: "\f182"; }
1202 |
1203 | .fa-male:before {
1204 | content: "\f183"; }
1205 |
1206 | .fa-gittip:before {
1207 | content: "\f184"; }
1208 |
1209 | .fa-sun-o:before {
1210 | content: "\f185"; }
1211 |
1212 | .fa-moon-o:before {
1213 | content: "\f186"; }
1214 |
1215 | .fa-archive:before {
1216 | content: "\f187"; }
1217 |
1218 | .fa-bug:before {
1219 | content: "\f188"; }
1220 |
1221 | .fa-vk:before {
1222 | content: "\f189"; }
1223 |
1224 | .fa-weibo:before {
1225 | content: "\f18a"; }
1226 |
1227 | .fa-renren:before {
1228 | content: "\f18b"; }
1229 |
1230 | .fa-pagelines:before {
1231 | content: "\f18c"; }
1232 |
1233 | .fa-stack-exchange:before {
1234 | content: "\f18d"; }
1235 |
1236 | .fa-arrow-circle-o-right:before {
1237 | content: "\f18e"; }
1238 |
1239 | .fa-arrow-circle-o-left:before {
1240 | content: "\f190"; }
1241 |
1242 | .fa-toggle-left:before, .fa-caret-square-o-left:before {
1243 | content: "\f191"; }
1244 |
1245 | .fa-dot-circle-o:before {
1246 | content: "\f192"; }
1247 |
1248 | .fa-wheelchair:before {
1249 | content: "\f193"; }
1250 |
1251 | .fa-vimeo-square:before {
1252 | content: "\f194"; }
1253 |
1254 | .fa-turkish-lira:before, .fa-try:before {
1255 | content: "\f195"; }
1256 |
1257 | .fa-plus-square-o:before {
1258 | content: "\f196"; }
1259 |
1260 | .fa-space-shuttle:before {
1261 | content: "\f197"; }
1262 |
1263 | .fa-slack:before {
1264 | content: "\f198"; }
1265 |
1266 | .fa-envelope-square:before {
1267 | content: "\f199"; }
1268 |
1269 | .fa-wordpress:before {
1270 | content: "\f19a"; }
1271 |
1272 | .fa-openid:before {
1273 | content: "\f19b"; }
1274 |
1275 | .fa-institution:before, .fa-bank:before, .fa-university:before {
1276 | content: "\f19c"; }
1277 |
1278 | .fa-mortar-board:before, .fa-graduation-cap:before {
1279 | content: "\f19d"; }
1280 |
1281 | .fa-yahoo:before {
1282 | content: "\f19e"; }
1283 |
1284 | .fa-google:before {
1285 | content: "\f1a0"; }
1286 |
1287 | .fa-reddit:before {
1288 | content: "\f1a1"; }
1289 |
1290 | .fa-reddit-square:before {
1291 | content: "\f1a2"; }
1292 |
1293 | .fa-stumbleupon-circle:before {
1294 | content: "\f1a3"; }
1295 |
1296 | .fa-stumbleupon:before {
1297 | content: "\f1a4"; }
1298 |
1299 | .fa-delicious:before {
1300 | content: "\f1a5"; }
1301 |
1302 | .fa-digg:before {
1303 | content: "\f1a6"; }
1304 |
1305 | .fa-pied-piper:before {
1306 | content: "\f1a7"; }
1307 |
1308 | .fa-pied-piper-alt:before {
1309 | content: "\f1a8"; }
1310 |
1311 | .fa-drupal:before {
1312 | content: "\f1a9"; }
1313 |
1314 | .fa-joomla:before {
1315 | content: "\f1aa"; }
1316 |
1317 | .fa-language:before {
1318 | content: "\f1ab"; }
1319 |
1320 | .fa-fax:before {
1321 | content: "\f1ac"; }
1322 |
1323 | .fa-building:before {
1324 | content: "\f1ad"; }
1325 |
1326 | .fa-child:before {
1327 | content: "\f1ae"; }
1328 |
1329 | .fa-paw:before {
1330 | content: "\f1b0"; }
1331 |
1332 | .fa-spoon:before {
1333 | content: "\f1b1"; }
1334 |
1335 | .fa-cube:before {
1336 | content: "\f1b2"; }
1337 |
1338 | .fa-cubes:before {
1339 | content: "\f1b3"; }
1340 |
1341 | .fa-behance:before {
1342 | content: "\f1b4"; }
1343 |
1344 | .fa-behance-square:before {
1345 | content: "\f1b5"; }
1346 |
1347 | .fa-steam:before {
1348 | content: "\f1b6"; }
1349 |
1350 | .fa-steam-square:before {
1351 | content: "\f1b7"; }
1352 |
1353 | .fa-recycle:before {
1354 | content: "\f1b8"; }
1355 |
1356 | .fa-automobile:before, .fa-car:before {
1357 | content: "\f1b9"; }
1358 |
1359 | .fa-cab:before, .fa-taxi:before {
1360 | content: "\f1ba"; }
1361 |
1362 | .fa-tree:before {
1363 | content: "\f1bb"; }
1364 |
1365 | .fa-spotify:before {
1366 | content: "\f1bc"; }
1367 |
1368 | .fa-deviantart:before {
1369 | content: "\f1bd"; }
1370 |
1371 | .fa-soundcloud:before {
1372 | content: "\f1be"; }
1373 |
1374 | .fa-database:before {
1375 | content: "\f1c0"; }
1376 |
1377 | .fa-file-pdf-o:before {
1378 | content: "\f1c1"; }
1379 |
1380 | .fa-file-word-o:before {
1381 | content: "\f1c2"; }
1382 |
1383 | .fa-file-excel-o:before {
1384 | content: "\f1c3"; }
1385 |
1386 | .fa-file-powerpoint-o:before {
1387 | content: "\f1c4"; }
1388 |
1389 | .fa-file-photo-o:before, .fa-file-picture-o:before, .fa-file-image-o:before {
1390 | content: "\f1c5"; }
1391 |
1392 | .fa-file-zip-o:before, .fa-file-archive-o:before {
1393 | content: "\f1c6"; }
1394 |
1395 | .fa-file-sound-o:before, .fa-file-audio-o:before {
1396 | content: "\f1c7"; }
1397 |
1398 | .fa-file-movie-o:before, .fa-file-video-o:before {
1399 | content: "\f1c8"; }
1400 |
1401 | .fa-file-code-o:before {
1402 | content: "\f1c9"; }
1403 |
1404 | .fa-vine:before {
1405 | content: "\f1ca"; }
1406 |
1407 | .fa-codepen:before {
1408 | content: "\f1cb"; }
1409 |
1410 | .fa-jsfiddle:before {
1411 | content: "\f1cc"; }
1412 |
1413 | .fa-life-bouy:before, .fa-life-buoy:before, .fa-life-saver:before, .fa-support:before, .fa-life-ring:before {
1414 | content: "\f1cd"; }
1415 |
1416 | .fa-circle-o-notch:before {
1417 | content: "\f1ce"; }
1418 |
1419 | .fa-ra:before, .fa-rebel:before {
1420 | content: "\f1d0"; }
1421 |
1422 | .fa-ge:before, .fa-empire:before {
1423 | content: "\f1d1"; }
1424 |
1425 | .fa-git-square:before {
1426 | content: "\f1d2"; }
1427 |
1428 | .fa-git:before {
1429 | content: "\f1d3"; }
1430 |
1431 | .fa-hacker-news:before {
1432 | content: "\f1d4"; }
1433 |
1434 | .fa-tencent-weibo:before {
1435 | content: "\f1d5"; }
1436 |
1437 | .fa-qq:before {
1438 | content: "\f1d6"; }
1439 |
1440 | .fa-wechat:before, .fa-weixin:before {
1441 | content: "\f1d7"; }
1442 |
1443 | .fa-send:before, .fa-paper-plane:before {
1444 | content: "\f1d8"; }
1445 |
1446 | .fa-send-o:before, .fa-paper-plane-o:before {
1447 | content: "\f1d9"; }
1448 |
1449 | .fa-history:before {
1450 | content: "\f1da"; }
1451 |
1452 | .fa-circle-thin:before {
1453 | content: "\f1db"; }
1454 |
1455 | .fa-header:before {
1456 | content: "\f1dc"; }
1457 |
1458 | .fa-paragraph:before {
1459 | content: "\f1dd"; }
1460 |
1461 | .fa-sliders:before {
1462 | content: "\f1de"; }
1463 |
1464 | .fa-share-alt:before {
1465 | content: "\f1e0"; }
1466 |
1467 | .fa-share-alt-square:before {
1468 | content: "\f1e1"; }
1469 |
1470 | .fa-bomb:before {
1471 | content: "\f1e2"; }
1472 |
1473 | .fa-soccer-ball-o:before, .fa-futbol-o:before {
1474 | content: "\f1e3"; }
1475 |
1476 | .fa-tty:before {
1477 | content: "\f1e4"; }
1478 |
1479 | .fa-binoculars:before {
1480 | content: "\f1e5"; }
1481 |
1482 | .fa-plug:before {
1483 | content: "\f1e6"; }
1484 |
1485 | .fa-slideshare:before {
1486 | content: "\f1e7"; }
1487 |
1488 | .fa-twitch:before {
1489 | content: "\f1e8"; }
1490 |
1491 | .fa-yelp:before {
1492 | content: "\f1e9"; }
1493 |
1494 | .fa-newspaper-o:before {
1495 | content: "\f1ea"; }
1496 |
1497 | .fa-wifi:before {
1498 | content: "\f1eb"; }
1499 |
1500 | .fa-calculator:before {
1501 | content: "\f1ec"; }
1502 |
1503 | .fa-paypal:before {
1504 | content: "\f1ed"; }
1505 |
1506 | .fa-google-wallet:before {
1507 | content: "\f1ee"; }
1508 |
1509 | .fa-cc-visa:before {
1510 | content: "\f1f0"; }
1511 |
1512 | .fa-cc-mastercard:before {
1513 | content: "\f1f1"; }
1514 |
1515 | .fa-cc-discover:before {
1516 | content: "\f1f2"; }
1517 |
1518 | .fa-cc-amex:before {
1519 | content: "\f1f3"; }
1520 |
1521 | .fa-cc-paypal:before {
1522 | content: "\f1f4"; }
1523 |
1524 | .fa-cc-stripe:before {
1525 | content: "\f1f5"; }
1526 |
1527 | .fa-bell-slash:before {
1528 | content: "\f1f6"; }
1529 |
1530 | .fa-bell-slash-o:before {
1531 | content: "\f1f7"; }
1532 |
1533 | .fa-trash:before {
1534 | content: "\f1f8"; }
1535 |
1536 | .fa-copyright:before {
1537 | content: "\f1f9"; }
1538 |
1539 | .fa-at:before {
1540 | content: "\f1fa"; }
1541 |
1542 | .fa-eyedropper:before {
1543 | content: "\f1fb"; }
1544 |
1545 | .fa-paint-brush:before {
1546 | content: "\f1fc"; }
1547 |
1548 | .fa-birthday-cake:before {
1549 | content: "\f1fd"; }
1550 |
1551 | .fa-area-chart:before {
1552 | content: "\f1fe"; }
1553 |
1554 | .fa-pie-chart:before {
1555 | content: "\f200"; }
1556 |
1557 | .fa-line-chart:before {
1558 | content: "\f201"; }
1559 |
1560 | .fa-lastfm:before {
1561 | content: "\f202"; }
1562 |
1563 | .fa-lastfm-square:before {
1564 | content: "\f203"; }
1565 |
1566 | .fa-toggle-off:before {
1567 | content: "\f204"; }
1568 |
1569 | .fa-toggle-on:before {
1570 | content: "\f205"; }
1571 |
1572 | .fa-bicycle:before {
1573 | content: "\f206"; }
1574 |
1575 | .fa-bus:before {
1576 | content: "\f207"; }
1577 |
1578 | .fa-ioxhost:before {
1579 | content: "\f208"; }
1580 |
1581 | .fa-angellist:before {
1582 | content: "\f209"; }
1583 |
1584 | .fa-cc:before {
1585 | content: "\f20a"; }
1586 |
1587 | .fa-shekel:before, .fa-sheqel:before, .fa-ils:before {
1588 | content: "\f20b"; }
1589 |
1590 | .fa-meanpath:before {
1591 | content: "\f20c"; }
1592 |
1593 | body {
1594 | margin: 0;
1595 | -webkit-font-smoothing: antialiased; }
1596 |
1597 | select {
1598 | color: inherit;
1599 | font: inherit;
1600 | margin: 0; }
1601 |
1602 | ul {
1603 | list-style-type: none;
1604 | padding-left: 2px; }
1605 |
1606 | input {
1607 | outline: 0; }
1608 |
1609 | html, body {
1610 | height: 100%; }
1611 |
1612 | body {
1613 | width: 100%;
1614 | overflow: hidden;
1615 | font-family: "Helvetica Neue", Helvetica, '游ゴシック', YuGothic, "ヒラギノ角ゴ ProN W3", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, sans-serif; }
1616 |
--------------------------------------------------------------------------------
/docs/dev-guide.md:
--------------------------------------------------------------------------------
1 | # 技術スタック
2 |
3 | - typescript: ドメイン層
4 | - coffeescript: UI層
5 | - React: View層
6 | - Overworld: 画面遷移管理
7 | - SVG: 計算量の少ないRect/Circleでだいたいのものを表現
8 | - minimongo: ストレージ層
9 |
--------------------------------------------------------------------------------
/docs/intro.md:
--------------------------------------------------------------------------------
1 | # はじめに
2 |
3 | ## 目標・コンセプト
4 |
5 | - WASD+マウスで全方位に派手に爆発するDiablo風アクション
6 | - PDCAサイクルを楽しめるハックアンドスラッシュ
7 | - カスタマイズ性の高いスキルツリー
8 | - リプレイ性のあるダンジョン
9 | - 技術的に: React+SVGのポテンシャル証明
10 | - おこづかい的に: 投げ銭でちょっとお小遣い入る程度に
11 |
12 | ## シナリオ
13 |
14 | - 薄く
15 | - プレーに関係ない程度に自己満足で書く
16 |
17 | ## 画面
18 |
19 | TODO: あとでモックを書く
20 |
21 | ## 参考
22 |
23 | - http://inishie-dungeon.com/
24 | - [ABA Games](http://www.asahi-net.or.jp/~cs8k-cyu/ "ABA Games")
25 |
--------------------------------------------------------------------------------
/domains/battlefield/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/d866fb556184cc1edffd9d0f1ca205fe1916a7f6/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 |
7 | # Runtime data
8 | pids
9 | *.pid
10 | *.seed
11 |
12 | # Directory for instrumented libs generated by jscoverage/JSCover
13 | lib-cov
14 |
15 | # Coverage directory used by tools like istanbul
16 | coverage
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
29 | node_modules
30 |
31 |
32 | ### https://raw.github.com/github/gitignore/d866fb556184cc1edffd9d0f1ca205fe1916a7f6/Global/OSX.gitignore
33 |
34 | .DS_Store
35 | .AppleDouble
36 | .LSOverride
37 |
38 | # Icon must end with two \r
39 | Icon
40 |
41 | # Thumbnails
42 | ._*
43 |
44 | # Files that might appear on external disk
45 | .Spotlight-V100
46 | .Trashes
47 |
48 | # Directories potentially created on remote AFP share
49 | .AppleDB
50 | .AppleDesktop
51 | Network Trash Folder
52 | Temporary Items
53 | .apdisk
54 | .tmp
55 | public/bundle.js
56 | lib
57 | typings
58 |
--------------------------------------------------------------------------------
/domains/battlefield/gulpfile.coffee:
--------------------------------------------------------------------------------
1 | gulp = require 'gulp'
2 | shell = require 'gulp-shell'
3 | coffee = require 'gulp-coffee'
4 |
5 | gulp.task 'build:ts', shell.task [
6 | 'tsc -m commonjs --target es5 --outDir lib src/entry.ts'
7 | ]
8 |
9 | gulp.task 'build:coffee', ->
10 | gulp.src('./src/**/*.coffee')
11 | .pipe(coffee())
12 | .pipe(gulp.dest('./lib'))
13 |
14 | gulp.task 'watch', ['build'], ->
15 | gulp.watch 'src/**/*.ts', ['build:ts']
16 | gulp.watch 'src/**/*.coffee', ['build:coffee']
17 |
18 | gulp.task 'build', ['clear', 'build:ts', 'build:coffee']
19 | gulp.task 'default', ['build']
20 |
21 | gulp.task 'clear', shell.task [
22 | 'rm -r lib'
23 | ]
24 |
--------------------------------------------------------------------------------
/domains/battlefield/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "battlefield",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "lib/core.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "dependencies": {
15 | "PhysicsJS": "git://github.com/wellcaffeinated/PhysicsJS",
16 | "bluebird": "^2.3.11",
17 | "lodash": "^2.4.1"
18 | },
19 | "devDependencies": {
20 | "coffee-loader": "^0.7.2",
21 | "coffee-script": "^1.8.0",
22 | "gulp": "^3.8.10",
23 | "gulp-shell": "^0.2.11",
24 | "typescript": "git://github.com/microsoft/typescript"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/domains/battlefield/src/behaviours/constant-friction.coffee:
--------------------------------------------------------------------------------
1 | Physics = require 'PhysicsJS'
2 | Physics.behavior 'constant-friction', ( parent ) ->
3 | defaults = {f: 0.00002}
4 | init: ( options ) ->
5 | parent.init.call( this );
6 | @options.defaults( defaults );
7 | @options( options );
8 | @_v = new Physics.vector();
9 |
10 | behave: ( data ) ->
11 | bodies = this.getTargets();
12 | f = 0.0002
13 |
14 | for body in bodies
15 | ax = 0
16 | ay = 0
17 | cof = body.cof
18 |
19 | if body.state.vel.x > 0
20 | ax -= f * cof
21 | else if body.state.vel.x < 0
22 | ax += f * cof
23 |
24 | if body.state.vel.y > 0
25 | ay -= f * cof
26 | else if body.state.vel.y < 0
27 | ay += f * cof
28 |
29 | @_v.clone {x: ax, y: ay}
30 | body.accelerate( @_v );
31 |
--------------------------------------------------------------------------------
/domains/battlefield/src/core.ts:
--------------------------------------------------------------------------------
1 | global.EventEmitter = require('events').EventEmitter;
2 | declare var app: any;
3 | require('./behaviours/constant-friction');
4 |
5 | import Player = require('./entities/battlers/player');
6 | import Stage = require('./stages/stage');
7 | import BattleStage = require('./stages/battle-stage');
8 | import serialize = require('./utils/serialize');
9 |
10 | var instance;
11 | export = Game;
12 | class Game extends EventEmitter {
13 | static instance: Game = null
14 | score: number = 0; // temporary game logic
15 | addScore(n: number) {this.score+=n;}
16 |
17 | player: Player;
18 | inputBuffer: any;
19 | stage: Stage;
20 | fps: number;
21 | running: boolean;
22 |
23 | static getInstance(): Game {
24 | if(this.instance == null)
25 | this.instance = new Game();
26 | return this.instance;
27 | }
28 |
29 | static getActiveStage(): Stage {
30 | return this.getInstance().stage;
31 | }
32 |
33 | constructor(){
34 | super();
35 | global.game = this;
36 | this.stage = null
37 | this.inputBuffer = {
38 | left: false,
39 | right: false,
40 | up: false,
41 | down: false,
42 | mouseLeft: false,
43 | mouseRight: false,
44 | focus: {x: 0, y: 0}
45 | }
46 | this.player = new Player(this.inputBuffer);
47 | this.player.setPosition(100, 100);
48 | this.fps = ~~(1000/60);
49 |
50 | this.on('io:update-focus', (pos) => {
51 | this.updateFocus(pos);
52 | });
53 |
54 | this.on('io:update-key', (key, val) => {
55 | this.updateKey(key, val);
56 | });
57 | }
58 |
59 | updateKey(key, val){
60 | /*if(this.inputBuffer[key] == null)
61 | throw key+'is unknown';*/
62 | this.inputBuffer[key] = val;
63 | }
64 |
65 | updateFocus(pos){
66 | this.inputBuffer.focus.x = pos.x+this.player.x-320;
67 | this.inputBuffer.focus.y = pos.y+this.player.y-240;
68 | }
69 |
70 | createNewStage(){
71 | this.stage = new BattleStage();
72 | this.stage.addChild(this.player);
73 | }
74 |
75 | public serialize(){
76 | return serialize(this, this.stage, this.player);
77 | }
78 |
79 | start(){
80 | if(this.running){
81 | console.info('game already running');
82 | return;
83 | }
84 | this.running = true;
85 |
86 | if(this.stage == null)
87 | throw 'you should initialize stage first';
88 |
89 | var fn = () => {
90 | if(!this.running) return;
91 |
92 | var beforeUpdate = Date.now();
93 | this.stage.update().then(() => {
94 | var emitter = app.getActiveEmitter();
95 | emitter.emit('stage:update', this.serialize());
96 | var afterUpdate = Date.now();
97 | setTimeout(fn, this.fps-(afterUpdate-beforeUpdate));
98 | });
99 | }
100 | fn();
101 | }
102 |
103 | pause(){
104 | this.running = false;
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/battlers/battler.ts:
--------------------------------------------------------------------------------
1 | import Entity = require('../entity');
2 |
3 | export = Battler;
4 | class Battler extends Entity {
5 | static type = 'battler';
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/battlers/enemies/enemy.ts:
--------------------------------------------------------------------------------
1 | import Battler = require('../battler');
2 | import GroupId = require('../../../values/group-id')
3 | import CreateBullet = require('../../../tasks/create-bullet');
4 |
5 | export = Enemy;
6 | class Enemy extends Battler {
7 | static type = 'enemy';
8 |
9 | private cnt: number;
10 | constructor(){
11 | super();
12 | this.life = 1;
13 | this.groupId = GroupId.ENEMY;
14 | this.cnt = 0;
15 | }
16 |
17 | step(){
18 | this.cnt++;
19 | if(this.cnt % 12 === 0) {
20 | this.dir = 360*Math.random();
21 | this.stage.addTask(new CreateBullet(this, this.x, this.y, this.dir));
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/battlers/player.ts:
--------------------------------------------------------------------------------
1 | import Battler = require('./battler');
2 | import CreateBullet = require('../../tasks/create-bullet');
3 | import CreateBulletTrap = require('../../tasks/create-bullet-trap');
4 | import GroupId = require('../../values/group-id')
5 |
6 | declare var game: any;
7 |
8 | export = Player;
9 |
10 | class Player extends Battler {
11 | static type = 'player';
12 |
13 | public focusDir: number = 0;
14 | constructor(public inputBuffer: any){
15 | super();
16 | this.groupId = GroupId.ALLY;
17 | this.life = Infinity;
18 | }
19 |
20 | private updateVelocity(){
21 | var speed = 0.3;
22 | var nx = 0;
23 | var ny = 0;
24 | // update pos
25 | if(this.inputBuffer.left) {
26 | nx = -speed;
27 | } else if(this.inputBuffer.right){
28 | nx = +speed;
29 | }
30 |
31 | if(this.inputBuffer.up) {
32 | ny = -speed;
33 | } else if(this.inputBuffer.down) {
34 | ny = +speed;
35 | }
36 |
37 | this.physicsBody.state.vel.set(nx, ny);
38 | }
39 |
40 | /*public get rad(): number {
41 | var mx = this.inputBuffer.focus.x;
42 | var my = this.inputBuffer.focus.y;
43 | return ~~(Math.atan2(my-this.y, mx-this.x)*180/3.14);
44 | }
45 | public set rad(v) {}*/
46 |
47 | private updateDirection(){
48 | var mx = this.inputBuffer.focus.x;
49 | var my = this.inputBuffer.focus.y;
50 | this.focusDir = ~~(Math.atan2(my-this.y, mx-this.x)*180/3.14);
51 | this.dir = this.focusDir;
52 | }
53 |
54 | private leftCooldown = 0;
55 | private rightCooldown = 0;
56 | private execSkills(){
57 | var mx = this.inputBuffer.focus.x;
58 | var my = this.inputBuffer.focus.y;
59 | if(this.inputBuffer.mouseLeft && this.leftCooldown <= 0) {
60 | this.stage.addTask(new CreateBullet(this, this.x, this.y, this.focusDir));
61 | this.leftCooldown = 3;
62 | } else if(this.leftCooldown > 0) this.leftCooldown--;
63 |
64 | if(this.inputBuffer.mouseRight && this.rightCooldown <= 0) {
65 | this.stage.addTask(new CreateBulletTrap(this, mx, my, this.focusDir));
66 | this.rightCooldown = 60;
67 | } else if(this.rightCooldown > 0) this.rightCooldown--;
68 | }
69 |
70 | step(){
71 | this.physicsBody.sleep(false);
72 | this.updateDirection();
73 | this.updateVelocity();
74 | this.execSkills();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/entity.ts:
--------------------------------------------------------------------------------
1 | var uuid = require('node-uuid');
2 | var _ = require('lodash');
3 | var Physics = require('PhysicsJS');
4 |
5 | global.EventEmitter = require('events').EventEmitter;
6 | import Stage = require('../stages/stage');
7 | import GroupId = require('../values/group-id');
8 | import RemoveEntity = require('../tasks/remove-entity');
9 |
10 | export = Entity;
11 | class Entity extends EventEmitter {
12 | public static type:string = 'entity';
13 |
14 | public id: string;
15 | /*public rad: number;*/
16 | public life: number;
17 | public groupId: GroupId;
18 | public physicsBody: any;
19 | public stage: Stage; // attached by addChild
20 | public willRemove: boolean;
21 |
22 | // Alias to Physics world
23 | public get x(): number {return this.physicsBody.state.pos.x;}
24 | public set x(val) {throw 'Can\t set x'}
25 | public get y(): number {return this.physicsBody.state.pos.y;}
26 | public set y(val) {throw 'Can\t set y'}
27 |
28 | public setPosition(x: number, y: number) {
29 | this.physicsBody.state.pos.set(x, y);
30 | }
31 |
32 | public get vx(): number {return this.physicsBody.state.vel.vx;}
33 | public get vy(): number {return this.physicsBody.state.vel.vy;}
34 | public setVelocity(vx: number, vy: number) {
35 | this.physicsBody.state.vel.set(vx, vy);
36 | }
37 |
38 | public get dir(): number {
39 | return this.physicsBody.state.angular.pos;
40 | }
41 |
42 | public set dir(v: number) {
43 | this.physicsBody.state.angular.pos = v;
44 | this.physicsBody.state.angular.vel = 0;
45 | this.physicsBody.state.angular.acc = 0;
46 | }
47 |
48 | constructor() {
49 | super();
50 | this.stage = null;
51 | this.physicsBody = this.createPhysicsShape();
52 |
53 | this.id = uuid();
54 | this.setPosition(0, 0);
55 | this.life = 1;
56 | this.willRemove = false;
57 | }
58 |
59 | public createPhysicsShape() {
60 | // default shape
61 | return this.physicsBody = Physics.body('circle', {
62 | radius: 10
63 | });
64 | }
65 |
66 | step(stage?: Stage): Promise | any{}
67 |
68 | public isAlive(): boolean { return this.life > 0; }
69 |
70 | public isDead(): boolean { return !this.isAlive();}
71 |
72 | remove(): void {
73 | this.willRemove = true;
74 | this.stage.addTask(new RemoveEntity(this.id));
75 | }
76 |
77 | public dispose(){}
78 |
79 | public onHit(other: Entity){}
80 |
81 | public suffer(damage: number): void {
82 | if(this.isAlive())
83 | this.life -= damage;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/objects/block.ts:
--------------------------------------------------------------------------------
1 | import Entity = require('../entity');
2 | import Battler = require('../battlers/battler');
3 | import GroupId = require('../../values/group-id');
4 | var Physics = require('PhysicsJS');
5 |
6 | export = Block;
7 |
8 | class Block extends Entity {
9 | static type = 'wall';
10 | public size: number;
11 | constructor(size: number) {
12 | this.size = size;
13 | super();
14 | this.life = Infinity;
15 | }
16 |
17 | isAlive() {return true;}
18 |
19 | public createPhysicsShape() {
20 | return Physics.body('rectangle', {
21 | width: this.size,
22 | height: this.size,
23 | treatment: 'static'
24 | });
25 | }
26 |
27 | public step(stage){
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/objects/bullets/bullet.ts:
--------------------------------------------------------------------------------
1 | import Entity = require('../../entity');
2 | import Battler = require('../../battlers/battler');
3 | import GroupId = require('../../../values/group-id');
4 | import Game = require('../../../core');
5 |
6 | var Physics = require('PhysicsJS');
7 |
8 | export = Bullet;
9 | class Bullet extends Entity {
10 | static type = 'bullet';
11 | private cnt: number;
12 | constructor(public owner: Battler) {
13 | super();
14 | this.life = 1;
15 | this.cnt = 0;
16 | this.groupId = owner.groupId;
17 | }
18 |
19 | public createPhysicsShape() {
20 | // default shape
21 | return this.physicsBody = Physics.body('circle', {
22 | radius: 10,
23 | cof: 0,
24 | });
25 | }
26 |
27 | onHit(other: Battler) {
28 | if(other.groupId && this.groupId !== other.groupId){
29 | this.attack(other);
30 | this.remove();
31 | }
32 | }
33 |
34 | private computeAttackPower(){ return 1; }
35 |
36 | public attack(other: Battler) {
37 | // TODO 対象と自分のパラメータからダメージ量を算出
38 | var damage = this.computeAttackPower();
39 | other.suffer(damage);
40 | }
41 |
42 | public step(stage){
43 | this.cnt++
44 | if(this.cnt > 40)
45 | this.remove()
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/objects/polygon.ts:
--------------------------------------------------------------------------------
1 | import Entity = require('../entity');
2 | import GroupId = require('../../values/group-id');
3 | var Physics = require('PhysicsJS');
4 |
5 | export = Polygon;
6 |
7 | class Polygon extends Entity {
8 | static type = 'polygon';
9 | constructor() {
10 | super();
11 | this.life = Infinity;
12 | }
13 |
14 | public createPhysicsShape() {
15 | return Physics.body('convex-polygon', {
16 | vertices: [
17 | { x: 0 , y: -30},
18 | { x: -29, y: -9 },
19 | { x: -18, y: 24 },
20 | { x: 18 , y: 24 },
21 | { x: 29 , y: -9 }
22 | ],
23 | treatment: 'static',
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entities/objects/traps/bullet-trap.ts:
--------------------------------------------------------------------------------
1 | import Entity = require('../../entity');
2 | import Battler = require('../../battlers/battler');
3 | import GroupId = require('../../../values/group-id');
4 | import RemoveEntity = require('../../../tasks/remove-entity');
5 | import CreateBullet = require('../../../tasks/create-bullet');
6 | import Game = require('../../../core');
7 |
8 | declare var game: Game;
9 |
10 | export = BulletTrap;
11 | class BulletTrap extends Battler {
12 | static type = 'bullet';
13 | private cnt: number;
14 | constructor(public owner: Battler) {
15 | super();
16 | this.life = 1;
17 | this.cnt = 0;
18 | this.groupId = owner.groupId;
19 | }
20 |
21 | private fire(){
22 | game.stage.addTask(new CreateBullet(this, this.x, this.y, this.dir));
23 | }
24 |
25 | public step(stage){
26 | this.cnt++;
27 | this.dir += 10;
28 | if(this.cnt%21 === 0) this.fire();
29 | if(this.cnt > 120) this.remove()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/domains/battlefield/src/entry.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import Game = require('./core');
3 |
--------------------------------------------------------------------------------
/domains/battlefield/src/stages/battle-stage.ts:
--------------------------------------------------------------------------------
1 | import Stage = require('./stage');
2 | import DeathChecker = require('../tasks/death-checker');
3 | import SimpleSpawner = require('../tasks/simple-spawner');
4 | import Block = require('../entities/objects/block');
5 | import Polygon = require('../entities/objects/polygon');
6 |
7 | var _ = require('lodash');
8 |
9 | export = BattleStage;
10 |
11 | class BattleStage extends Stage {
12 | loadMap(){
13 | /*_.range(10).forEach((i: number)=>{
14 | var polygon = new Polygon();
15 | polygon.setPosition(100*i, 40)
16 | this.addChild(polygon);
17 | });*/
18 |
19 | var map = [
20 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
21 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
22 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
23 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
24 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
25 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
26 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
27 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
28 | [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
29 | [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1],
30 | [1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1],
31 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
32 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
33 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
34 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
35 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
36 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
37 | [1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
38 | [1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1],
39 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
40 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
41 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
42 | [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
43 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
44 | ];
45 |
46 | var x_size = map[0].length;
47 | var y_size = map.length;
48 |
49 | var size = 30;
50 |
51 | this.width = x_size * size;
52 | this.height = y_size * size;
53 |
54 | this.physicsWorld = this.createWorld(this.width, this.height);
55 |
56 | _.range(y_size).forEach(y => {
57 | _.range(x_size).forEach(x => {
58 | if(map[y][x]) {
59 | var block = new Block(size);
60 | block.setPosition(x*size+size/2, y*size+size/2)
61 | this.addChild(block);
62 | }
63 | });
64 | });
65 |
66 | /*_.range(10).forEach((i: number)=>{
67 | var block = new Block(size);
68 | block.setPosition(i*size, 240)
69 | this.addChild(block);
70 | });*/
71 | }
72 |
73 | constructor(){
74 | super();
75 | this.loadMap();
76 | this.addTask(new DeathChecker());
77 | this.addTask(new SimpleSpawner());
78 |
79 | /*_.range(10).forEach((i: number)=>{
80 | var polygon = new Polygon();
81 | polygon.setPosition(100*i, 40)
82 | this.addChild(polygon);
83 | });
84 |
85 | _.range(10).forEach((i: number)=>{
86 | var block = new Block();
87 | block.setPosition(100*i, 240)
88 | this.addChild(block);
89 | });*/
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/domains/battlefield/src/stages/stage.ts:
--------------------------------------------------------------------------------
1 | global.EventEmitter = require('events').EventEmitter;
2 | var Physics = require('PhysicsJS');
3 |
4 | import Player = require('../entities/battlers/player');
5 | import Entity = require('../entities/entity');
6 | import Task = require('../tasks/task');
7 | import Priority = require('../values/priority');
8 | import TaskRunner = require('./task-runner');
9 |
10 | declare var Physics: any;
11 | var _ = require('lodash');
12 |
13 | export = Stage;
14 | class Stage extends EventEmitter {
15 | public cnt: number;
16 | public entities: Entity[];
17 | /*public taskQueues: Task[];*/
18 | public taskRunner: TaskRunner;
19 | public physicsWorld: any;
20 |
21 | /*public width: number = 1000;
22 | public height: number = 1000;*/
23 | public width;
24 | public height;
25 |
26 | addChild(entity: Entity){
27 | this.entities.push(entity);
28 | entity.stage = this;
29 | this.physicsWorld.add(entity.physicsBody);
30 | }
31 |
32 | public get taskQueueCount(): number { return this.taskRunner.taskQueues.length; }
33 |
34 | constructor(){
35 | super();
36 | this.cnt = 0;
37 | this.entities = [];
38 | this.taskRunner = new TaskRunner();
39 | }
40 |
41 | createWorld(width: number, height: number){
42 | var world = Physics({
43 | integrator: 'verlet',
44 | maxIPF: 16,
45 | timestep: 1000.0 / 60
46 | });
47 |
48 | var viewportBounds = Physics.aabb(0, 0, width, height);
49 | var edgeBounce = Physics.behavior('edge-collision-detection',{
50 | aabb: viewportBounds,
51 | restitution: 0.5,
52 | cof: 0.05
53 | });
54 |
55 | var friction = Physics.behavior('constant-friction');
56 |
57 | world.add([
58 | Physics.behavior('body-impulse-response'),
59 | Physics.behavior('body-collision-detection'),
60 | Physics.behavior('sweep-prune'),
61 | friction,
62 | edgeBounce
63 | ]);
64 |
65 | world.on('collisions:detected', (data) => {
66 | data.collisions.forEach((col)=>{
67 | var bodyA = col.bodyA;
68 | var bodyB = col.bodyB;
69 | var entityA = _.find(this.entities, e => e.physicsBody.uid === bodyA.uid);
70 | var entityB = _.find(this.entities, e => e.physicsBody.uid === bodyB.uid);
71 | //TODO: research why get null object
72 | if(entityA && entityB) {
73 | entityA.onHit(entityB);
74 | entityB.onHit(entityA);
75 | }
76 | });
77 | });
78 |
79 | global.world = world;
80 | return world;
81 | }
82 |
83 | public addTask(task: Task): void{
84 | this.taskRunner.addTask(task);
85 | }
86 |
87 | private updatePhysicsWorld(){
88 | this.physicsWorld.step(Date.now());
89 | }
90 |
91 | public update(): Promise{
92 | this.cnt++;
93 | this.updatePhysicsWorld();
94 |
95 | return new Promise(done => {
96 | Promise.all(this.entities.map(e => e.step(this))).then(() => {
97 | done(this.taskRunner.run(this));
98 | });
99 | });
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/domains/battlefield/src/stages/task-runner.ts:
--------------------------------------------------------------------------------
1 | import Stage = require('./stage');
2 | import Entity = require('../entities/entity');
3 | import Task = require('../tasks/task');
4 | import Priority = require('../values/priority');
5 | var _ = require('lodash');
6 |
7 | export = TaskRunner;
8 | class TaskRunner {
9 | public taskQueues: Task[] = [];
10 |
11 | constructor(){
12 | this.taskQueues = [];
13 | }
14 |
15 | public addTask(task: Task): void{
16 | this.taskQueues.push(task);
17 | }
18 |
19 | private sortTasks(): void {
20 | this.taskQueues = _.sortBy(this.taskQueues, task => {
21 | return task.priority ? task.priority : Priority.LOW
22 | });
23 | }
24 |
25 | private execAllTasks(stage: Stage){
26 | this.sortTasks();
27 | var nextTasks: Task[] = [];
28 | var taskQueues = this.taskQueues.slice();
29 | this.taskQueues = [];
30 |
31 | return new Promise(done => {
32 | (Promise).reduce(taskQueues, (p, task) => {
33 | return new Promise(done=> {
34 | Promise.resolve(task.exec(stage)).then((val)=> {
35 | if(val === true) nextTasks.push(task);
36 | done();
37 | });
38 | });
39 | }, Promise.resolve()).then(()=>{
40 | this.taskQueues = this.taskQueues.concat(nextTasks);
41 | done();
42 | });
43 | });
44 | }
45 |
46 | public run(stage: Stage): Promise{
47 | return new Promise(done => {
48 | this.execAllTasks(stage).then(done);
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/create-bullet-trap.ts:
--------------------------------------------------------------------------------
1 | import Task = require('./task');
2 | import BulletTrap = require('../entities/objects/traps/bullet-trap');
3 | import Battler = require('../entities/battlers/battler')
4 |
5 | export = CreateBulletTrap;
6 |
7 | class CreateBulletTrap implements Task {
8 | constructor(
9 | public owner:Battler,
10 | public x: number, public y: number, public dir: number
11 | ){}
12 |
13 | exec(stage){
14 | var bulletTrap = new BulletTrap(this.owner);
15 | bulletTrap.setPosition(this.x, this.y);
16 | bulletTrap.dir = this.dir;
17 |
18 | stage.addChild(bulletTrap);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/create-bullet.ts:
--------------------------------------------------------------------------------
1 | import Task = require('./task');
2 | import Bullet = require('../entities/objects/bullets/bullet');
3 | import Battler = require('../entities/battlers/battler')
4 |
5 | export = CreateBullet;
6 |
7 | class CreateBullet implements Task {
8 | constructor(
9 | public owner:Battler,
10 | public x: number, public y: number, public dir: number
11 | ){
12 | }
13 |
14 | exec(stage){
15 | var bullet = new Bullet(this.owner);
16 | bullet.setPosition(this.x, this.y)
17 | bullet.dir = this.dir;
18 | stage.addChild(bullet);
19 |
20 | var speed = 0.5;
21 | var rad = this.dir/180*3.14;
22 | var vx = Math.cos(rad) * speed;
23 | var vy = Math.sin(rad) * speed;
24 | bullet.setVelocity(vx, vy);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/death-checker.ts:
--------------------------------------------------------------------------------
1 | import Task = require('./task');
2 | import RemoveEntity = require('./remove-entity');
3 | import Priority = require('../values/priority');
4 | import GroupId = require('../values/group-id');
5 | import Game = require('../core');
6 | declare var game: Game;
7 | var _ = require('lodash');
8 |
9 | // Sweep all dead entities
10 | // Always active if it exists.
11 | // TODO: Giving exp and gold is here.
12 | export = DeathChecker;
13 | class DeathChecker implements Task {
14 | public get priority(): Priority {return Priority.DEATH_CHECKER;}
15 | exec(stage){
16 | // calc point
17 | var deadEntities = stage.entities.filter(
18 | e => e.groupId === GroupId.ENEMY && e.isDead()
19 | );
20 | game.addScore(deadEntities.length);
21 |
22 | // TODO: work around for miss about death
23 | /*var deadPhysicsIds = deadEntities.map(e => e.physicsBody.uid);
24 | stage.physicsWorld.getBodies().forEach(body => {
25 | if(_.include(deadPhysicsIds, body.uid)){
26 | stage.physicsWorld.remove(body);
27 | }
28 | });
29 | stage.entities = stage.entities
30 | .filter(e => e.isAlive());*/
31 |
32 | stage.entities
33 | .filter(e => e.isDead())
34 | .forEach(e => e.remove());
35 |
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/remove-entity.ts:
--------------------------------------------------------------------------------
1 | import Task = require('./task');
2 | import Priority = require('../values/priority');
3 | export = RemoveEntity;
4 | var _ = require('lodash');
5 |
6 | class RemoveEntity implements Task {
7 | constructor(public entityId: string){}
8 | public get priority(): Priority {return Priority.REMOVE_ENTITIES;}
9 | exec(stage){
10 | var target = _.find(stage.entities, e => e.id === this.entityId);
11 | if(target) stage.physicsWorld.remove(target.physicsBody);
12 | stage.entities = stage.entities.filter(e => e.id !== this.entityId);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/simple-spawner.ts:
--------------------------------------------------------------------------------
1 | import Task = require('./task');
2 | import Priority = require('../values/priority');
3 | import GroupId = require('../values/group-id');
4 | import Enemy = require('../entities/battlers/enemies/enemy');
5 | var _ = require('lodash');
6 |
7 | export = SimpleSpawner;
8 | class SimpleSpawner implements Task {
9 | public get priority(): Priority {return Priority.SPAWN;}
10 | exec(stage){
11 | var enemyCount = stage.entities.filter(e => e.groupId === GroupId.ENEMY).length;
12 | if(enemyCount < 3) {
13 | _.range(5).forEach(() => {
14 | var enemy = new Enemy();
15 | enemy.setPosition(
16 | Math.random() * stage.width,
17 | Math.random() * stage.height
18 | );
19 | stage.addChild(enemy);
20 | });
21 | }
22 | return true;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/domains/battlefield/src/tasks/task.ts:
--------------------------------------------------------------------------------
1 | import Stage = require('../stages/stage');
2 | import Priority = require('../values/priority')
3 |
4 | interface Task {
5 | priority?: Priority;
6 | exec(stage?: Stage): void | boolean | Promise | Promise;
7 | }
8 |
9 | export = Task;
10 |
--------------------------------------------------------------------------------
/domains/battlefield/src/types.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare class EventEmitter {
4 | on(name: string, fn: Function): void;
5 | off(name: string, fn?: Function): void;
6 | emit(name: string, ...args: any[]): void;
7 | }
8 |
--------------------------------------------------------------------------------
/domains/battlefield/src/utils/serialize.ts:
--------------------------------------------------------------------------------
1 | import Stage = require('../stages/stage');
2 | import Entity = require('../entities/entity');
3 |
4 | function formatPhysicsBody(body: any){
5 | var obj:any = {
6 | name: body.name,
7 | pos: body.state.pos.values(),
8 | angle: body.state.angular.pos
9 | }
10 | if(body.name === 'circle'){
11 | obj.radius = body.radius;
12 | } else if(body.name === 'rectangle'){
13 | obj.width = body.width;
14 | obj.height = body.height;
15 | obj.x = body.x;
16 | obj.y = body.y;
17 | } else if(body.name === 'convex-polygon'){
18 | obj.vertices = body.geometry.vertices;
19 | }
20 | return obj;
21 | }
22 |
23 | function serializeEntity(entity: Entity){
24 | return {
25 | id: entity.id,
26 | groupId: entity.groupId,
27 | x: entity.x, y: entity.y,
28 | dir: entity.dir,
29 | body: formatPhysicsBody(entity.physicsBody),
30 | type: (entity.constructor).type
31 | };
32 | }
33 |
34 | //TODO: remove player camera controller from this function
35 | function serialize(game, stage: Stage, target: Entity){
36 | var cx = target.x-320;
37 | var cy = target.y-240;
38 | return {
39 | cx: cx,
40 | cy: cy,
41 | cnt: stage.cnt,
42 | stage: {
43 | width: stage.width,
44 | height: stage.height
45 | },
46 | entities: stage.entities.map(e => serializeEntity(e)),
47 | focus: game.inputBuffer.focus,
48 | /*running: game.running*/
49 | /*bodies: formatBodies,*/
50 | };
51 | }
52 | export = serialize;
53 |
--------------------------------------------------------------------------------
/domains/battlefield/src/values/group-id.ts:
--------------------------------------------------------------------------------
1 | enum GroupId {
2 | ALLY = 1,
3 | ENEMY = 2,
4 | UNDEFINED = 99,
5 | }
6 |
7 | export = GroupId;
8 |
--------------------------------------------------------------------------------
/domains/battlefield/src/values/priority.ts:
--------------------------------------------------------------------------------
1 | enum Priority {
2 | // For System Event
3 | HIGH = 102,
4 | NORMAL = 101,
5 | LOW = 100,
6 |
7 | DEATH_CHECKER = 10,
8 | REMOVE_ENTITIES = 9,
9 | SPAWN = 5,
10 | }
11 |
12 | export = Priority;
13 |
--------------------------------------------------------------------------------
/domains/battlefield/test/stages/stage-test.coffee:
--------------------------------------------------------------------------------
1 | Stage = require '../../../lib/game/stages/stage'
2 | sinon = require 'sinon'
3 |
4 | describe 'Stage', ->
5 | it 'should exec queues and consume', ->
6 | stage = new Stage
7 |
8 | spy1 = sinon.spy()
9 | spy2 = sinon.spy()
10 |
11 | task1 = exec: -> new Promise (done) ->
12 | setTimeout ->
13 | spy1()
14 | done()
15 | , 0
16 |
17 | task2 = exec: -> new Promise (done) ->
18 | setTimeout ->
19 | spy1()
20 | spy2()
21 | done()
22 | , 16
23 |
24 | stage.addTask(task1);
25 | stage.addTask(task2);
26 | equal stage.taskQueueCount, 2
27 | new Promise (done) ->
28 | stage.update().then ->
29 | ok spy1.calledTwice
30 | ok spy2.calledOnce
31 | equal stage.taskQueueCount, 0
32 | done()
33 |
34 | it 'should save task to next if it returns with true', ->
35 | stage = new Stage
36 | spy1 = sinon.spy()
37 | task1 = exec: -> new Promise (done) ->
38 | setTimeout ->
39 | spy1()
40 | done(true)
41 |
42 | stage.addTask(task1);
43 | equal stage.taskQueueCount, 1
44 |
45 | new Promise (done) ->
46 | stage.update().then ->
47 | equal stage.taskQueueCount, 1
48 | ok spy1.calledOnce
49 |
50 | stage.update().then ->
51 | equal stage.taskQueueCount, 1
52 | ok spy1.calledTwice
53 | done()
54 |
55 | it 'should do task by priority', (done) ->
56 | stage = new Stage
57 | spy1 = sinon.spy()
58 | spy2 = sinon.spy()
59 |
60 | task1 =
61 | exec: ->
62 | ok spy2.called
63 | spy1()
64 | done()
65 | priority: 0
66 |
67 | task2 =
68 | exec: ->
69 | ok not spy1.called
70 | spy2()
71 | priority: 1
72 |
73 | stage.addTask(task1);
74 | stage.addTask(task2);
75 |
76 | stage.update()
77 |
--------------------------------------------------------------------------------
/domains/map-editor/debug.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/domains/map-editor/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mizchi-sandbox/ar2/308fe2096084b2cdf1aa03fcc7b609d62c651fc9/domains/map-editor/index.js
--------------------------------------------------------------------------------
/domains/map-editor/src/component/actions.coffee:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | }
3 |
--------------------------------------------------------------------------------
/domains/map-editor/src/component/index.coffee:
--------------------------------------------------------------------------------
1 | extend = require 'extend'
2 | template = require './template.jade'
3 |
4 | module.exports = React.createClass
5 | mixins: [Overworld.mixinFor(-> app), require './actions']
6 |
7 | render: ->
8 | template extend {}, @, @props, @state
9 |
--------------------------------------------------------------------------------
/domains/map-editor/src/component/template.jade:
--------------------------------------------------------------------------------
1 | mixin physicsBody(body)
2 | - var x = body.pos.x;
3 | - var y = body.pos.y;
4 | - var med = body.angle;
5 | g(
6 | key= body.uid
7 | transform= 'translate('+x+','+y+') rotate(' + med + ')'
8 | )
9 | if body.name === "circle"
10 | circle(
11 | cx=0
12 | cy=0
13 | r= body.radius
14 | fill= 'none',
15 | stroke= 'green'
16 | )
17 | else if body.name === 'rectangle'
18 | rect(
19 | width=body.width
20 | height=body.height
21 | x=-body.width/2
22 | y=-body.height/2
23 | fill='green'
24 | )
25 | else if body.name === 'convex-polygon'
26 | - var vs = body.vertices;
27 | - var points = vs.map(function(v){return v.x+','+v.y;}).join(' ')
28 | polygon(
29 | points = points
30 | fill= 'green'
31 | )
32 |
33 | mixin entityAvatar(entity)
34 | //- id, type, x, y, rad
35 | - var baseColor = entity.groupId === 1 ? 'white' : 'red';
36 | g(
37 | transform='translate(' + entity.x + ', ' + entity.y + ') rotate(' + (entity.dir+90) + ')'
38 | key=entity.id
39 | id=entity.id
40 | )
41 | if entity.type === 'player'
42 | circle(cx=0 cy=0 r=15 fill=baseColor stroke='black')
43 | line(
44 | x1=0 y1=0
45 | x2=0 y2=-15
46 | stroke='black')
47 | else if entity.type === 'enemy'
48 | circle(cx=0 cy=0 r=15 fill=baseColor stroke='black')
49 | line(
50 | x1=0 y1=0
51 | x2=0 y2=-15
52 | stroke='black')
53 | else if entity.type === 'wall'
54 | rect(
55 | width=entity.body.width
56 | height=entity.body.height
57 | x=-entity.body.width/2
58 | y=-entity.body.height/2
59 | fill='black'
60 | )
61 | else if entity.type === 'polygon'
62 | - var vs = entity.body.vertices;
63 | - var points = vs.map(function(v){return v.x+','+v.y;}).join(' ')
64 | polygon(
65 | points = points
66 | fill='black'
67 | )
68 | else
69 | //- maybe bullet now
70 | circle(cx=0 cy=0 r=5 fill=baseColor stroke='green')
71 | line( x1=0 y1=0
72 | x2=0 y2=-5
73 | stroke='white')
74 |
75 | mixin focus(x, y)
76 | g(
77 | transform='translate(' + x + ', ' + y + ')'
78 | )
79 | circle(cx=0 cy=0 r=10 fill='transparent' stroke='blue')
80 |
81 | svg(
82 | key='main'
83 | className='main'
84 | width=640 height=480
85 | onMouseMove=onMouseMove
86 | onMouseDown=onMouseDown
87 | onMouseUp=onMouseUp
88 | onContextMenu=onContextMenu
89 | )
90 | rect(
91 | x=0 y=0
92 | width=640 height=480
93 | fill='wheat'
94 | key='bg'
95 | )
96 | g(
97 | transform='translate(' + -cx + ', ' + -cy + ')'
98 | key='field'
99 | )
100 | //- background
101 | rect(
102 | x=0 y=0
103 | width=stage.width height=stage.height
104 | fill='gray'
105 | )
106 |
107 | //- entities
108 | for entity in entities
109 | +entityAvatar(entity)
110 | +focus(focus.x, focus.y)
111 |
112 | //- g(
113 | //- transform='translate(' + -cx + ', ' + -cy + ')'
114 | //- key='physics'
115 | //- )
116 | //- for body in bodies
117 | //- +physicsBody(body)
118 |
--------------------------------------------------------------------------------
/domains/map-editor/src/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mizchi-sandbox/ar2/308fe2096084b2cdf1aa03fcc7b609d62c651fc9/domains/map-editor/src/index.js
--------------------------------------------------------------------------------
/domains/map-editor/src/scene/aggregator.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | initState: (props) -> {}
3 | aggregate: (props, state) -> {}
4 |
--------------------------------------------------------------------------------
/domains/map-editor/src/scene/index.coffee:
--------------------------------------------------------------------------------
1 | Overworld = require 'overworld'
2 | module.exports =
3 | class extends Overworld.World
4 | @component : require '../component'
5 | @aggregator: require './aggregator'
6 | @subscriber: require './subscriber'
7 |
--------------------------------------------------------------------------------
/domains/map-editor/src/scene/subscriber.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (subscribe) ->
2 | subscribe 'menu:close', (context) -> (args...) ->
3 | app.popWorld()
4 |
--------------------------------------------------------------------------------
/dtsm.json:
--------------------------------------------------------------------------------
1 | {
2 | "repos": [
3 | {
4 | "url": "https://github.com/borisyankov/DefinitelyTyped.git",
5 | "ref": "master"
6 | }
7 | ],
8 | "path": "typings",
9 | "bundle": "typings/bundle.d.ts",
10 | "dependencies": {
11 | "node/node.d.ts": {
12 | "ref": "ca32947b75a2b1203779dac7154ffbc232746e4d"
13 | },
14 | "es6-promise/es6-promise.d.ts": {
15 | "ref": "ca32947b75a2b1203779dac7154ffbc232746e4d"
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/gulpfile.coffee:
--------------------------------------------------------------------------------
1 | gulp = require 'gulp'
2 | coffee = require 'gulp-coffee'
3 | webpack = require 'gulp-webpack'
4 | shell = require 'gulp-shell'
5 | sass = require 'gulp-sass'
6 |
7 | webpackConfig = require './webpack.config'
8 |
9 | gulp.task 'build:coffee', ->
10 | gulp.src('./src/**/*.coffee')
11 | .pipe(coffee())
12 | .pipe(gulp.dest('./lib'))
13 |
14 | gulp.task 'build:ts', shell.task [
15 | 'tsc -m commonjs --target es5 --outDir lib src/entry.ts'
16 | ]
17 |
18 | gulp.task 'webpack', ->
19 | gulp.src('lib/index.js')
20 | .pipe(webpack(webpackConfig))
21 | .pipe(gulp.dest('.'))
22 |
23 | gulp.task 'build:jade', ->
24 | gulp.src('src/**/*.jade')
25 | .pipe(gulp.dest('lib'))
26 |
27 | gulp.task 'build:css', ->
28 | gulp
29 | .src('styles/style.scss')
30 | .pipe(sass())
31 | .pipe(gulp.dest('public'))
32 |
33 | ## Watch tasks
34 | gulp.task 'watch', ['build'], ->
35 | gulp.watch 'src/**/*.coffee', ['build:coffee']
36 | # gulp.watch 'src/**/*.ts', ['build:ts']
37 | gulp.watch 'src/**/*.jade', ['build:jade']
38 | gulp.watch 'lib/**/*', ['webpack']
39 | gulp.watch 'domains/battlefield/lib/*.js', ['webpack']
40 | gulp.watch 'styles/**/*.scss', ['build:css']
41 |
42 | gulp.task 'build', ['clear', 'build:coffee', 'build:jade']
43 | gulp.task 'default', ['build']
44 |
45 | gulp.task 'clear', shell.task [
46 | 'rm -r lib'
47 | ]
48 |
49 | ## Deploy tasks
50 | gulp.task 'prepare-deploy', ->
51 | gulp.src('public/**/*')
52 | .pipe(gulp.dest('deploy'))
53 |
54 | ## Deploy tasks
55 | gulp.task 'deploy', ['prepare-deploy'], shell.task [
56 | 'git subtree push --prefix deploy/ origin gh-pages'
57 | ]
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ar2",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha --compilers coffee:coffee-script/register --recursive -t 200 --reporter spec"
8 | },
9 | "author": "",
10 | "license": "MIT",
11 | "dependencies": {
12 | "bluebird": "^2.3.11",
13 | "change-case": "^2.1.6",
14 | "clone": "^0.2.0",
15 | "extend": "^2.0.0",
16 | "global": "^4.3.0",
17 | "gulp": "^3.8.10",
18 | "lodash": "^2.4.1",
19 | "minimongo": "^3.2.5",
20 | "mousetrap": "^1.4.6",
21 | "node-uuid": "^1.4.2",
22 | "overworld": "0.0.2",
23 | "react": "^0.12.1",
24 | "react-jade": "2.3.0",
25 | "sinon": "^1.12.2"
26 | },
27 | "devDependencies": {
28 | "coffee-loader": "^0.7.2",
29 | "coffee-script": "^1.8.0",
30 | "dtsm": "^0.2.0",
31 | "font-awesome": "^4.2.0",
32 | "gulp-coffee": "^2.2.0",
33 | "gulp-sass": "^1.2.4",
34 | "gulp-shell": "^0.2.11",
35 | "gulp-webpack": "^1.1.2",
36 | "react-jade-loader": "mizchi/react-jade-loader#24b5cc8f34376c8d8c11ae96425b44de0d57f06c",
37 | "webpack": "^1.4.13"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AR
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/scripts/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # battlefield
4 | cd domains/battlefield
5 | npm install
6 | gulp
7 |
8 | # here
9 | cd ../..
10 | ./node_modules/.bin/dtsm install
11 | npm install
12 | ./node_modules/.bin/gulp build
13 | ./node_modules/.bin/gulp webpack
14 |
--------------------------------------------------------------------------------
/scripts/watch:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env coffee
2 |
3 | {spawn} = require 'child_process'
4 |
5 | startWatch = (cwd) ->
6 | name = cwd.replace process.cwd(), ''
7 | watchRoot = spawn('gulp', ['watch'], cwd: cwd)
8 | watchRoot.stdout.on 'data', (data) ->
9 | console.log name + ':' + data
10 |
11 | watchRoot.stderr.on 'data', (data) ->
12 | console.log name + ':' + data
13 |
14 | watchRoot.on 'close', (code) ->
15 | console.log name + ':' + data
16 |
17 | startWatch process.cwd()
18 | startWatch process.cwd() + '/domains/battlefield'
19 |
--------------------------------------------------------------------------------
/src/components/field/actions.coffee:
--------------------------------------------------------------------------------
1 | getMainRect = do ->
2 | main = document.querySelector '.main'
3 | rect = null
4 | ->
5 | main ?= document.querySelector '.main'
6 | rect ?= main.getBoundingClientRect()
7 |
8 | MouseButtons =
9 | 0: 'mouseLeft'
10 | 2: 'mouseRight'
11 |
12 | module.exports =
13 | onMouseMove: (e) ->
14 | rect = getMainRect()
15 | x = e.clientX - rect.left
16 | y = e.clientY - rect.top
17 | game?.emit 'io:update-focus', {x, y}
18 | return
19 |
20 | onMouseDown: (e) ->
21 | game.emit 'io:update-key', MouseButtons[e.button], true
22 | e.stopPropagation()
23 | e.preventDefault()
24 | return
25 |
26 | onMouseUp: (e) ->
27 | game.emit 'io:update-key', MouseButtons[e.button], false
28 | e.stopPropagation()
29 | e.preventDefault()
30 | return
31 |
32 | onContextMenu: (e) ->
33 | e.stopPropagation()
34 | e.preventDefault()
35 | return
36 |
37 | onClickStop: (e) ->
38 | @emit 'field:stop'
39 |
40 | onClickRestart: (e) ->
41 | @emit 'field:restart'
42 |
--------------------------------------------------------------------------------
/src/components/field/index.coffee:
--------------------------------------------------------------------------------
1 | extend = require 'extend'
2 | template = require './template.jade'
3 |
4 | module.exports = React.createClass
5 | mixins: [Overworld.mixinFor(-> app), require './actions']
6 |
7 | render: ->
8 | template extend {}, @, @props, @state
9 |
--------------------------------------------------------------------------------
/src/components/field/template.jade:
--------------------------------------------------------------------------------
1 | mixin physicsBody(body)
2 | - var x = body.pos.x;
3 | - var y = body.pos.y;
4 | - var med = body.angle;
5 | g(
6 | key= body.uid
7 | transform= 'translate('+x+','+y+') rotate(' + med + ')'
8 | )
9 | if body.name === "circle"
10 | circle(
11 | cx=0
12 | cy=0
13 | r= body.radius
14 | fill= 'none',
15 | stroke= 'green'
16 | )
17 | else if body.name === 'rectangle'
18 | rect(
19 | width=body.width
20 | height=body.height
21 | x=-body.width/2
22 | y=-body.height/2
23 | fill='green'
24 | )
25 | else if body.name === 'convex-polygon'
26 | - var vs = body.vertices;
27 | - var points = vs.map(function(v){return v.x+','+v.y;}).join(' ')
28 | polygon(
29 | points = points
30 | fill= 'green'
31 | )
32 |
33 | mixin entityAvatar(entity)
34 | //- id, type, x, y, rad
35 | - var baseColor = entity.groupId === 1 ? 'white' : 'red';
36 | g(
37 | transform='translate(' + entity.x + ', ' + entity.y + ') rotate(' + (entity.dir+90) + ')'
38 | key=entity.id
39 | id=entity.id
40 | )
41 | if entity.type === 'player'
42 | circle(cx=0 cy=0 r=15 fill=baseColor stroke='black')
43 | line(
44 | x1=0 y1=0
45 | x2=0 y2=-15
46 | stroke='black')
47 | else if entity.type === 'enemy'
48 | circle(cx=0 cy=0 r=15 fill=baseColor stroke='black')
49 | line(
50 | x1=0 y1=0
51 | x2=0 y2=-15
52 | stroke='black')
53 | else if entity.type === 'wall'
54 | rect(
55 | width=entity.body.width
56 | height=entity.body.height
57 | x=-entity.body.width/2
58 | y=-entity.body.height/2
59 | fill='black'
60 | )
61 | else if entity.type === 'polygon'
62 | - var vs = entity.body.vertices;
63 | - var points = vs.map(function(v){return v.x+','+v.y;}).join(' ')
64 | polygon(
65 | points = points
66 | fill='black'
67 | )
68 | else
69 | //- maybe bullet now
70 | circle(cx=0 cy=0 r=5 fill=baseColor stroke='green')
71 | line( x1=0 y1=0
72 | x2=0 y2=-5
73 | stroke='white')
74 |
75 | mixin focus(x, y)
76 | g(
77 | transform='translate(' + x + ', ' + y + ')'
78 | )
79 | circle(cx=0 cy=0 r=10 fill='transparent' stroke='blue')
80 |
81 | svg(
82 | key='main'
83 | className='main'
84 | width=640 height=480
85 | onMouseMove=onMouseMove
86 | onMouseDown=onMouseDown
87 | onMouseUp=onMouseUp
88 | onContextMenu=onContextMenu
89 | )
90 | rect(
91 | x=0 y=0
92 | width=640 height=480
93 | fill='wheat'
94 | key='bg'
95 | )
96 | g(
97 | transform='translate(' + -cx + ', ' + -cy + ')'
98 | key='field'
99 | )
100 | //- background
101 | rect(
102 | x=0 y=0
103 | width=stage.width height=stage.height
104 | fill='gray'
105 | )
106 | //- entities
107 | for entity in entities
108 | +entityAvatar(entity)
109 | +focus(focus.x, focus.y)
110 |
111 | //- g(
112 | //- transform='translate(' + -cx + ', ' + -cy + ')'
113 | //- key='physics'
114 | //- )
115 | //- for body in bodies
116 | //- +physicsBody(body)
117 |
118 | .controll
119 | if paused
120 | button(onClick=onClickRestart) restart
121 | else
122 | button(onClick=onClickStop) stop
123 |
--------------------------------------------------------------------------------
/src/components/menu/actions.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | onClickBack: ->
3 | @emit 'menu:close', {}
4 |
--------------------------------------------------------------------------------
/src/components/menu/index.coffee:
--------------------------------------------------------------------------------
1 | template = require './template.jade'
2 | actions = require './actions'
3 | extend = require 'extend'
4 |
5 | module.exports = React.createClass
6 | mixins: [Overworld.mixinFor(-> app), actions]
7 | render: ->
8 | template extend {}, @, @props, @state
9 |
--------------------------------------------------------------------------------
/src/components/menu/template.jade:
--------------------------------------------------------------------------------
1 | .menu
2 | h1 menu
3 | button(onClick=onClickBack) Back
4 |
--------------------------------------------------------------------------------
/src/components/opening/actions.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | onClick: ->
3 | app.pushWorld 'field', {}
4 |
--------------------------------------------------------------------------------
/src/components/opening/index.coffee:
--------------------------------------------------------------------------------
1 | template = require './template.jade'
2 | actions = require './actions'
3 | extend = require 'extend'
4 |
5 | module.exports = React.createClass
6 | mixins: [Overworld.mixinFor(-> app), actions]
7 | render: ->
8 | template extend {}, @, @props, @state
9 |
--------------------------------------------------------------------------------
/src/components/opening/template.jade:
--------------------------------------------------------------------------------
1 | .opening
2 | h1 Actrogue2
3 |
4 | p ~ under technical testings
5 |
6 | button(onClick=onClick) Game Start
7 |
8 | h2 操作方法
9 | p
10 | dl
11 | dt WASD or ↑←↓
12 | dd プレイヤーの移動
13 | dt マウス
14 | dd 照準の移動
15 | dt 左クリック
16 | dd 発射
17 | dt 右クリック
18 | dd 弾を発射するトラップ
19 |
--------------------------------------------------------------------------------
/src/index.coffee:
--------------------------------------------------------------------------------
1 | # requires
2 | window.app = null
3 | require './setup'
4 | require './router'
5 |
6 | Game = require '../domains/battlefield'
7 | window.game = Game.getInstance()
8 |
9 | window.addEventListener 'DOMContentLoaded', ->
10 | app.mount(document.body)
11 | app.transition('opening', {})
12 |
--------------------------------------------------------------------------------
/src/router.coffee:
--------------------------------------------------------------------------------
1 | app.link 'field', require './scenes/field'
2 | app.link 'opening', require './scenes/opening'
3 | app.link 'menu', require './scenes/menu'
4 |
--------------------------------------------------------------------------------
/src/scenes/field/aggregator.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | initState: (props) ->
3 | entities: []
4 | cx: 0
5 | cy: 0
6 | score: 0
7 | focus:
8 | x: -1000
9 | y: -1000
10 | stage:
11 | width: 0
12 | height: 0
13 | bodies: []
14 | paused: false
15 |
16 | aggregate: (props, state) ->
17 | state
18 |
--------------------------------------------------------------------------------
/src/scenes/field/index.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | class Field extends Overworld.World
3 | @component : require '../../components/field'
4 | @aggregator: require './aggregator'
5 | @subscriber: require './subscriber'
6 |
--------------------------------------------------------------------------------
/src/scenes/field/subscriber.coffee:
--------------------------------------------------------------------------------
1 | clone = require 'clone'
2 |
3 | module.exports = (subscribe) ->
4 | subscribe 'stage:update', (context) -> (serialized) ->
5 | context.update(serialized)
6 |
7 | subscribe 'lifecycle:created', (context) -> () ->
8 | game.createNewStage()
9 | game.start()
10 |
11 | subscribe 'lifecycle:paused', (context) -> () ->
12 | game.pause()
13 |
14 | subscribe 'lifecycle:resumed', (context) -> () ->
15 | game.start()
16 |
17 | subscribe 'io:open-menu', (context) -> (serialized) ->
18 | console.log 'open menu'
19 | app.pushWorld 'menu', {}
20 |
21 | subscribe 'field:stop', (context) -> (serialized) ->
22 | game.pause()
23 | s = clone(context.state)
24 | s.paused = true
25 | context.update(s)
26 |
27 | subscribe 'field:restart', (context) -> (serialized) ->
28 | game.start()
29 | s = clone(context.state)
30 | s.paused = false
31 | context.update(s)
32 |
--------------------------------------------------------------------------------
/src/scenes/menu/aggregator.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | initState: (props) -> {}
3 | aggregate: (props, state) -> {}
4 |
--------------------------------------------------------------------------------
/src/scenes/menu/index.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | class extends Overworld.World
3 | @component : require '../../components/menu'
4 | @aggregator: require './aggregator'
5 | @subscriber: require './subscriber'
6 |
--------------------------------------------------------------------------------
/src/scenes/menu/subscriber.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (subscribe) ->
2 | subscribe 'menu:close', (context) -> (args...) ->
3 | app.popWorld()
4 |
--------------------------------------------------------------------------------
/src/scenes/opening/aggregator.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | initState: (props) -> {}
3 | aggregate: (props, state) -> {}
4 |
--------------------------------------------------------------------------------
/src/scenes/opening/index.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | class extends Overworld.World
3 | @component : require '../../components/opening'
4 | @aggregator: require './aggregator'
5 | @subscriber: require './subscriber'
6 |
--------------------------------------------------------------------------------
/src/scenes/opening/subscriber.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (subscribe) ->
2 | subscribe 'opening:update', (context) -> (args...) ->
3 | context.update {}
4 |
--------------------------------------------------------------------------------
/src/setup.coffee:
--------------------------------------------------------------------------------
1 | # requires
2 | global = require 'global'
3 | global.Promise = require 'bluebird'
4 | global.React = require 'react'
5 | global.Overworld = require 'overworld'
6 | Overworld.setReact React
7 |
8 | global.app = new Overworld.Portal
9 |
10 | KeyMap =
11 | 37: 'left'
12 | 38: 'up'
13 | 39: 'right'
14 | 40: 'down'
15 | 87: 'w'
16 | 65: 'a'
17 | 83: 's'
18 | 68: 'd'
19 | 73: 'i'
20 |
21 | window.addEventListener 'keydown', (e) ->
22 | # console.log e.keyCode
23 | emitter = app.getActiveEmitter()
24 | return unless game
25 | switch KeyMap[e.keyCode]
26 | when 'left' , 'a' then game.emit 'io:update-key', 'left', true
27 | when 'up' , 'w' then game.emit 'io:update-key', 'up', true
28 | when 'right', 'd' then game.emit 'io:update-key', 'right',true
29 | when 'down' , 's' then game.emit 'io:update-key', 'down', true
30 | when 'i' then emitter.emit 'io:open-menu'
31 |
32 | window.addEventListener 'keyup', (e) ->
33 | return unless game
34 | switch KeyMap[e.keyCode]
35 | when 'left' , 'a' then game.emit 'io:update-key', 'left', false
36 | when 'up' , 'w' then game.emit 'io:update-key', 'up', false
37 | when 'right', 'd' then game.emit 'io:update-key', 'right',false
38 | when 'down' , 's' then game.emit 'io:update-key', 'down', false
39 |
--------------------------------------------------------------------------------
/styles/mixins.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | // Word break
4 | @mixin break-word($width: 0) {
5 | @if $width != 0 {
6 | width: $width;
7 | }
8 | word-wrap: break-word;
9 | word-break: break-all;
10 | }
11 |
--------------------------------------------------------------------------------
/styles/style.scss:
--------------------------------------------------------------------------------
1 | $fa-font-path: "../node_modules/font-awesome/fonts";
2 | @import "node_modules/font-awesome/scss/font-awesome";
3 | @import "variables";
4 |
5 | // Normalize (Should be replaced by normalize.css.)
6 |
7 | body {
8 | margin: 0;
9 | -webkit-font-smoothing: antialiased;
10 | }
11 |
12 | select {
13 | color: inherit;
14 | font: inherit;
15 | margin: 0;
16 | }
17 |
18 | ul {
19 | list-style-type: none;
20 | padding-left: 2px;
21 | }
22 |
23 | input {
24 | outline: 0;
25 | }
26 |
27 | // Styles
28 |
29 | // Common styles
30 |
31 | html,body {
32 | height: 100%;
33 | }
34 |
35 | body {
36 | width: 100%;
37 | overflow: hidden;
38 | font-family: "Helvetica Neue",Helvetica,'游ゴシック', YuGothic, "ヒラギノ角ゴ ProN W3","Hiragino Kaku Gothic ProN","メイリオ",Meiryo,sans-serif;
39 | }
40 |
--------------------------------------------------------------------------------
/styles/variables.scss:
--------------------------------------------------------------------------------
1 | // Variables
2 |
3 | // Typography
4 | $text-color: #4a4a4a;
5 | $code-color: $text-color;
6 | $code-bg: #f7f7f7;
7 | $code-font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
8 | $bullet: '\002022';
9 | $italic-font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', '游ゴシック', YuGothic, sans-serif;
10 |
--------------------------------------------------------------------------------
/test/components/menu-test.coffee:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | component = require '../../src/components/menu'
3 | element = React.createFactory component
4 |
5 | describe 'components/menu', ->
6 | describe '#render', ->
7 | it 'should validate output', ->
8 | rendered = React.renderToString(element {})
9 |
--------------------------------------------------------------------------------
/test/components/opening-test.coffee:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | component = require '../../src/components/opening'
3 | element = React.createFactory component
4 |
5 | describe 'components/opening', ->
6 | describe '#render', ->
7 | it 'should validate output', ->
8 | rendered = React.renderToString(element {})
9 |
--------------------------------------------------------------------------------
/test/scenes/menu-test.coffee:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | Scene = require '../../src/scenes/menu'
3 |
4 | describe 'scenes/menu', ->
5 | it 'should be written', ->
6 | new Scene
7 |
--------------------------------------------------------------------------------
/test/scenes/opening-test.coffee:
--------------------------------------------------------------------------------
1 | require '../test-helper'
2 | Scene = require '../../src/scenes/opening'
3 |
4 | describe 'scenes/opening', ->
5 | it 'should be written', ->
6 | new Scene
7 |
--------------------------------------------------------------------------------
/test/test-helper.coffee:
--------------------------------------------------------------------------------
1 | global = require 'global'
2 | global.Promise = require 'bluebird'
3 | global.React = require 'react'
4 | global.Overworld = require 'overworld'
5 | Overworld.setReact React
6 |
7 | # require jade
8 | jade = require('react-jade')
9 | require.extensions['.jade'] = (module, filename) ->
10 | module.exports = jade.compileFile(filename)
11 |
12 | global.assert = require 'assert'
13 | global.ok = assert.ok
14 | global.equal = assert.equal
15 | global.deepEqual = assert.deepEqual
16 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require("webpack");
2 | var path = require('path');
3 |
4 | module.exports = {
5 | // entry: './lib/index.js',
6 |
7 | output: {
8 | filename: 'public/bundle.js'
9 | },
10 |
11 | module: {
12 | loaders: [
13 | { test: /\.coffee$/, loader: "coffee" },
14 | { test: /\.jade$/, loader: "react-jade-loader" }
15 | ]
16 | },
17 |
18 | resolve: {
19 | root: [],
20 | extensions: ["", ".coffee", ".js"]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------