├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── assets
├── audio
│ ├── bump.ogg
│ ├── campfire.ogg
│ ├── fountain.ogg
│ ├── grass_step.ogg
│ ├── ground_step.ogg
│ ├── gs_sound_data.0017dd40.mid
│ ├── gs_sound_data.0017dda0.mid
│ ├── jump.ogg
│ ├── jump2.ogg
│ ├── new-bark-town.ogg
│ ├── notice.ogg
│ ├── run_step.ogg
│ └── sea.ogg
├── fonts
│ ├── advocut-webfont.eot
│ ├── advocut-webfont.ttf
│ └── advocut-webfont.woff
├── i18n
│ ├── br.json
│ ├── cn.json
│ ├── da.json
│ ├── de.json
│ ├── en.json
│ ├── fr.json
│ └── nl.json
└── img
│ ├── 0.png
│ ├── 0_normal.png
│ ├── 1.png
│ ├── 136.png
│ ├── 151.png
│ ├── 200.png
│ ├── 3.png
│ ├── 4.png
│ ├── 4_normal.png
│ ├── 85.png
│ ├── 85_normal.png
│ ├── chat
│ ├── bleft.png
│ ├── bright.png
│ ├── fill.png
│ ├── point.png
│ ├── tleft.png
│ └── tright.png
│ ├── icons.png
│ ├── light.png
│ └── tilesets
│ └── hgss_by_epicday.png
├── index.html
├── main.css
├── package.json
├── server
├── config.js
├── package.json
└── src
│ ├── GameServer.js
│ ├── Instance.js
│ ├── index.js
│ └── polyfill.js
├── src
├── Engine
│ ├── Audio
│ │ └── index.js
│ ├── Camera
│ │ └── index.js
│ ├── Commander
│ │ └── index.js
│ ├── Connection
│ │ └── index.js
│ ├── Controller
│ │ ├── actions.js
│ │ └── index.js
│ ├── DisplayObject
│ │ └── index.js
│ ├── Editor
│ │ ├── commands.js
│ │ ├── index.js
│ │ ├── render.js
│ │ └── tileset.js
│ ├── Entity
│ │ ├── functions.js
│ │ └── index.js
│ ├── Environment
│ │ ├── Evaluator
│ │ │ └── index.js
│ │ ├── Parser
│ │ │ ├── NodeList.js
│ │ │ ├── expression.js
│ │ │ ├── index.js
│ │ │ ├── parse.js
│ │ │ └── precedence.js
│ │ ├── Tester
│ │ │ ├── index.js
│ │ │ └── tests.js
│ │ ├── Tokenizer
│ │ │ ├── index.js
│ │ │ └── tokens.js
│ │ └── index.js
│ ├── Input
│ │ ├── Keyboard.js
│ │ ├── Mouse.js
│ │ └── index.js
│ ├── Language
│ │ └── index.js
│ ├── Map
│ │ ├── MapEntity.js
│ │ ├── events.js
│ │ ├── functions.js
│ │ └── index.js
│ ├── MiniMap
│ │ └── index.js
│ ├── Notification
│ │ └── index.js
│ ├── Path
│ │ └── index.js
│ ├── Renderer
│ │ ├── debug.js
│ │ ├── grid.js
│ │ ├── index.js
│ │ ├── render.js
│ │ └── webgl
│ │ │ ├── index.js
│ │ │ └── shaders.js
│ ├── Shadow
│ │ └── index.js
│ ├── Texture
│ │ ├── effects.js
│ │ └── index.js
│ ├── index.js
│ ├── logic.js
│ ├── sound.js
│ └── utils
│ │ └── index.js
├── Game
│ ├── entities
│ │ ├── Light
│ │ │ └── index.js
│ │ ├── Monster.js
│ │ ├── Player
│ │ │ ├── face.js
│ │ │ ├── follow.js
│ │ │ ├── index.js
│ │ │ ├── jump.js
│ │ │ ├── new
│ │ │ │ ├── face.js
│ │ │ │ ├── index.js
│ │ │ │ ├── jump.js
│ │ │ │ ├── sound.js
│ │ │ │ └── walk.js
│ │ │ ├── sound.js
│ │ │ └── walk.js
│ │ └── index.js
│ ├── index.js
│ └── input.js
├── Math.js
├── Packets
│ ├── Facing.js
│ ├── Jumping.js
│ ├── Position.js
│ ├── Velocity.js
│ └── index.js
├── cfg.js
├── libs
│ ├── Howler.js
│ ├── astar.js
│ ├── seed.js
│ └── wheel.js
└── polyfill.js
├── stats.js
├── webpack.config.js
└── worlds
└── kanto
├── i18n
├── de.json
└── en.json
├── index.js
└── town
├── objects
├── building1.json
├── building1.png
├── building1_normal.png
├── campfire.json
├── campfire.png
├── campfire_normal.png
├── charizard.json
├── charizard.png
├── charizard_normal.png
├── door1.json
├── door1.png
├── flower.json
├── flower.png
├── flower_normal.png
├── grass.json
├── grass.png
├── lantern.json
├── lantern.png
├── lantern_normal.png
├── ping.json
├── ping.png
├── raindrop.json
├── raindrop.png
├── sign.json
├── sign.png
├── sign_normal.png
├── table.json
├── table.png
├── table_normal.png
├── tree.json
├── tree.png
├── tree_normal.png
├── water1.json
└── water1.png
├── town.js
└── town.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Line endings: enforce LF in GitHub, convert to native on checkout.
2 |
3 | * text=auto
4 | *.js text
5 |
6 | # Make GitHub ignore vendor libraries while computing language stats.
7 | # See https://github.com/github/linguist#overrides.
8 |
9 | /assets/* linguist-vendored=true
10 | /worlds/* linguist-vendored=true
11 |
12 | # Explicitly specify language for non-standard extensions used under
13 | # ide/web/lib/templates to make GitHub correctly count their language stats.
14 | #
15 | *.js_ linguist-language=JavaScript
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Thumbs.db
2 | Desktop.ini
3 | $RECYCLE.BIN/
4 | .DS_Store
5 | *.bat
6 | *.sh
7 |
8 | node_modules
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | PokeMMO
2 | 2016-05-05
3 | Copyright (c) 2015 Felix Maier @github.com/maierfelix
4 | All rights reserved.
5 |
6 | Repository: https://github.com/maierfelix/PokeMMO
7 |
8 | The above notice and the following licenses applies to all parts of this software.
9 | Redistribution and use in source and binary forms, with or without
10 | modification, are permitted provided that the following conditions are met:
11 |
12 | * The Software shall be used for Good, not Evil.
13 |
14 | * Redistributions of source code must retain the above copyright notice, this
15 | list of conditions and the following disclaimer.
16 |
17 | * Redistributions in binary form must reproduce the above copyright notice,
18 | this list of conditions and the following disclaimer in the documentation
19 | and/or other materials provided with the distribution.
20 |
21 | * You may not remove, edit or change any copyright notices, inside the source.
22 | Those conditions also applies to any established copyright notices inside the production build.
23 |
24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Pokémon Engine
2 |
3 | [](https://gitter.im/maierfelix/PokeMMO?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | [Demo](http://maierfelix.github.io/PokeMMO)
6 | Runs best on Chrome.
7 | Uses the 2D canvas to render the editor mode and WebGL for the gameplay (unfinished).
8 | Graphics used in the demo are created by [EpicDay](http://epicday.deviantart.com/) and [Red_Ex](http://the-red-ex.deviantart.com/).
9 | Sounds are taken from [SoundBible](http://soundbible.com/).
10 |
11 | - Z: Action
12 | - X: Run
13 | - C: Jump
14 | - F1: Switch renderer (webgl/canvas)
15 | - F2: Edit mode
16 | - F3: Free camera mode (Press right mouse key to drag around)
17 | - F4: God mode
18 |
19 | Setup:
20 | ````
21 | Client:
22 | npm install
23 | npm run watch
24 |
25 | Server:
26 | cd ./server
27 | npm install
28 | npm run start
29 | ````
30 |
31 | - [ ] Engine
32 | - [x] Collisions
33 | - [x] Camera
34 | - [x] 3D Audio implementation
35 | - [x] Grid based path finding
36 | - [x] Maps
37 | - [ ] Map connections
38 | - [x] Dynamic multi-lingual support
39 | - [x] Mini map
40 | - [x] Pings
41 | - [ ] Notifications (Map name, dialog boxes etc)
42 | - [ ] Record/Replay Mode
43 | - [ ] Seed based animations
44 | - [x] Canvas renderer
45 | - [x] WebGL renderer
46 | - [ ] Normal map based lighting
47 |
48 | - [ ] Editor
49 | - [x] Undo & Redo
50 | - [x] Select, Copy, Paste, Cut, Delete (unstable)
51 | - [ ] Range map entity selections
52 | - [x] Map entities
53 | - [ ] Map entities settings
54 | - [x] Map entity add & edit support
55 | - [ ] Map entity collison box editor
56 | - [x] Draggable map entities
57 | - [ ] UI
58 | - [ ] Background map tile drawing
59 | - [ ] Background map collision tile drawing
60 | - [ ] Map connections
61 | - [ ] Map entity event code editor
62 |
63 | - [ ] Interpreter
64 | - [x] Syntax
65 | - [x] Global flags
66 | - [x] Expressions
67 | - [ ] Game api
68 | - [x] Frame based step script execution
69 |
--------------------------------------------------------------------------------
/assets/audio/bump.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/bump.ogg
--------------------------------------------------------------------------------
/assets/audio/campfire.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/campfire.ogg
--------------------------------------------------------------------------------
/assets/audio/fountain.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/fountain.ogg
--------------------------------------------------------------------------------
/assets/audio/grass_step.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/grass_step.ogg
--------------------------------------------------------------------------------
/assets/audio/ground_step.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/ground_step.ogg
--------------------------------------------------------------------------------
/assets/audio/gs_sound_data.0017dd40.mid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/gs_sound_data.0017dd40.mid
--------------------------------------------------------------------------------
/assets/audio/gs_sound_data.0017dda0.mid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/gs_sound_data.0017dda0.mid
--------------------------------------------------------------------------------
/assets/audio/jump.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/jump.ogg
--------------------------------------------------------------------------------
/assets/audio/jump2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/jump2.ogg
--------------------------------------------------------------------------------
/assets/audio/new-bark-town.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/new-bark-town.ogg
--------------------------------------------------------------------------------
/assets/audio/notice.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/notice.ogg
--------------------------------------------------------------------------------
/assets/audio/run_step.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/run_step.ogg
--------------------------------------------------------------------------------
/assets/audio/sea.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/audio/sea.ogg
--------------------------------------------------------------------------------
/assets/fonts/advocut-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/fonts/advocut-webfont.eot
--------------------------------------------------------------------------------
/assets/fonts/advocut-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/fonts/advocut-webfont.ttf
--------------------------------------------------------------------------------
/assets/fonts/advocut-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/fonts/advocut-webfont.woff
--------------------------------------------------------------------------------
/assets/i18n/br.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Navegador não suportado.",
3 | "s_days": [
4 | "Domingo",
5 | "Segunda",
6 | "Terça",
7 | "Quarta",
8 | "Quinta",
9 | "Sexta",
10 | "Sábado"
11 | ],
12 | "s_months": [
13 | "Janeiro",
14 | "Fevereiro",
15 | "Março",
16 | "Abril",
17 | "Maio",
18 | "Junho",
19 | "Julho",
20 | "Agosto",
21 | "Setembro",
22 | "Outubro",
23 | "Novembro",
24 | "Dezembro"
25 | ],
26 | "s_German": "Alemão",
27 | "s_English": "Inglês",
28 | "s_Settings": "Configurações",
29 | "s_Objects": "Objetos",
30 | "s_On": "Ligado",
31 | "s_Off": "Desligado",
32 | "s_ChangeLanguage": "Mudar linguagem"
33 | }
34 |
--------------------------------------------------------------------------------
/assets/i18n/cn.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "浏览器不支持.",
3 | "s_days": [
4 | "星期天",
5 | "星期一",
6 | "星期二",
7 | "星期三",
8 | "星期四",
9 | "星期五",
10 | "星期六"
11 | ],
12 | "s_months": [
13 | "一月",
14 | "二月",
15 | "三月",
16 | "四月",
17 | "五月",
18 | "六月",
19 | "七月",
20 | "八月",
21 | "九月",
22 | "十月",
23 | "十一月",
24 | "十二月"
25 | ],
26 | "s_German": "德语",
27 | "s_English": "英语",
28 | "s_Settings": "设置",
29 | "s_Objects": "物体",
30 | "s_On": "开",
31 | "s_Off": "关",
32 | "s_ChangeLanguage": "更换语言"
33 | }
--------------------------------------------------------------------------------
/assets/i18n/da.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Browser understøttes ikke.",
3 | "s_days": [
4 | "Søndag",
5 | "Mandag",
6 | "Tirsdag",
7 | "Onsdag",
8 | "Torsdag",
9 | "Fredag",
10 | "Lørdag"
11 | ],
12 | "s_months": [
13 | "Januar",
14 | "Februar",
15 | "Marts",
16 | "April",
17 | "Maj",
18 | "Juni",
19 | "Juli",
20 | "August",
21 | "September",
22 | "Oktober",
23 | "November",
24 | "December"
25 | ],
26 | "s_German": "Tysk",
27 | "s_English": "Engelsk",
28 | "s_Settings": "Indstillinger",
29 | "s_Objects": "Objekter",
30 | "s_On": "Tænd",
31 | "s_Off": "Sluk",
32 | "s_ChangeLanguage": "Skift sprog",
33 | }
--------------------------------------------------------------------------------
/assets/i18n/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Browser nicht unterstützt.",
3 | "s_Days": [
4 | "Sonntag",
5 | "Montag",
6 | "Dienstag",
7 | "Mittwoch",
8 | "Donnerstag",
9 | "Freitag",
10 | "Samstag"
11 | ],
12 | "s_Months": [
13 | "Januar",
14 | "Februar",
15 | "März",
16 | "April",
17 | "Mai",
18 | "Juni",
19 | "Juli",
20 | "August",
21 | "September",
22 | "Oktober",
23 | "November",
24 | "Dezember"
25 | ],
26 | "s_German": "Deutsch",
27 | "s_English": "Englisch",
28 | "s_Settings": "Einstellungen",
29 | "s_Objects": "Objekte",
30 | "s_On": "An",
31 | "s_Off": "Aus",
32 | "s_ChangeLanguage": "Sprache wechseln",
33 | "s_Width": "Breite",
34 | "s_Height": "Höhe",
35 | "s_Dimension": "Dimension",
36 | "s_MS": "ms",
37 | "s_C": "C",
38 | "s_V": "V",
39 | "s_X": "X",
40 | "s_Y": "Y",
41 | "s_Z": "Z",
42 | "s_Delta": "Delta",
43 | "s_Scale": "Skalierung",
44 | "s_Entity": "Entität",
45 | "s_Entities": "Entitäten",
46 | "s_EntitiesInView": "Sichtbare Entitäten",
47 | "s_Textures": "Texturen",
48 | "s_Local": "Lokal",
49 | "s_CommandStack": "Kommandos",
50 | "s_GodMode": "Gott Modus",
51 | "s_EditMode": "Editier Modus",
52 | "s_DebugMode": "Debug Modus",
53 | "s_FreeCamera": "Freie Kamera",
54 | "s_Enabled": "Aktiviert",
55 | "s_Disabled": "Deaktiviert",
56 | "s_Jump": "Hüpfen",
57 | "s_Run": "Rennen",
58 | "s_Action": "Aktion",
59 | "s_CTRL": "STRG",
60 | "s_Undo": "Rückgängig",
61 | "s_Redo": "Wiederherstellen",
62 | "s_Copy": "Kopieren",
63 | "s_Paste": "Einfügen",
64 | "s_Cut": "Ausschneiden",
65 | "s_Space": "Leertaste",
66 | "s_FocusPlayer": "Spieler fokussieren",
67 | "s_FocusEntity": "Entität fokussieren",
68 | "s_Wheel": "Mausrad",
69 | "s_Zoom": "Vergrößern",
70 | "s_RightMouse": "Rechte Maus",
71 | "s_DoubleClick": "Doppelklick"
72 | }
--------------------------------------------------------------------------------
/assets/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Browser not supported.",
3 | "s_days": [
4 | "Sunday",
5 | "Monday",
6 | "Tuesday",
7 | "Wednesday",
8 | "Thursday",
9 | "Friday",
10 | "Saturday"
11 | ],
12 | "s_months": [
13 | "January",
14 | "February",
15 | "March",
16 | "April",
17 | "May",
18 | "June",
19 | "July",
20 | "August",
21 | "September",
22 | "October",
23 | "November",
24 | "December"
25 | ],
26 | "s_German": "German",
27 | "s_English": "English",
28 | "s_Settings": "Settings",
29 | "s_Objects": "Objects",
30 | "s_On": "On",
31 | "s_Off": "Off",
32 | "s_ChangeLanguage": "Change language",
33 | "s_Width": "Width",
34 | "s_Height": "Height",
35 | "s_Dimension": "Dimension",
36 | "s_MS": "ms",
37 | "s_C": "C",
38 | "s_V": "V",
39 | "s_X": "X",
40 | "s_Y": "Y",
41 | "s_Z": "Z",
42 | "s_Delta": "Delta",
43 | "s_Scale": "Scale",
44 | "s_Entity": "Entity",
45 | "s_Entities": "Entities",
46 | "s_EntitiesInView": "Entities In View",
47 | "s_Textures": "Textures",
48 | "s_Local": "Local",
49 | "s_CommandStack": "Command Stack",
50 | "s_GodMode": "God Mode",
51 | "s_EditMode": "Edit Mode",
52 | "s_DebugMode": "Debug Mode",
53 | "s_FreeCamera": "Free Camera",
54 | "s_Enabled": "Enabled",
55 | "s_Disabled": "Disabled",
56 | "s_Jump": "Jump",
57 | "s_Run": "Run",
58 | "s_Action": "Action",
59 | "s_CTRL": "CTRL",
60 | "s_Undo": "Undo",
61 | "s_Redo": "Redo",
62 | "s_Copy": "Copy",
63 | "s_Paste": "Paste",
64 | "s_Cut": "Cut",
65 | "s_Space": "Space",
66 | "s_FocusPlayer": "Focus Player",
67 | "s_FocusEntity": "Focus Entity",
68 | "s_Wheel": "Wheel",
69 | "s_Zoom": "Zoom",
70 | "s_RightMouse": "RMouse",
71 | "s_DoubleClick": "Doubleclick"
72 | }
--------------------------------------------------------------------------------
/assets/i18n/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Navigateur non supporté",
3 | "s_days": [
4 | "Dimanche",
5 | "Lundi",
6 | "Mardi",
7 | "Mercredi",
8 | "Jeudi",
9 | "Vendredi",
10 | "Samedi"
11 | ],
12 | "s_months": [
13 | "Janvier",
14 | "Février",
15 | "Mars",
16 | "Avril",
17 | "Mai",
18 | "Juin",
19 | "Juillet",
20 | "Août",
21 | "Septembre",
22 | "Octobre",
23 | "Novembre",
24 | "Décembre"
25 | ],
26 | "s_German": "Allemand",
27 | "s_English": "Anglais",
28 | "s_Settings": "Paramètres",
29 | "s_Objects": "Objets",
30 | "s_On": "Activé",
31 | "s_Off": "Désactivé",
32 | "s_ChangeLanguage": "Changer la langue"
33 | }
34 |
--------------------------------------------------------------------------------
/assets/i18n/nl.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_BrowserNotSupported": "Uw browser word niet ondersteund.",
3 | "s_Days": [
4 | "Zondag",
5 | "Maandag",
6 | "Dinsdag",
7 | "Woensdag",
8 | "Donderdag",
9 | "Vrijdag",
10 | "Zaterdag"
11 | ],
12 | "s_Months": [
13 | "Januari",
14 | "Februari",
15 | "Maart",
16 | "April",
17 | "Mei",
18 | "Juni",
19 | "Juli",
20 | "Augustus",
21 | "September",
22 | "Oktober",
23 | "November",
24 | "December"
25 | ],
26 | "s_German": "Duits",
27 | "s_English": "Engels",
28 | "s_Settings": "Instellingen",
29 | "s_Objects": "Objecten",
30 | "s_On": "Aan",
31 | "s_Off": "Uit",
32 | "s_ChangeLanguage": "Taal Veranderen",
33 | "s_Width": "Breedte",
34 | "s_Height": "Hoogte",
35 | "s_Dimension": "Dimensie",
36 | "s_MS": "ms",
37 | "s_C": "C",
38 | "s_V": "V",
39 | "s_X": "X",
40 | "s_Y": "Y",
41 | "s_Z": "Z",
42 | "s_Delta": "Delta",
43 | "s_Scale": "Schaal",
44 | "s_Entity": "Entiteit",
45 | "s_Entities": "Entiteiten",
46 | "s_EntitiesInView": "Entiteiten op het scherm",
47 | "s_Textures": "Texturen",
48 | "s_Local": "Lokaal",
49 | "s_CommandStack": "Commandostapel",
50 | "s_GodMode": "God Mode",
51 | "s_EditMode": "Bewerkmodus",
52 | "s_DebugMode": "Foutopsporingsmodus",
53 | "s_FreeCamera": "Vrije Camera",
54 | "s_Enabled": "Ingeschakeld",
55 | "s_Disabled": "Uitgeschakeld",
56 | "s_Jump": "Springen",
57 | "s_Run": "Rennen",
58 | "s_Action": "Actie",
59 | "s_CTRL": "CTRL",
60 | "s_Undo": "Ongedaan maken"
61 | }
--------------------------------------------------------------------------------
/assets/img/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/0.png
--------------------------------------------------------------------------------
/assets/img/0_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/0_normal.png
--------------------------------------------------------------------------------
/assets/img/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/1.png
--------------------------------------------------------------------------------
/assets/img/136.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/136.png
--------------------------------------------------------------------------------
/assets/img/151.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/151.png
--------------------------------------------------------------------------------
/assets/img/200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/200.png
--------------------------------------------------------------------------------
/assets/img/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/3.png
--------------------------------------------------------------------------------
/assets/img/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/4.png
--------------------------------------------------------------------------------
/assets/img/4_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/4_normal.png
--------------------------------------------------------------------------------
/assets/img/85.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/85.png
--------------------------------------------------------------------------------
/assets/img/85_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/85_normal.png
--------------------------------------------------------------------------------
/assets/img/chat/bleft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/bleft.png
--------------------------------------------------------------------------------
/assets/img/chat/bright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/bright.png
--------------------------------------------------------------------------------
/assets/img/chat/fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/fill.png
--------------------------------------------------------------------------------
/assets/img/chat/point.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/point.png
--------------------------------------------------------------------------------
/assets/img/chat/tleft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/tleft.png
--------------------------------------------------------------------------------
/assets/img/chat/tright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/chat/tright.png
--------------------------------------------------------------------------------
/assets/img/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/icons.png
--------------------------------------------------------------------------------
/assets/img/light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/light.png
--------------------------------------------------------------------------------
/assets/img/tilesets/hgss_by_epicday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/assets/img/tilesets/hgss_by_epicday.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Pokémon Engine
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/main.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @font-face {
4 | font-family: 'AdvoCut';
5 | src: url(./assets/fonts/advocut-webfont.eot);
6 | src: url(./assets/fonts/advocut-webfont.eot?#iefix) format('embedded-opentype'),
7 | url(./assets/fonts/advocut-webfont.woff) format('woff'),
8 | url(./assets/fonts/advocut-webfont.ttf) format('truetype'),
9 | url(./assets/fonts/advocut-webfont.svg#AndinaRegular) format('svg');
10 | font-weight: normal;
11 | font-style: normal;
12 | }
13 |
14 | @-ms-viewport {
15 | width: device-width;
16 | }
17 |
18 | html {
19 | min-height:100%;
20 | background: #1f1f1f;
21 | }
22 |
23 | body {
24 | overflow:hidden;
25 | -webkit-user-select: none;
26 | -moz-user-select: none;
27 | margin:0;
28 | color: white;
29 | font-family: 'AdvoCut', sans-serif;
30 | text-align: center;
31 | cursor: default;
32 | }
33 |
34 | *:focus {
35 | outline:none;
36 | }
37 |
38 | *,*::before,*::after {
39 | -moz-box-sizing:border-box;
40 | box-sizing:border-box;
41 | }
42 |
43 | ::-webkit-scrollbar {
44 | width: 8px;
45 | height: 8px;
46 | background:transparent;
47 | }
48 | ::-webkit-scrollbar-thumb {
49 | background: rgba(255,255,255,0.12);
50 | border-radius: 14px;
51 | }
52 | ::-webkit-scrollbar-corner {
53 | background:transparent;
54 | }
55 | ::selection{
56 | color:#EEE;
57 | background:#141414;
58 | }
59 |
60 | button, a {
61 | padding: 0;
62 | border: 1px solid transparent;
63 | background: none;
64 | outline: none;
65 | text-decoration: none;
66 | }
67 |
68 | #ui {
69 | z-index: 2;
70 | }
71 |
72 | #canvas {
73 | z-index: 1;
74 | }
75 |
76 | #webgl {
77 | z-index: 1;
78 | }
79 |
80 | canvas, img {
81 | position: absolute;
82 | z-index: 1;
83 | left: 0px;
84 | top: 0px;
85 | image-rendering: optimizeSpeed;
86 | image-rendering: -o-crisp-edges;
87 | image-rendering: -moz-crisp-edges;
88 | image-rendering: optimize-contrast;
89 | image-rendering: -webkit-optimize-contrast;
90 | image-rendering: pixelated;
91 | -ms-interpolation-mode: nearest-neighbor;
92 | -ms-touch-action: manipulation;
93 | touch-action: manipulation;
94 | transform-origin: 0% 0%;
95 | -ms-transform-origin: 0% 0%;
96 | -webkit-transform-origin: 0% 0%;
97 | -o-transform-origin: 0% 0%;
98 | -moz-transform-origin: 0% 0%;
99 | transform: scale(1, 1);
100 | -ms-transform: scale(1, 1);
101 | -webkit-transform: scale(1, 1);
102 | -o-transform: scale(1, 1);
103 | -moz-transform: scale(1, 1);
104 | -webkit-backface-visibility: hidden;
105 | -webkit-perspective: 1000;
106 | cursor: -moz-grab;
107 | cursor: -webkit-grab;
108 | cursor: grab;
109 | -webkit-touch-callout: none;
110 | -webkit-user-select: none;
111 | -khtml-user-select: none;
112 | -moz-user-select: none;
113 | -ms-user-select: none;
114 | user-select: none;
115 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pokiengine",
3 | "version": "0.0.2",
4 | "description": "Pokémon Engine",
5 | "scripts": {
6 | "watch": "webpack --watch"
7 | },
8 | "devDependencies": {
9 | "babel-core": "^6.0.20",
10 | "babel-loader": "^6.0.1",
11 | "babel-plugin-transform-runtime": "^6.4.3",
12 | "babel-preset-es2015": "^6.24.1",
13 | "babel-preset-stage-0": "^6.3.13",
14 | "node-libs-browser": "^0.5.3",
15 | "webpack": "^1.12.2"
16 | },
17 | "dependencies": {
18 | "babel-runtime": "^6.3.19",
19 | "json-stringify-safe": "^5.0.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/server/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Window title
3 | * @type {String}
4 | */
5 | export let TITLE = "Server";
6 |
7 | /**
8 | * Maximum connections
9 | * @type {Number}
10 | */
11 | export let MAX_CONNECTIONS = 64;
12 |
13 | /**
14 | * Connection port
15 | * @constant
16 | * @type {Number}
17 | */
18 | export const PORT = 449;
19 |
20 | /**
21 | * Server mode
22 | * @constant
23 | * @type {Number}
24 | */
25 | export const MODE = 0;
26 |
27 | /**
28 | * Log level
29 | * @constant
30 | * @type {Number}
31 | */
32 | export const LOG_LEVEL = 1;
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pokiengine",
3 | "version": "0.0.1",
4 | "description": "Pokémon Engine Server",
5 | "main": "src/index.js",
6 | "dependencies": {
7 | "fast-json-patch": "Starcounter-Jack/JSON-Patch",
8 | "msgpack-lite": "^0.1.13",
9 | "shortid": "^2.2.4",
10 | "es6-module-loader": "^0.17.11",
11 | "ws": "latest",
12 | "babel-runtime": "^6.3.19"
13 | },
14 | "devDependencies": {
15 | "assert": "^1.3.0",
16 | "babel": "^6.5.2",
17 | "babel-cli": "^6.6.5",
18 | "babel-core": "^6.0.20",
19 | "babel-loader": "^6.0.1",
20 | "babel-plugin-transform-runtime": "^6.4.3",
21 | "babel-preset-stage-0": "^6.5.0",
22 | "benchmark": "^1.0.0",
23 | "express": "^4.13.3",
24 | "immutable": "^3.7.6",
25 | "immutable-diff": "^0.1.1",
26 | "mocha": "^2.3.4",
27 | "node-libs-browser": "^0.5.3",
28 | "nodemon": "^1.7.1"
29 | },
30 | "scripts": {
31 | "start": "nodemon src/index.js --exec babel-node --presets es2015,stage-0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/server/src/GameServer.js:
--------------------------------------------------------------------------------
1 | import WebSocket from "ws";
2 | import http from "http";
3 | import fs from "fs";
4 |
5 | import "./polyfill";
6 |
7 | import Packet from "../../src/packets";
8 |
9 | import {
10 | PORT
11 | } from "../config";
12 |
13 | import { uHash } from "../../src/Engine/utils";
14 |
15 | import Entity from "../../src/Engine/Entity";
16 |
17 | import Instance from "./Instance";
18 |
19 | import * as game_cfg from "../../src/cfg";
20 |
21 | /**
22 | * GameServer
23 | * @class GameServer
24 | * @export
25 | */
26 | export default class GameServer {
27 |
28 | /**
29 | * @constructor
30 | */
31 | constructor() {
32 |
33 | game_cfg.IS_CLIENT = false;
34 |
35 | /**
36 | * Websocket instance
37 | * @type {Object}
38 | */
39 | this.ws = null;
40 |
41 | /**
42 | * One frame tick
43 | * @type {Number}
44 | */
45 | this.frame = 1000.0 / 60.0;
46 |
47 | /**
48 | * Now timestamp
49 | * @type {Number}
50 | */
51 | this.now = 0;
52 |
53 | /**
54 | * Tick timer
55 | * @type {Number}
56 | */
57 | this.tick = 0;
58 |
59 | /**
60 | * Now timestamp
61 | * @type {Number}
62 | */
63 | this.then = 0;
64 |
65 | /**
66 | * Running state
67 | * @type {Boolean}
68 | */
69 | this.running = false;
70 |
71 | /**
72 | * Users
73 | * @type {Array}
74 | */
75 | this.users = [];
76 |
77 | /**
78 | * Interval instance
79 | * @type {Object}
80 | */
81 | this.interval = null;
82 |
83 | this.init();
84 |
85 | }
86 |
87 | /**
88 | * Intitialse a ws server
89 | */
90 | init() {
91 |
92 | let options = {
93 | port: PORT,
94 | perMessageDeflate: false
95 | };
96 |
97 | this.ws = new WebSocket.Server(options, this::this.onStart);
98 |
99 | this.ws.on('connection', this::this.onConnection);
100 | this.ws.on('error', this::this.onError);
101 |
102 | }
103 |
104 | /**
105 | * Start main loop
106 | */
107 | startLoop() {
108 | clearInterval(this.interval);
109 | this.interval = setInterval(this::this.loop, this.frame);
110 | }
111 |
112 | /**
113 | * Stop main loop
114 | */
115 | stopLoop() {
116 | clearInterval(this.interval);
117 | }
118 |
119 | /**
120 | * Start event
121 | * @param {Object} e
122 | */
123 | onStart(e) {
124 | this.startLoop();
125 | this.running = true;
126 | }
127 |
128 | /**
129 | * New client connected
130 | * @param {Object} socket
131 | */
132 | onConnection(socket, req) {
133 |
134 | let ip = req.connection.remoteAddress;
135 |
136 | console.log(`${ip} joined!`);
137 |
138 | this.addUser(socket);
139 |
140 | }
141 |
142 | addUser(socket) {
143 |
144 | let entity = new Entity({});
145 | let instance = new Instance(this, entity);
146 |
147 | entity.id = uHash();
148 | entity.socket = socket;
149 | entity.instance = instance;
150 |
151 | var self = this;
152 |
153 | socket.on('message', instance::instance.onMessage);
154 | socket.on('close', function() {
155 | self.onClose(entity.id);
156 | });
157 |
158 | this.users.push(entity);
159 |
160 | }
161 |
162 | /**
163 | * Message event
164 | * @param {Object} msg
165 | */
166 | onMessage(msg) {
167 | //console.log(msg);
168 | }
169 |
170 | /**
171 | * Close event
172 | * @param {Number} id
173 | */
174 | onClose(id) {
175 |
176 | let ii = 0;
177 | let length = this.users.length;
178 |
179 | for (; ii < length; ++ii) {
180 | if (this.users[ii].id === id) {
181 | this.users[ii].instance.kill();
182 | this.users.splice(ii, 1);
183 | break;
184 | }
185 | };
186 |
187 | }
188 |
189 | /**
190 | * Error event
191 | * @param {Object} e
192 | */
193 | onError(e) {
194 | switch (e.code) {
195 | case "EADDRINUSE":
196 | console.log("[Error] Server could not bind to port! Please close out of Skype or change 'serverPort' in gameserver.ini to a different number.");
197 | break;
198 | case "EACCES":
199 | console.log("[Error] Please make sure you are running Ogar with root privileges.");
200 | break;
201 | default:
202 | console.log("[Error] Unhandled error code: " + e.code);
203 | break;
204 | };
205 | process.exit(1);
206 | }
207 |
208 | /**
209 | * Share a message
210 | * @param {Object} msg
211 | * @param {String} name
212 | */
213 | broadcastMessage(msg, name) {
214 |
215 | let ii = 0;
216 | let length = this.users.length;
217 |
218 | for (; ii < length; ++ii) {
219 | if (this.users[ii].name === name) continue;
220 | this.users[ii].socket.sendPacket(msg);
221 | };
222 |
223 | }
224 |
225 | /**
226 | * Send message to single client
227 | * @param {Object} msg
228 | * @param {String} name
229 | */
230 | sendMessageTo(msg, name) {
231 |
232 | let ii = 0;
233 | let length = this.users.length;
234 |
235 | for (; ii < length; ++ii) {
236 | if (this.users[ii].name !== name) continue;
237 | this.users[ii].socket.sendPacket(msg);
238 | };
239 |
240 | }
241 |
242 | /**
243 | * Update timers
244 | */
245 | update() {
246 | this.now = Date.now();
247 | this.tick += (this.now - this.then);
248 | this.then = this.now;
249 | return void 0;
250 | }
251 |
252 | /**
253 | * Main loop
254 | */
255 | loop() {
256 |
257 | this.update();
258 |
259 | if (this.running === false) return void 0;
260 |
261 | if (this.tick < 25) return void 0;
262 |
263 | this.thread(this.moveTick);
264 |
265 | this.tick = 0;
266 |
267 | /*
268 | this.thread(this.spawnTick);
269 | this.thread(this.gamemodeTick);
270 | this.thread(this.cellUpdateTick);
271 | */
272 |
273 | return void 0;
274 |
275 | }
276 |
277 | animateNPC() {
278 |
279 | let cfg = game_cfg;
280 |
281 | let entity = "Joy";
282 | let move = [cfg.LEFT, cfg.RIGHT, cfg.UP, cfg.DOWN][(Math.random() * 3) << 0];
283 |
284 | let ii = 0;
285 | let length = this.users.length;
286 |
287 | for (; ii < length; ++ii) {
288 | //this.users[ii].packetHandler.socket.sendPacket(new Packet.Position(1337, move));
289 | };
290 |
291 | }
292 |
293 | moveTick() {
294 |
295 | }
296 |
297 | /**
298 | * Thread based function execution
299 | * @param {Function} func
300 | */
301 | thread(func) {
302 | setTimeout(this::func, 0);
303 | return void 0;
304 | }
305 |
306 | }
--------------------------------------------------------------------------------
/server/src/Instance.js:
--------------------------------------------------------------------------------
1 | import Packet from "../../src/packets";
2 |
3 | /**
4 | * Instance
5 | * @class Instance
6 | * @export
7 | */
8 | export default class Instance {
9 |
10 | /**
11 | * @constructor
12 | * @param {Object} instance
13 | * @param {Object} entity
14 | */
15 | constructor(instance, entity) {
16 |
17 | /**
18 | * Instance ref
19 | * @type {Object}
20 | */
21 | this.instance = instance;
22 |
23 | /**
24 | * Entity ref
25 | * @type {Object}
26 | */
27 | this.entity = entity;
28 |
29 | /**
30 | * Protocol
31 | * @type {Number}
32 | */
33 | this.protocol = 0;
34 |
35 | }
36 |
37 | /**
38 | * Sto buffer
39 | * @param {Array} message
40 | * @return {Object}
41 | */
42 | stobuf(buffer) {
43 |
44 | let ii = 0;
45 | let length = buffer.length;
46 | let arrayBuffer = new ArrayBuffer(length);
47 | let view = new Uint8Array(arrayBuffer);
48 |
49 | for (; ii < length; ++ii) {
50 | view[ii] = buffer[ii];
51 | };
52 |
53 | return (view.buffer);
54 | }
55 |
56 | invalidMessage(msg) {
57 | return (
58 | msg !== void 0 &&
59 | typeof msg === "string" ||
60 | msg.length === 0
61 | );
62 | }
63 |
64 | /**
65 | * Kill myself
66 | */
67 | kill() {
68 | let data = this.getSTR(34, JSON.stringify({name: this.entity.name}));
69 | this.instance.broadcastMessage(data, this.entity.name);
70 | return void 0;
71 | }
72 |
73 | /**
74 | * Handle a message
75 | * @param {Array} msg
76 | */
77 | onMessage(msg) {
78 |
79 | if (this.invalidMessage(msg) === true) return void 0;
80 |
81 | let buffer = this.stobuf(msg);
82 | let view = new DataView(buffer);
83 | let packetId = view.getUint8(0, true);
84 |
85 | /** Username */
86 | if (packetId === 0) {
87 | let name = this.getString(view);
88 | this.entity.name = name;
89 | this.instance.broadcastMessage(this.buildEntityData(name, 160, 144, false), name);
90 | this.instance.sendMessageTo(this.buildEntityData(name, 160, 144, true), name);
91 | return void 0;
92 | }
93 |
94 | /** Jumping */
95 | if (packetId === 30) {
96 | let id = view.getUint16(1, true);
97 | let data = this.getSTR(packetId, JSON.stringify({name: this.entity.name}));
98 | this.instance.broadcastMessage(data, this.entity.name);
99 | return void 0;
100 | }
101 |
102 | /** Facing */
103 | if (packetId === 31) {
104 | let id = view.getUint16(1, true);
105 | let dir = view.getUint16(3, true);
106 | this.entity.facing = dir << 0;
107 | let data = this.getSTR(packetId, JSON.stringify({ name: this.entity.name, dir: dir }));
108 | this.instance.broadcastMessage(data, this.entity.name);
109 | return void 0;
110 | }
111 |
112 | /** Movement */
113 | if (packetId === 32) {
114 | let id = view.getUint16(1, true);
115 | let dir = view.getUint16(3, true);
116 | let x = view.getUint16(5, true);
117 | let y = view.getUint16(7, true);
118 | this.entity.position.x = x << 0;
119 | this.entity.position.y = y << 0;
120 | let data = this.getSTR(packetId, JSON.stringify({ name: this.entity.name, dir: dir, x: x, y: y }));
121 | this.instance.broadcastMessage(data, this.entity.name);
122 | return void 0;
123 | }
124 |
125 | /** Velocity */
126 | if (packetId === 33) {
127 | let id = view.getUint16(1, true);
128 | let velocity = view.getUint16(3, true);
129 | this.entity.velocity = Number(velocity);
130 | let data = this.getSTR(packetId, JSON.stringify({ name: this.entity.name, velocity: velocity }));
131 | this.instance.broadcastMessage(data, this.entity.name);
132 | return void 0;
133 | }
134 |
135 | }
136 |
137 | /**
138 | * Build entity data
139 | * @param {String} name
140 | * @param {Number} x
141 | * @param {Number} y
142 | * @param {Boolean} local
143 | * @return {Object}
144 | */
145 | buildEntityData(name, x, y, local) {
146 |
147 | var options = {
148 | name: name,
149 | map: "Town",
150 | x: x,
151 | y: y,
152 | width: 16,
153 | height: 16,
154 | isLocalPlayer: local,
155 | sprite: "assets/img/0.png"
156 | };
157 |
158 | let data = JSON.stringify(options);
159 |
160 | return (this.getSTR(22, data));
161 |
162 | }
163 |
164 | getString(view) {
165 |
166 | if ((view.byteLength + 1) % 2 === 1) {
167 | return void 0;
168 | }
169 |
170 | var txt = "";
171 | var maxLen = 32 * 2;
172 | for (var i = 1; i < view.byteLength && i <= maxLen; i += 2) {
173 | var charCode = view.getUint16(i, true);
174 | if (charCode == 0) {
175 | return void 0;
176 | }
177 | txt += String.fromCharCode(charCode);
178 | }
179 | return (txt);
180 | }
181 |
182 | getSTR(id, str) {
183 |
184 | var lb = [str];
185 | var bufferSize = 5;
186 | var validElements = 0;
187 |
188 | // Get size of packet
189 | for (var i = 0; i < lb.length; i++) {
190 | if (typeof lb[i] == "undefined") {
191 | continue;
192 | }
193 |
194 | var item = lb[i];
195 | bufferSize += 4; // Empty ID
196 | bufferSize += item.length * 2; // String length
197 | bufferSize += 2; // Name terminator
198 |
199 | validElements++;
200 | }
201 |
202 | var buf = new ArrayBuffer(bufferSize);
203 | var view = new DataView(buf);
204 |
205 | // Set packet data
206 | view.setUint8(0, id, true); // Packet ID
207 | view.setUint32(1, validElements, true); // Number of elements
208 | var offset = 5;
209 |
210 | // Loop through strings
211 | for (var i = 0; i < lb.length; i++) {
212 | if (typeof lb[i] == "undefined") {
213 | continue;
214 | }
215 |
216 | var item = lb[i];
217 |
218 | view.setUint32(offset, 0, true);
219 | offset += 4;
220 |
221 | for (var j = 0; j < item.length; j++) {
222 | view.setUint16(offset, item.charCodeAt(j), true);
223 | offset += 2;
224 | }
225 |
226 | view.setUint16(offset, 0, true);
227 | offset += 2;
228 | }
229 |
230 | return buf;
231 |
232 | }
233 |
234 | }
--------------------------------------------------------------------------------
/server/src/index.js:
--------------------------------------------------------------------------------
1 | import * as cfg from "../config";
2 |
3 | import GameServer from "./GameServer";
4 |
5 | let server = new GameServer();
6 |
7 | process.title = cfg.TITLE;
8 |
9 | console.log("\x1b[32;1mStarting new server...\x1b[0m");
--------------------------------------------------------------------------------
/server/src/polyfill.js:
--------------------------------------------------------------------------------
1 | import WebSocket from "ws";
2 |
3 | /**
4 | * Get buffer
5 | * @param {Object} packet
6 | */
7 | WebSocket.prototype.getBuffer = function(data) {
8 |
9 | let ii = 0;
10 | let length = data.byteLength || data.length;
11 |
12 | let array = new Uint8Array(data.buffer || data);
13 | let offset = data.byteOffset || 0;
14 | let buffer = new Buffer(length);
15 |
16 | for (; ii < length; ++ii) {
17 | buffer[ii] = array[offset + ii];
18 | };
19 |
20 | return (buffer);
21 |
22 | };
23 |
24 | /**
25 | * Send a packet object
26 | * @param {Object} packet
27 | */
28 | WebSocket.prototype.sendPacket = function(packet) {
29 |
30 | if (this.readyState === WebSocket.OPEN && packet.build !== void 0) {
31 | this.send(this.getBuffer(packet.build()), {
32 | binary: true
33 | });
34 | } else if (packet.build === void 0) {
35 | this.send(packet, {
36 | binary: true
37 | });
38 | }
39 |
40 | return void 0;
41 |
42 | };
--------------------------------------------------------------------------------
/src/Engine/Audio/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Audio
3 | * @class Audio
4 | * @export
5 | */
6 | class Audio {
7 |
8 | /**
9 | * @constructor
10 | */
11 | constructor() {
12 |
13 | /**
14 | * Audio res path
15 | * @type {String}
16 | */
17 | this.path = "assets/audio/";
18 |
19 | /**
20 | * Noises
21 | * @type {Array}
22 | */
23 | this.noises = [];
24 |
25 | }
26 |
27 | /**
28 | * Play a sound
29 | * @param {String} name
30 | * @param {Number} vol
31 | * @param {Number} x
32 | * @param {Number} y
33 | */
34 | playSound(name, vol, x, y) {
35 | let path = this.path + `${name}.ogg`;
36 | var sound = new Howl({
37 | urls: [path],
38 | autoplay: true,
39 | loop: false,
40 | pos3d: [x, y, vol / 1e3]
41 | });
42 | }
43 |
44 | /**
45 | * Play a song
46 | * @param {String} name
47 | * @param {Number} vol
48 | * @param {Boolean} fadeIn
49 | */
50 | playSong(name, vol, fadeIn) {
51 | vol = vol / 1e2;
52 | let path = this.path + `${name}.ogg`;
53 | var song = new Howl({
54 | urls: [path],
55 | autoplay: true,
56 | loop: true,
57 | volume: fadeIn ? 0 : vol
58 | });
59 | if (fadeIn) {
60 | song.fadeIn(vol, 2e3);
61 | }
62 | }
63 |
64 | /**
65 | * Play a noise
66 | * @param {String} name
67 | * @param {Number} vol
68 | * @param {Number} x
69 | * @param {Number} y
70 | * @return {Object}
71 | */
72 | playNoise(name, vol, x, y) {
73 | let path = this.path + `${name}.ogg`;
74 | var noise = new Howl({
75 | urls: [path],
76 | autoplay: true,
77 | loop: true,
78 | volume: vol / 1e2,
79 | pos3d: [x, y, vol / 1e3]
80 | });
81 | this.noises.push(noise);
82 | /** This is for smooth out/in fading noise range area */
83 | noise.isInView = true;
84 | noise.fadingIn = false;
85 | noise.fadingOut = false;
86 | return (noise);
87 | }
88 |
89 | }
90 |
91 | export default Audio = new Audio();
--------------------------------------------------------------------------------
/src/Engine/Commander/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Commander
3 | * @class Commander
4 | * @export
5 | */
6 | export default class Commander {
7 |
8 | /**
9 | * @constructor
10 | */
11 | constructor() {
12 |
13 | /**
14 | * Stack position
15 | * @type {Number}
16 | */
17 | this.position = -1;
18 |
19 | /**
20 | * Command templates
21 | * @type {Object}
22 | */
23 | this.commands = {};
24 |
25 | /**
26 | * Command stack
27 | * @type {Array}
28 | */
29 | this.stack = [];
30 |
31 | }
32 |
33 | /**
34 | * Register a new command
35 | * @param {Object} cmd
36 | */
37 | newCommand(cmd) {
38 | this.commands[cmd.action] = cmd;
39 | cmd = null;
40 | }
41 |
42 | /**
43 | * Push a command
44 | * @param {String} action
45 | * @param {Object} scope
46 | * @param {Array} data
47 | */
48 | push(action, scope, data) {
49 |
50 | let cmd = {
51 | action: action,
52 | data: data,
53 | scope: scope
54 | };
55 |
56 | this.stack.splice(this.position + 1, this.stack.length);
57 |
58 | this.stack.push(cmd);
59 |
60 | this.redo();
61 | this.undo();
62 | this.redo();
63 | this.undo();
64 | this.redo();
65 |
66 | }
67 |
68 | /**
69 | * Fire command
70 | * @param {Object} cmd
71 | * @param {String} action
72 | */
73 | fire(cmd, action) {
74 | let template = this.commands[cmd.action][action];
75 | template.bind(cmd.scope).apply(template, cmd.data);
76 | }
77 |
78 | /**
79 | * Get cmd from current stack index
80 | * @return {Object}
81 | */
82 | getCurrentCmd() {
83 | return (this.stack[this.position]);
84 | }
85 |
86 | /**
87 | * Undo
88 | */
89 | undo() {
90 |
91 | if (this.position >= 0) {
92 | this.fire(this.getCurrentCmd(), "onUndo");
93 | this.position--;
94 | }
95 |
96 | }
97 |
98 | /**
99 | * Redo
100 | */
101 | redo() {
102 |
103 | if (this.position < this.stack.length - 1) {
104 | this.position++;
105 | this.fire(this.getCurrentCmd(), "onRedo");
106 | }
107 |
108 | }
109 |
110 | }
--------------------------------------------------------------------------------
/src/Engine/Controller/index.js:
--------------------------------------------------------------------------------
1 | import { DIMENSION } from "../../cfg";
2 |
3 | import * as actions from "./actions";
4 |
5 | /**
6 | * Controller
7 | * @class Controller
8 | * @export
9 | */
10 | export default class Controller {
11 |
12 | /**
13 | * @constructor
14 | * @param {Object} instance
15 | */
16 | constructor(instance) {
17 |
18 | /**
19 | * Instance
20 | * @type {Object}
21 | */
22 | this.instance = instance;
23 |
24 | /**
25 | * Engine ref
26 | * @type {Object}
27 | */
28 | this.engine = this.instance;
29 |
30 | /**
31 | * Actions ref
32 | * @type {Object}
33 | */
34 | this.actions = actions.actions;
35 |
36 | /**
37 | * Log array
38 | * @type {Array}
39 | */
40 | this.logs = [];
41 |
42 | }
43 |
44 | /**
45 | * Execute a action
46 | * @param {String} name
47 | * @param {Array} args
48 | */
49 | action(name, args = args || []) {
50 |
51 | let cmd = this.actions[name];
52 | let rule = this.engine.instance::cmd.rule() === true;
53 |
54 | if (rule === true) {
55 | cmd.action.bind(this.engine.instance).apply(this, args);
56 | }
57 |
58 | if (cmd.log !== false) this.log(name, rule);
59 |
60 | return void 0;
61 |
62 | }
63 |
64 | /**
65 | * Log a action
66 | * @param {String} name
67 | */
68 | log(name, failed) {
69 |
70 | this.logs.push({
71 | name: name,
72 | success: failed,
73 | timestamp: this.instance.renderer.now
74 | });
75 |
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/src/Engine/DisplayObject/index.js:
--------------------------------------------------------------------------------
1 | import { uHash } from "../utils";
2 | import math from "../../Math";
3 |
4 | /**
5 | * Display object
6 | * @class DisplayObject
7 | * @export
8 | */
9 | export default class DisplayObject {
10 |
11 | /**
12 | * @constructor
13 | * @param {Number} width
14 | * @param {Number} height
15 | */
16 | constructor(x, y, width, height) {
17 |
18 | /**
19 | * Unique id
20 | * @type {Number}
21 | */
22 | this.id = uHash();
23 |
24 | /**
25 | * Position
26 | * @type {Object}
27 | */
28 | this.position = new math.Point(
29 | x !== void 0 ? x : 0,
30 | y !== void 0 ? y : 0
31 | );
32 |
33 | /**
34 | * Size
35 | * @type {Object}
36 | */
37 | this.size = new math.Point(
38 | width !== void 0 ? width : 0,
39 | height !== void 0 ? height : 0
40 | );
41 |
42 | /**
43 | * Scale factor
44 | * @type {Object}
45 | */
46 | this.scale = new math.Point(1, 1);
47 |
48 | /**
49 | * X
50 | * @type {Number}
51 | * @getter
52 | * @setter
53 | */
54 | Object.defineProperty(this, "x", {
55 | get: function() {
56 | return (this.position.x);
57 | },
58 | set: function(value) {
59 | this.position.x = value;
60 | },
61 | configurable: true,
62 | enumerable: true
63 | });
64 |
65 | /**
66 | * Y
67 | * @type {Number}
68 | * @getter
69 | * @setter
70 | */
71 | Object.defineProperty(this, "y", {
72 | get: function() {
73 | return (this.position.y);
74 | },
75 | set: function(value) {
76 | this.position.y = value;
77 | },
78 | configurable: true,
79 | enumerable: true
80 | });
81 |
82 | /**
83 | * Width
84 | * @type {Number}
85 | * @getter
86 | * @setter
87 | */
88 | Object.defineProperty(this, "width", {
89 | get: function() {
90 | return (this.size.x);
91 | },
92 | set: function(value) {
93 | this.size.x = value;
94 | },
95 | configurable: true,
96 | enumerable: true
97 | });
98 |
99 | /**
100 | * Height
101 | * @type {Number}
102 | * @getter
103 | * @setter
104 | */
105 | Object.defineProperty(this, "height", {
106 | get: function() {
107 | return (this.size.y);
108 | },
109 | set: function(value) {
110 | this.size.y = value;
111 | },
112 | configurable: true,
113 | enumerable: true
114 | });
115 |
116 | }
117 |
118 | }
--------------------------------------------------------------------------------
/src/Engine/Editor/commands.js:
--------------------------------------------------------------------------------
1 | import {
2 | Y_DEPTH_HACK,
3 | DIMENSION
4 | } from "../../cfg";
5 |
6 | export let commands = [
7 | /** Select command */
8 | {
9 | action: "select",
10 | onUndo: function(entity, selection) {
11 | this.entitySelection = null;
12 | this.entitySelection = selection;
13 | },
14 | onRedo: function(entity, selection) {
15 | this.entitySelection = null;
16 | this.entitySelection = entity;
17 | }
18 | },
19 | /** Drag command */
20 | {
21 | action: "drag",
22 | onUndo: function(x, y) {
23 | this.x -= x;
24 | this.y -= y;
25 | this.y <<= 0;
26 | this.y += Y_DEPTH_HACK;
27 | this.last.x = this.x;
28 | this.last.y = this.y;
29 | },
30 | onRedo: function(x, y) {
31 | this.x += x;
32 | this.y += y;
33 | this.y <<= 0;
34 | this.y += Y_DEPTH_HACK;
35 | this.last.x = this.x;
36 | this.last.y = this.y;
37 | }
38 | },
39 | /** Delete command */
40 | {
41 | action: "delete",
42 | onUndo: function(entity) {
43 | this.instance.addEntity(entity);
44 | this.entitySelection = entity;
45 | },
46 | onRedo: function(entity) {
47 | this.instance.removeEntity(entity);
48 | this.entitySelection = null;
49 | }
50 | },
51 | /** Cut command */
52 | {
53 | action: "cut",
54 | onUndo: function(entity) {
55 | this.instance.editor.pasteEntity();
56 | },
57 | onRedo: function(entity) {
58 | this.instance.editor.copyEntity();
59 | this.instance.editor.deleteEntity();
60 | }
61 | },
62 | /** Copy command */
63 | {
64 | action: "copy",
65 | onUndo: function(entity, copy) {
66 | this.entityCopy = copy;
67 | this.entitySelection = copy;
68 | },
69 | onRedo: function(entity, copy) {
70 | this.entityCopy = entity;
71 | this.entitySelection = entity;
72 | }
73 | },
74 | /** Paste command */
75 | {
76 | action: "paste",
77 | onUndo: function (entity, paste) {
78 | this.instance.removeEntity(paste);
79 | },
80 | onRedo: function(entity, paste) {
81 |
82 | let map = this.map;
83 |
84 | if (paste !== null && paste !== void 0) {
85 | map.instance.addEntity(paste);
86 | return void 0;
87 | }
88 |
89 | let clone = this.instance.cloneEntity(entity);
90 |
91 | /** Fuck that */
92 | this.instance.editor.commander.stack[this.instance.editor.commander.position].data[1] = clone;
93 |
94 | map.instance.addEntity(clone);
95 |
96 | }
97 | }
98 | ];
--------------------------------------------------------------------------------
/src/Engine/Editor/render.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION
3 | } from "../../cfg";
4 |
5 | import math from "../../Math";
6 |
7 | /**
8 | * Edit mode
9 | */
10 | export function renderEditorMode() {
11 |
12 | this.renderSelection();
13 |
14 | if (this.instance.editor.STATES.SELECTING === true) {
15 | //this.renderSelectedEntities();
16 | }
17 |
18 | this.renderEntitySelection();
19 |
20 | }
21 |
22 | /**
23 | * Render selected entities
24 | */
25 | export function renderSelectedEntities() {
26 |
27 | let ii = 0;
28 | let length = 0;
29 |
30 | let entity = null;
31 | let entities = this.instance.editor.selectedEntities;
32 |
33 | length = entities.length;
34 |
35 | let resolution = 0;
36 |
37 | let x = 0;
38 | let y = 0;
39 |
40 | let width = 0;
41 | let height = 0;
42 |
43 | for (; ii < length; ++ii) {
44 |
45 | entity = entities[ii];
46 |
47 | resolution = this.camera.resolution;
48 |
49 | x = (this.camera.x + (entity.position.x + entity.xMargin) * resolution) << 0;
50 | y = (this.camera.y + (entity.position.y + entity.yMargin + entity.z) * resolution) << 0;
51 |
52 | width = (entity.size.x * resolution) << 0;
53 | height = (entity.size.y * resolution) << 0;
54 |
55 | this.context.beginPath();
56 |
57 | this.context.strokeStyle = "red";
58 | this.context.lineWidth = (resolution / 2) << 0;
59 | this.context.strokeRect(
60 | x, y,
61 | width, height
62 | );
63 | this.context.stroke();
64 |
65 | this.context.closePath();
66 |
67 | };
68 |
69 | }
70 |
71 | /**
72 | * Render selection
73 | */
74 | export function renderSelection() {
75 |
76 | if (this.instance.editor.STATES.SELECTING === false) return void 0;
77 |
78 | let selection = this.instance.editor.selection;
79 |
80 | let resolution = this.camera.resolution;
81 |
82 | let x = (this.camera.x + selection.x1 * resolution) << 0;
83 | let y = (this.camera.y + selection.y1 * resolution) << 0;
84 |
85 | let width = ((selection.x2 - selection.x1) * resolution) << 0;
86 | let height = ((selection.y2 - selection.y1) * resolution) << 0;
87 |
88 | this.context.beginPath();
89 |
90 | this.context.strokeStyle = "red";
91 | this.context.lineWidth = (resolution / 2) << 0;
92 | this.context.strokeRect(
93 | x, y,
94 | width, height
95 | );
96 | this.context.stroke();
97 |
98 | this.context.closePath();
99 |
100 | return void 0;
101 |
102 | }
103 |
104 | /**
105 | * Render entity selection
106 | */
107 | export function renderEntitySelection() {
108 |
109 | let entity = this.instance.editor.entitySelection;
110 |
111 | if (entity === null) return void 0;
112 |
113 | if (this.camera.isInView(
114 | entity.position.x, entity.position.y,
115 | entity.size.x * entity.scale, entity.size.y * entity.scale
116 | ) === false) return void 0;
117 | if (entity.opacity === .0) return void 0;
118 | if (entity.texture === null) return void 0;
119 |
120 | let resolution = this.camera.resolution;
121 |
122 | let x = (this.camera.x + (entity.position.x + entity.xMargin) * resolution) << 0;
123 | let y = (this.camera.y + (entity.position.y + entity.yMargin + entity.z) * resolution) << 0;
124 |
125 | let width = ((entity.size.x * entity.scale) * resolution) << 0;
126 | let height = ((entity.size.y * entity.scale) * resolution) << 0;
127 |
128 | if (entity.noise !== null) {
129 | this.renderEntityNoise(entity, x, y, width, height);
130 | }
131 |
132 | this.context.beginPath();
133 |
134 | this.context.strokeStyle = "red";
135 | this.context.lineWidth = (resolution / 2) << 0;
136 | this.context.strokeRect(
137 | x, y,
138 | width, height
139 | );
140 | this.context.stroke();
141 |
142 | this.context.closePath();
143 |
144 | this.renderSelectionText(entity, x, y);
145 |
146 | this.context.globalAlpha = .25;
147 |
148 | if (entity.collidable === true) {
149 | if (entity.collisionBox.length > 0) {
150 | this.renderEntityCollisionBox(entity, x, y);
151 | } else {
152 | this.context.fillStyle = "red";
153 | this.context.fillRect(
154 | x, y,
155 | width, height
156 | );
157 | this.context.fill();
158 | }
159 | }
160 |
161 | this.context.globalAlpha = 1.0;
162 |
163 | return void 0;
164 |
165 | }
166 |
167 | /**
168 | * Render entity noise radius
169 | * @param {Object} entity
170 | * @param {Number} x
171 | * @param {Number} y
172 | * @param {Number} width
173 | * @param {Number} height
174 | */
175 | export function renderEntityNoise(entity, x, y, width, height) {
176 |
177 | let resolution = this.camera.resolution;
178 |
179 | let radius = ((entity.noiseRadius - DIMENSION) || DIMENSION) * resolution;
180 |
181 | x += width / 2;
182 | y += height / 2;
183 |
184 | this.context.globalAlpha = .2;
185 |
186 | this.context.beginPath();
187 |
188 | this.context.fillStyle = "green";
189 | this.context.lineWidth = (resolution / 2) << 0;
190 | this.context.arc(x, y, radius, 0, 2 * Math.PI, false);
191 | this.context.fill();
192 |
193 | this.context.closePath();
194 |
195 | this.context.globalAlpha = 1.0;
196 |
197 | return void 0;
198 |
199 | }
200 |
201 | /**
202 | * Render entity collision box
203 | * @param {Object} entity
204 | * @param {Number} x
205 | * @param {Number} y
206 | */
207 | export function renderEntityCollisionBox(entity, x, y) {
208 |
209 | let collision = entity.collisionBox;
210 |
211 | let resolution = this.camera.resolution;
212 |
213 | let tile = 0;
214 |
215 | let ii = 0;
216 |
217 | let xx = 0;
218 | let yy = 0;
219 |
220 | let dim = DIMENSION * entity.scale * resolution;
221 |
222 | let width = (entity.width) / DIMENSION;
223 | let height = (entity.height) / DIMENSION;
224 |
225 | let length = width * height;
226 |
227 | for (; ii < length; ++ii) {
228 | tile = collision[yy + xx];
229 | if (tile === 1) {
230 | this.context.fillStyle = "red";
231 | this.context.fillRect(
232 | x + (xx * dim),
233 | y + ((yy / width) * dim),
234 | dim, dim
235 | );
236 | this.context.fill();
237 | }
238 | ++xx;
239 | if (xx >= width) {
240 | yy += width;
241 | xx = 0;
242 | }
243 | };
244 |
245 | return void 0;
246 |
247 | }
248 |
249 | /**
250 | * Render entity selection text
251 | * @param {Object} entity
252 | * @param {Number} x
253 | * @param {Number} y
254 | */
255 | export function renderSelectionText(entity, x, y) {
256 |
257 | let resolution = this.camera.resolution;
258 |
259 | let color = "red";
260 |
261 | let ln = .5 * resolution;
262 | let size = 2.5 * resolution;
263 |
264 | let xx = x;
265 | let yy = y - (ln * 1.25) - size;
266 |
267 | let decimals = 1;
268 |
269 | let txtX = `X: ${entity.position.x.toFixed(decimals)}`;
270 | let txtY = `Y: ${entity.position.y.toFixed(decimals)}`;
271 |
272 | this.instance.renderer.drawPixelText(
273 | txtX,
274 | xx, yy,
275 | size, ln,
276 | color
277 | );
278 |
279 | this.instance.renderer.drawPixelText(
280 | txtY,
281 | xx, yy += size,
282 | size, ln,
283 | color
284 | );
285 |
286 | return void 0;
287 |
288 | }
--------------------------------------------------------------------------------
/src/Engine/Editor/tileset.js:
--------------------------------------------------------------------------------
1 | import {
2 | FREE_CAMERA,
3 | Y_DEPTH_HACK,
4 | DIMENSION,
5 | MIN_SCALE, MAX_SCALE,
6 | PIXEL_SCALE
7 | } from "../../cfg";
8 |
9 | import { tileContainsImageData } from "../utils";
10 |
11 | export function updateTilesetPosition() {
12 | if (this.instance.currentMap !== null) {
13 | let width = this.instance.currentMap.texture.width;
14 | let height = this.instance.currentMap.texture.height;
15 | this.tileset.x = DIMENSION + this.instance.width - width;
16 | this.tileset.y = 0;
17 | }
18 | }
19 |
20 | /**
21 | * @param {Number} x
22 | * @param {Number} y
23 | */
24 | export function clickedInsideTileset(x, y) {
25 | let tileX = this.instance.editor.tileset.x;
26 | let tileY = this.instance.editor.tileset.y;
27 | let tileWidth = this.instance.currentMap.texture.width;
28 | let tileHeight = this.instance.currentMap.texture.height;
29 | return (
30 | x >= tileX && x <= tileX + tileWidth &&
31 | y >= tileY && y <= tileY + tileHeight
32 | );
33 | }
34 |
35 | /**
36 | * @param {Number} x
37 | * @param {Number} y
38 | */
39 | export function selectTile(x, y) {
40 |
41 | console.log(x, y);
42 |
43 | }
--------------------------------------------------------------------------------
/src/Engine/Entity/functions.js:
--------------------------------------------------------------------------------
1 | import {
2 | VOLUME
3 | } from "../../cfg";
4 |
5 | import MapEntity from "../Map/MapEntity";
6 |
7 | import Entity from "./index";
8 |
9 | /**
10 | * Add a new entity
11 | * @param {Object} entity
12 | * @export
13 | */
14 | export function addEntity(entity) {
15 |
16 | if (entity.isLocalPlayer) {
17 | entity.instance = this.instance;
18 | this.localEntity = entity;
19 | }
20 |
21 | if (entity.customOpacity() === false) {
22 | entity.fadeIn(1);
23 | }
24 |
25 | if (entity.noise) {
26 | if (entity.noise._audioNode !== void 0) {
27 | entity.noise._audioNode[0].gain.linearRampToValueAtTime(VOLUME.ENTITY_NOISE / 1e2, entity.noise._audioNode[0].context.currentTime);
28 | }
29 | }
30 |
31 | this.currentMap.entities.push(entity);
32 |
33 | }
34 |
35 | /**
36 | * Clone a entity
37 | * @param {Object} entity
38 | * @return {Object}
39 | */
40 | export function cloneEntity(entity) {
41 |
42 | let entities = this.instance.entities;
43 |
44 | let map = this.currentMap;
45 |
46 | let clone = null;
47 | let tmp = null;
48 |
49 | if (entity instanceof entities.Player) {
50 | tmp = new entities.Player({
51 | name: "undefined",
52 | map: entity.map,
53 | x: entity.x, y: entity.y,
54 | zIndex: entity.zIndex,
55 | sprite: entity.sprite,
56 | width: entity.width, height: entity.height,
57 | isLocalPlayer: false,
58 | collidable: entity.collidable,
59 | shadow: entity.hasShadow
60 | });
61 | if (entity.instance) {
62 | tmp.instance = entity.instance;
63 | }
64 | if (tmp.hasShadow) {
65 | tmp.shadow.x = entity.shadow.x;
66 | tmp.shadow.y = entity.shadow.y;
67 | }
68 | }
69 | else if (entity instanceof MapEntity) {
70 | tmp = map.objectTemplates[entity.name.toLowerCase()];
71 | } else {
72 | return void 0;
73 | }
74 |
75 | tmp.x = entity.x;
76 | tmp.y = entity.y;
77 | tmp.z = entity.z;
78 |
79 | if (entity instanceof MapEntity) {
80 | clone = new MapEntity(entity);
81 | if (entity.noise) {
82 | clone.noiseSrcPath = entity.noiseSrcPath;
83 | clone.noise = clone.noiseSrcPath;
84 | }
85 | if (entity.normal) {
86 | clone.normal = entity.normal;
87 | }
88 | } else {
89 | clone = tmp;
90 | }
91 |
92 | return (clone);
93 |
94 | }
95 |
96 | /**
97 | * Get a entity by its
98 | * matching property
99 | * @param {*} key
100 | * @param {String} prop
101 | * @return {Number}
102 | */
103 | export function getEntityByProperty(key, prop) {
104 |
105 | let ii = 0;
106 | let length = 0;
107 |
108 | length = this.currentMap.entities.length;
109 |
110 | for (; ii < length; ++ii) {
111 | if (this.currentMap.entities[ii][prop] === key) {
112 | return (this.currentMap.entities[ii]);
113 | }
114 | };
115 |
116 | return (-1);
117 |
118 | }
119 |
120 | /**
121 | * Remove a entity
122 | * @param {Object} entity
123 | */
124 | export function removeEntity(entity) {
125 |
126 | let noiseEntity = null;
127 |
128 | /** Clear entity selection */
129 | if (
130 | this.editor.entitySelection !== null &&
131 | entity.id === this.editor.entitySelection.id
132 | ) {
133 | this.editor.entitySelection = null;
134 | }
135 |
136 | if (entity.noise) {
137 | if (entity.noise._audioNode !== void 0) {
138 | entity.noise._audioNode[0].gain.linearRampToValueAtTime(.0, entity.noise._audioNode[0].context.currentTime);
139 | }
140 | }
141 |
142 | this.removeEntityFromArray(entity, this.currentMap.entities);
143 |
144 | }
145 |
146 | /**
147 | * Remove a entity from an array
148 | * @param {Object} entity
149 | * @param {Array} entities
150 | * @return {Object}
151 | */
152 | export function removeEntityFromArray(entity, array) {
153 |
154 | let ii = 0;
155 | let length = 0;
156 |
157 | let id = entity.id;
158 |
159 | let cache = null;
160 |
161 | length = array.length;
162 |
163 | for (; ii < length; ++ii) {
164 | if (array[ii].id === id) {
165 | cache = array[ii];
166 | array[ii] = null;
167 | array.splice(ii, 1);
168 | return (cache);
169 | }
170 | };
171 |
172 | return void 0;
173 |
174 | }
175 |
176 | /**
177 | * Get a entity
178 | * @param {Number} id
179 | * @return {Number}
180 | */
181 | export function getEntityById(id) {
182 |
183 | let property = "id";
184 |
185 | let index = 0;
186 |
187 | return (this.getEntityByProperty(id, property));
188 |
189 | }
190 |
191 | /**
192 | * Remove a entity by its id
193 | * @param {Number} id
194 | */
195 | export function removeEntityById(id) {
196 |
197 | let entity = null;
198 |
199 | if ((entity = this.getEntityByProperty(id, property)) === void 0) return void 0;
200 |
201 | this.removeEntity(entity);
202 |
203 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Parser/NodeList.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Numeric node types
3 | * @type {Object}
4 | */
5 | export let NODE_TYPES = {
6 | Program: 1,
7 | BlockStatement: 2,
8 | ReturnStatement: 3,
9 | Literal: 4,
10 | Identifier: 5,
11 | IfStatement: 6,
12 | BinaryExpression: 7,
13 | UnaryExpression: 8,
14 | AsyncStatement: 9,
15 | MemberExpression: 10,
16 | CallExpression: 11,
17 | AssignmentExpression: 12
18 | };
19 |
20 | /**
21 | * NODE_LIST
22 | * @class NODE_LIST
23 | * @export
24 | */
25 | export default class NODE_LIST {
26 |
27 | constructor() {}
28 |
29 | static get Program() {
30 | return (
31 | class Program {
32 | constructor() {
33 | this.type = NODE_TYPES.Program;
34 | this.body = [];
35 | }
36 | }
37 | );
38 | }
39 |
40 | static get BlockStatement() {
41 | return (
42 | class BlockStatement {
43 | constructor() {
44 | this.type = NODE_TYPES.BlockStatement;
45 | this.body = [];
46 | }
47 | }
48 | );
49 | }
50 |
51 | static get ReturnStatement() {
52 | return (
53 | class ReturnStatement {
54 | constructor() {
55 | this.type = NODE_TYPES.ReturnStatement;
56 | this.value = null;
57 | }
58 | }
59 | );
60 | }
61 |
62 | static get Literal() {
63 | return (
64 | class Literal {
65 | constructor() {
66 | this.type = NODE_TYPES.Literal;
67 | this.name = null;
68 | this.value = null;
69 | }
70 | }
71 | );
72 | }
73 |
74 | static get Identifier() {
75 | return (
76 | class Identifier {
77 | constructor() {
78 | this.type = NODE_TYPES.Identifier;
79 | this.name = null;
80 | }
81 | }
82 | );
83 | }
84 |
85 | static get IfStatement() {
86 | return (
87 | class IfStatement {
88 | constructor() {
89 | this.type = NODE_TYPES.IfStatement;
90 | this.condition = null;
91 | this.consequent = null;
92 | this.alternate = null;
93 | }
94 | }
95 | );
96 | }
97 |
98 | static get BinaryExpression() {
99 | return (
100 | class BinaryExpression {
101 | constructor() {
102 | this.type = NODE_TYPES.BinaryExpression;
103 | this.operator = null;
104 | this.left = null;
105 | this.right = null;
106 | }
107 | }
108 | );
109 | }
110 |
111 | static get UnaryExpression() {
112 | return (
113 | class UnaryExpression {
114 | constructor() {
115 | this.type = NODE_TYPES.UnaryExpression;
116 | this.operator = null;
117 | this.init = null;
118 | }
119 | }
120 | );
121 | }
122 |
123 | static get AsyncStatement() {
124 | return (
125 | class AsyncStatement {
126 | constructor() {
127 | this.type = NODE_TYPES.AsyncStatement;
128 | this.init = null;
129 | }
130 | }
131 | );
132 | }
133 |
134 | static get MemberExpression() {
135 | return (
136 | class MemberExpression {
137 | constructor() {
138 | this.type = NODE_TYPES.MemberExpression;
139 | this.object = null;
140 | this.property = null;
141 | }
142 | }
143 | );
144 | }
145 |
146 | static get CallExpression() {
147 | return (
148 | class CallExpression {
149 | constructor() {
150 | this.type = NODE_TYPES.CallExpression;
151 | this.callee = null;
152 | this.arguments = [];
153 | }
154 | }
155 | );
156 | }
157 |
158 | static get AssignmentExpression() {
159 | return (
160 | class AssignmentExpression {
161 | constructor() {
162 | this.type = NODE_TYPES.AssignmentExpression;
163 | this.operator = null;
164 | this.left = null;
165 | this.right = null;
166 | }
167 | }
168 | );
169 | }
170 |
171 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Parser/expression.js:
--------------------------------------------------------------------------------
1 | import NODE_LIST from "./NodeList";
2 |
3 | /**
4 | * Recursive object member parsing
5 | * Identifier *. *Identifier
6 | * @return {Object}
7 | */
8 | export function parseMemberExpression() {
9 |
10 | let ast = null;
11 | let tmp = null;
12 | let parent = null;
13 |
14 | ast = this.parseUnary();
15 |
16 | for (;this.accept("PERIOD") === true;) {
17 | parent = new NODE_LIST.MemberExpression();
18 | parent.object = ast;
19 | this.next();
20 | tmp = this.parseMemberExpression();
21 | parent.property = tmp;
22 | ast = parent;
23 | };
24 |
25 | return (ast);
26 |
27 | }
28 |
29 | /**
30 | * Recursive operator precedence based
31 | * binary expression parsing
32 | * @param {Number} id
33 | * @return {Object}
34 | */
35 | export function parseExpression(id) {
36 |
37 | let state = null;
38 | let ast = null;
39 | let parent = null;
40 | let tmp = null;
41 |
42 | state = this.precedence[id];
43 |
44 | ast = state === void 0 ? this.parseUnary() : this.parseExpression(id + 1);
45 |
46 | for (;this.acceptPrecedenceState(state) === true;) {
47 | parent = new NODE_LIST.BinaryExpression();
48 | parent.operator = this.node.name;
49 | parent.left = ast;
50 | this.next();
51 | tmp = (state === void 0 ? this.parseUnary() : this.parseExpression(id + 1));
52 | if (tmp === null) return (null);
53 | parent.right = tmp;
54 | ast = parent;
55 | if (this.accept("SEMICOLON") === true) {
56 | this.next();
57 | }
58 | };
59 |
60 | return (ast);
61 |
62 | }
63 |
64 | /**
65 | * Parse unary
66 | * @return {Object}
67 | */
68 | export function parseUnary() {
69 |
70 | let ast = null;
71 | let tmp = null;
72 |
73 | if (this.accept("SUB") === true) {
74 | ast = new NODE_LIST.BinaryExpression();
75 | ast.operator = this.node.name;
76 | tmp = new NODE_LIST.Literal();
77 | tmp.name = "NUMBER";
78 | tmp.value = 0;
79 | ast.right = tmp;
80 | this.next();
81 | if ((tmp = this.parseBase()) === null) return (null);
82 | ast.left = tmp;
83 | }
84 | else if (this.accept("NOT") === true) {
85 | ast = new NODE_LIST.UnaryExpression();
86 | ast.operator = this.node.name;
87 | this.next();
88 | ast.init = this.parseExpression(0);
89 | }
90 | else {
91 | if (this.accept("ADD") === true) {
92 | this.next();
93 | }
94 | if (!(ast = this.parseBase())) return (null);
95 | }
96 |
97 | return (ast);
98 |
99 | }
100 |
101 | /**
102 | * Parse base
103 | * @return {Object}
104 | */
105 | export function parseBase() {
106 |
107 | let ast = null;
108 |
109 | if (
110 | this.accept("TRUE") === true ||
111 | this.accept("FALSE") === true
112 | ) {
113 | ast = new NODE_LIST.Identifier();
114 | ast.name = this.node.value;
115 | this.next();
116 | return (ast);
117 | }
118 |
119 | if (this.accept("NUMBER") === true) {
120 | ast = new NODE_LIST.Literal();
121 | ast.name = this.node.name;
122 | ast.value = Number(this.node.value);
123 | this.next();
124 | return (ast);
125 | }
126 |
127 | if (this.accept("STRING") === true) {
128 | ast = new NODE_LIST.Literal();
129 | ast.name = this.node.name;
130 | ast.value = this.node.value;
131 | this.next();
132 | return (ast);
133 | }
134 |
135 | if (this.accept("LPAREN") === true) {
136 | this.next();
137 | ast = this.parseExpression(0);
138 | this.next();
139 | return (ast);
140 | }
141 |
142 | if (this.accept("IDENTIFIER") === true) {
143 | ast = new NODE_LIST.Identifier();
144 | ast.name = this.node.value;
145 | if (this.tokens[this.index + 1].name === "PERIOD") {
146 | this.next();
147 | let exp = this.parseMemberExpression();
148 | exp.object = ast;
149 | return (exp);
150 | }
151 | this.next();
152 | return (ast);
153 | }
154 |
155 | return (ast);
156 |
157 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Parser/index.js:
--------------------------------------------------------------------------------
1 | import NODE_LIST from "./NodeList";
2 |
3 | import * as pr from "./precedence";
4 |
5 | import * as parse from "./parse";
6 | import * as expression from "./expression";
7 |
8 | import { inherit } from "../../utils";
9 |
10 | /**
11 | * Parser
12 | * @class Parser
13 | * @export
14 | */
15 | export default class Parser {
16 |
17 | /**
18 | * @constructor
19 | */
20 | constructor() {
21 |
22 | /**
23 | * Token input
24 | * @type {Array}
25 | */
26 | this.tokens = null;
27 |
28 | /**
29 | * Token index
30 | * @type {Number}
31 | */
32 | this.index = 0;
33 |
34 | /**
35 | * Operator precedences
36 | * @type {Array}
37 | */
38 | this.precedence = pr.precedence;
39 |
40 | /**
41 | * node
42 | * @type {Object}
43 | * @getter
44 | */
45 | Object.defineProperty(this, "node", {
46 | get: function() {
47 | return (this.tokens[this.index]);
48 | }
49 | });
50 |
51 | }
52 |
53 | /**
54 | * Parse
55 | * @param {Array} tokens
56 | * @return {Object}
57 | */
58 | parse(tokens) {
59 |
60 | this.tokens = tokens;
61 |
62 | this.index = 0;
63 |
64 | let ast = new NODE_LIST.Program();
65 |
66 | let length = this.tokens.length;
67 |
68 | let block = null;
69 |
70 | for (;;) {
71 | if (this.index >= length) break;
72 | if ((block = this.parseBlock()) === null) continue;
73 | ast.body.push(block);
74 | };
75 |
76 | return (ast);
77 |
78 | }
79 |
80 | /**
81 | * Increase token index
82 | */
83 | next() {
84 | this.index++;
85 | }
86 |
87 | /**
88 | * Node type acception
89 | * @param {String} type
90 | * @return {Boolean}
91 | */
92 | accept(type) {
93 | if (this.node === void 0) return (false);
94 | if (this.node.name === type) {
95 | return (true);
96 | }
97 | return (false);
98 | }
99 |
100 | /**
101 | * Node type expection
102 | * @param {String} name
103 | */
104 | expect(name) {
105 | for (;true;) {
106 | if (this.node.name === name) {
107 | this.next();
108 | break;
109 | }
110 | this.next();
111 | }
112 | return void 0;
113 | }
114 |
115 | /**
116 | * Accept precedence state
117 | * @param {String} state
118 | * @return {Boolean}
119 | */
120 | acceptPrecedenceState(state) {
121 | return (
122 | state !== void 0 &&
123 | this.node !== void 0 &&
124 | state.indexOf(this.node.name) > -1
125 | );
126 | }
127 |
128 | }
129 |
130 | inherit(Parser, parse);
131 | inherit(Parser, expression);
--------------------------------------------------------------------------------
/src/Engine/Environment/Parser/parse.js:
--------------------------------------------------------------------------------
1 | import NODE_LIST from "./NodeList";
2 |
3 | /**
4 | * Parse a block
5 | * @return {Object}
6 | */
7 | export function parseBlock() {
8 |
9 | if (this.accept("IF") === true) {
10 | return (this.parseIfStatement());
11 | }
12 |
13 | if (this.accept("RETURN") === true) {
14 | return (this.parseReturnStatement());
15 | }
16 |
17 | if (this.accept("ATSIGN") === true) {
18 | return (this.parseAsyncStatement());
19 | }
20 |
21 | if (this.accept("IDENTIFIER") === true) {
22 | return (this.parseIdentifierRoute());
23 | }
24 |
25 | return (this.parseExpression(0));
26 |
27 | }
28 |
29 | /**
30 | * Parse async statement
31 | * Identifier () | = | ;
32 | * @return {Object}
33 | */
34 | export function parseAsyncStatement() {
35 |
36 | let ast = null;
37 |
38 | this.next();
39 | ast = new NODE_LIST.AsyncStatement();
40 | ast.init = this.parseBlock();
41 |
42 | return (ast);
43 |
44 | }
45 |
46 | /**
47 | * Is assignment or assignset
48 | * @return {Boolean}
49 | */
50 | export function isSet() {
51 | return (
52 | this.accept("ASSIGN") === true ||
53 | this.accept("ADDSET") === true ||
54 | this.accept("SUBSET") === true ||
55 | this.accept("MULSET") === true ||
56 | this.accept("DIVSET") === true ||
57 | this.accept("MODSET") === true
58 | );
59 | }
60 |
61 | /**
62 | * Parse identifier route
63 | * Identifier () | = | . | ;
64 | * @return {Object}
65 | */
66 | export function parseIdentifierRoute() {
67 |
68 | let ast = null;
69 |
70 | let tmp = this.parseExpression(0);
71 |
72 | /** Call expression */
73 | if (this.accept("LPAREN") === true) {
74 | ast = this.parseCallExpression();
75 | ast.callee = tmp;
76 | }
77 |
78 | /** Assignment expression */
79 | if (this.isSet() === true) {
80 | ast = this.parseAssignmentExpression();
81 | ast.left = tmp;
82 | }
83 |
84 | if (ast === null) {
85 | return (tmp);
86 | }
87 |
88 | return (ast);
89 |
90 | }
91 |
92 | /**
93 | * Parse call expression
94 | * MemberExpression () ;
95 | * @return {Object}
96 | */
97 | export function parseCallExpression() {
98 |
99 | let ast = null;
100 |
101 | ast = new NODE_LIST.CallExpression();
102 | ast.arguments = this.parseArguments();
103 |
104 | this.next();
105 |
106 | return (ast);
107 |
108 | }
109 |
110 | /**
111 | * Parse assignment expression
112 | * Expression = Expression
113 | * @return {Object}
114 | */
115 | export function parseAssignmentExpression() {
116 |
117 | let ast = null;
118 |
119 | ast = new NODE_LIST.AssignmentExpression();
120 | ast.left = this.parseExpression(0);
121 | ast.operator = this.node.name;
122 | this.next();
123 | ast.right = this.parseExpression(0);
124 |
125 | if (this.accept("SEMICOLON") === true) {
126 | this.next();
127 | }
128 |
129 | return (ast);
130 |
131 | }
132 |
133 | /**
134 | * Parse if statement
135 | * if ( Expression ) { Body } | { Body }
136 | * @return {Object}
137 | */
138 | export function parseIfStatement() {
139 |
140 | let ast = null;
141 |
142 | this.next();
143 |
144 | ast = new NODE_LIST.IfStatement();
145 | ast.condition = this.parseParentheseExpression();
146 | ast.consequent = this.parseBraceBody();
147 |
148 | if (this.accept("LBRACE") === true) {
149 | ast.alternate = this.parseBraceBody();
150 | }
151 |
152 | return (ast);
153 |
154 | }
155 |
156 | /**
157 | * Parse return statement
158 | * return ( Expression )
159 | * @return {Object}
160 | */
161 | export function parseReturnStatement() {
162 |
163 | let ast = null;
164 |
165 | this.next();
166 | ast = new NODE_LIST.ReturnStatement();
167 | ast.value = this.parseParentheseExpression();
168 | this.next();
169 |
170 | return (ast);
171 |
172 | }
173 |
174 | /**
175 | * Parse brace body
176 | * { Body }
177 | * @return {Object}
178 | */
179 | export function parseBraceBody() {
180 |
181 | let ast = null;
182 |
183 | this.expect("LBRACE");
184 | ast = this.parseBlockStatement();
185 | this.expect("RBRACE");
186 |
187 | return (ast);
188 |
189 | }
190 |
191 | /**
192 | * Parse block statement
193 | * @return {Object}
194 | */
195 | export function parseBlockStatement() {
196 |
197 | let ast = new NODE_LIST.BlockStatement();
198 |
199 | for (;true;) {
200 | if (this.accept("RBRACE") === true) break;
201 | ast.body.push(this.parseBlock());
202 | };
203 |
204 | return (ast);
205 |
206 | }
207 |
208 | /**
209 | * Parse arguments
210 | * [ , ]
211 | * @return {Array}
212 | */
213 | export function parseArguments() {
214 |
215 | let args = [];
216 |
217 | let tmp = null;
218 |
219 | this.expect("LPAREN");
220 |
221 | tmp = this.parseBlock();
222 |
223 | if (tmp !== null) {
224 | args.push(tmp);
225 | }
226 |
227 | for (;this.accept("COMMA") === true;) {
228 | this.next();
229 | if (this.accept("LPAREN") === true) {
230 | this.next();
231 | tmp = this.parseCallExpression();
232 | if (tmp !== null) {
233 | args.push(tmp);
234 | }
235 | } else {
236 | tmp = this.parseBlock();
237 | if (tmp !== null) {
238 | args.push(tmp);
239 | }
240 | }
241 | if (this.accept("RPAREN") === true) {
242 | this.next();
243 | break;
244 | }
245 | };
246 |
247 | if (args.length <= 1 && this.accept("RPAREN") === true) {
248 | this.next();
249 | }
250 |
251 | return (args);
252 |
253 | }
254 |
255 | /**
256 | * Parse parenthese expression
257 | * ( Expression )
258 | */
259 | export function parseParentheseExpression() {
260 |
261 | let ast = null;
262 |
263 | this.expect("LPAREN");
264 | ast = this.parseExpression(0);
265 | this.expect("RPAREN");
266 |
267 | return (ast);
268 |
269 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Parser/precedence.js:
--------------------------------------------------------------------------------
1 | export let precedence = [
2 | ["OR"],
3 | ["AND"],
4 | ["EQ", "NEQ"],
5 | ["LE", "LT", "GE", "GT"],
6 | ["ADD", "SUB"],
7 | ["MUL", "DIV", "MOD"]
8 | ];
--------------------------------------------------------------------------------
/src/Engine/Environment/Tester/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | NODE_LIST, NODE_TYPES
3 | } from "../Parser/NodeList";
4 |
5 | import * as tests from "./tests";
6 |
7 | import { inherit } from "../../utils";
8 |
9 | /**
10 | * Tester
11 | * @class Tester
12 | * @export
13 | */
14 | export default class Tester {
15 |
16 | /**
17 | * @constructor
18 | * @param {Object} tokenizer
19 | * @param {Object} parser
20 | * @param {Object} evaluator
21 | */
22 | constructor(tokenizer, parser, evaluator) {
23 |
24 | /**
25 | * Tokenizer instance ref
26 | * @type {Object}
27 | */
28 | this.tokenizer = tokenizer;
29 |
30 | /**
31 | * Parser instance ref
32 | * @type {Object}
33 | */
34 | this.parser = parser;
35 |
36 | /**
37 | * Evaluator instance ref
38 | * @type {Object}
39 | */
40 | this.evaluator = evaluator;
41 |
42 | this.setup();
43 |
44 | }
45 |
46 | /**
47 | * Test
48 | * @param {Object} key
49 | * @param {Function} resolve
50 | */
51 | test(key, resolve) {
52 |
53 | let ast = this.parser.parse(this.tokenizer.scan(key.expression));
54 |
55 | this.evaluator.evaluate(ast, this::function(result) {
56 | if (result !== key.expect) {
57 | console.log(this.parser.parse(this.tokenizer.scan(key.expression)));
58 | console.info(`%c ☓ ${key.name} :: ${key.expression} = ${result}`, "color: darkred;");
59 | resolve(false);
60 | }
61 | resolve(true);
62 | });
63 |
64 | return void 0;
65 |
66 | }
67 |
68 | /**
69 | * Setup
70 | */
71 | setup() {
72 |
73 | let failures = 0;
74 |
75 | for (let type in tests) {
76 | for (let key of tests[type]) {
77 | this.test(key, (result) => result === false && ++failures);
78 | };
79 | if (failures <= 0) {
80 | console.info(`%c ✓ ${type}`, "color: darkgreen;");
81 | }
82 | };
83 |
84 | if (failures) {
85 | console.error(`${failures} ${failures > 1 || failures === 0 ? "tests" : "test"} failed!`);
86 | } else {
87 | console.info("%cAll tests passed successfully!", "color: green;");
88 | }
89 |
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Tester/tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Mathematical tests
3 | * @type {Array}
4 | */
5 | export let Mathematical = [
6 | /** Logical */
7 | {
8 | name: "Not",
9 | expression: "!true",
10 | expect: false
11 | },
12 | {
13 | name: "Not",
14 | expression: "!!true",
15 | expect: true
16 | },
17 | {
18 | name: "Not",
19 | expression: "!!!false",
20 | expect: true
21 | },
22 | {
23 | name: "Logical And",
24 | expression: "1 && 2",
25 | expect: 2
26 | },
27 | {
28 | name: "Logical And",
29 | expression: "1 == 1 && 2 >= 2",
30 | expect: true
31 | },
32 | {
33 | name: "Logical And",
34 | expression: "1 != 1 && 2 < 2",
35 | expect: false
36 | },
37 | {
38 | name: "Logical Or",
39 | expression: "0 || 2",
40 | expect: 2
41 | },
42 | {
43 | name: "Logical Or",
44 | expression: "2 || 0",
45 | expect: 2
46 | },
47 | {
48 | name: "Logical Or",
49 | expression: "10 <= 2 || 5 < 2 || 50 / 2 == 25",
50 | expect: true
51 | },
52 | {
53 | name: "Logical And Or",
54 | expression: "5 == 1 || 1 == 2 || 5 == 5",
55 | expect: true
56 | },
57 | /** Comparisions */
58 | {
59 | name: "Equality",
60 | expression: "1 == 5",
61 | expect: false
62 | },
63 | {
64 | name: "Equality",
65 | expression: "5 == 5",
66 | expect: true
67 | },
68 | {
69 | name: "Inequality",
70 | expression: "1 != 5",
71 | expect: true
72 | },
73 | {
74 | name: "Inequality",
75 | expression: "5 != 5",
76 | expect: false
77 | },
78 | {
79 | name: "LW",
80 | expression: "5 < 10",
81 | expect: true
82 | },
83 | {
84 | name: "LW",
85 | expression: "10 < 5",
86 | expect: false
87 | },
88 | {
89 | name: "LW",
90 | expression: "5 < 5",
91 | expect: false
92 | },
93 | {
94 | name: "LE",
95 | expression: "5 <= 10",
96 | expect: true
97 | },
98 | {
99 | name: "LE",
100 | expression: "10 <= 5",
101 | expect: false
102 | },
103 | {
104 | name: "LE",
105 | expression: "5 <= 5",
106 | expect: true
107 | },
108 | {
109 | name: "GT",
110 | expression: "5 > 10",
111 | expect: false
112 | },
113 | {
114 | name: "GT",
115 | expression: "10 > 5",
116 | expect: true
117 | },
118 | {
119 | name: "GT",
120 | expression: "5 > 5",
121 | expect: false
122 | },
123 | {
124 | name: "GE",
125 | expression: "5 >= 10",
126 | expect: false
127 | },
128 | {
129 | name: "GE",
130 | expression: "10 >= 5",
131 | expect: true
132 | },
133 | {
134 | name: "GE",
135 | expression: "5 >= 5",
136 | expect: true
137 | },
138 | /** Binary operators */
139 | {
140 | name: "Add operator",
141 | expression: "5.5 + 2.5 + 7",
142 | expect: 15
143 | },
144 | {
145 | name: "Minus operator",
146 | expression: "5.5 - 2.5 - 7",
147 | expect: -4
148 | },
149 | {
150 | name: "Mul operator",
151 | expression: "5.5 * 2.5 * 7",
152 | expect: 96.25
153 | },
154 | {
155 | name: "Div operator",
156 | expression: "25 / 5 / 2.5",
157 | expect: 2
158 | },
159 | {
160 | name: "Mod operator",
161 | expression: "32 % 6",
162 | expect: 2
163 | },
164 | {
165 | name: "Complex",
166 | expression: "5 + 1 / 2 * 2 - ((2.5 * (6 + 4 * 2) / 5) * 5) - 1.5",
167 | expect: -30.5
168 | },
169 | /** Numbers */
170 | {
171 | name: "Negative integer",
172 | expression: "-77.5",
173 | expect: -77.5
174 | },
175 | /** Booleans */
176 | {
177 | name: "True bool",
178 | expression: "true",
179 | expect: true
180 | },
181 | {
182 | name: "False bool",
183 | expression: "false",
184 | expect: false
185 | }
186 | ];
--------------------------------------------------------------------------------
/src/Engine/Environment/Tokenizer/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tokenizer
3 | * @class Tokenizer
4 | * @export
5 | */
6 | export default class Tokenizer {
7 |
8 | /**
9 | * @constructor
10 | * @param {Object} tokens
11 | * @param {Array} ignore
12 | */
13 | constructor(tokens, ignore) {
14 |
15 | /**
16 | * Operand lookup map
17 | * @type {Object}
18 | */
19 | this.TOKEN_LIST = tokens || {};
20 |
21 | /**
22 | * Ignore token list
23 | * @type {Array}
24 | */
25 | this.IGNORE_LIST = ignore || [];
26 |
27 | /**
28 | * Stream buffer
29 | * @type {String}
30 | */
31 | this.buffer = null;
32 |
33 | /**
34 | * Stream index
35 | * @type {Number}
36 | */
37 | this.index = 0;
38 |
39 | }
40 |
41 | /**
42 | * Is digit
43 | * @param {Number} c
44 | * @return {Boolean}
45 | */
46 | isDigit(c) {
47 | return (
48 | c >= 48 && c <= 57
49 | );
50 | }
51 |
52 | /**
53 | * Is alpha
54 | * @param {Number} c
55 | * @return {Boolean}
56 | */
57 | isAlpha(c) {
58 | return (
59 | c > 64 && c < 91 ||
60 | c > 96 && c < 123
61 | );
62 | }
63 |
64 | /**
65 | * Is alpha digit
66 | * @param {Number} c
67 | * @return {Boolean}
68 | */
69 | isAlphaDigit(c) {
70 | return (
71 | c > 47 && c < 58 ||
72 | c > 64 && c < 91 ||
73 | c > 96 && c < 123 ||
74 | c === 95
75 | );
76 | }
77 |
78 | /**
79 | * Is string
80 | * @param {Number} c
81 | * @return {Boolean}
82 | */
83 | isString(c) {
84 | return (
85 | c === 34 || c === 39
86 | );
87 | }
88 |
89 | /**
90 | * Token validation
91 | * @param {Object} token
92 | * @return {Boolean}
93 | */
94 | isValidToken(token) {
95 | return (
96 | token.name !== void 0 &&
97 | this.IGNORE_LIST.indexOf(token.name) <= -1
98 | );
99 | }
100 |
101 | /**
102 | * Token name validation
103 | * @param {String} name
104 | * @return {Boolean}
105 | */
106 | isIgnoredName(name) {
107 | return (
108 | this.IGNORE_LIST.indexOf(name) <= -1
109 | );
110 | }
111 |
112 | /**
113 | * Creates number token
114 | * @return {Object}
115 | */
116 | readNumber() {
117 |
118 | let end = this.index + 1;
119 |
120 | let c = null;
121 |
122 | for (; end < this.length; ++end) {
123 | c = this.buffer.charAt(end).charCodeAt(0);
124 | /** Also check for floating numbers */
125 | if (c !== 46 && this.isDigit(c) === false) break;
126 | };
127 |
128 | let value = this.buffer.slice(this.index, end);
129 |
130 | this.index = end;
131 |
132 | return ({
133 | name: "NUMBER",
134 | value: value
135 | });
136 |
137 | }
138 |
139 | /**
140 | * Creates identifier or keyword token
141 | * @return {Object}
142 | */
143 | readIdentifier() {
144 |
145 | let end = this.index + 1;
146 |
147 | for (; end < this.length && this.isAlphaDigit(this.buffer.charAt(end).charCodeAt(0)) === true; ++end) {};
148 |
149 | let value = this.buffer.slice(this.index, end);
150 |
151 | this.index = end;
152 |
153 | /** Keyword */
154 | if (this.TOKEN_LIST[value] !== void 0) {
155 | return ({
156 | name: this.TOKEN_LIST[value],
157 | value: value
158 | });
159 | /** Identifier */
160 | } else {
161 | return ({
162 | name: "IDENTIFIER",
163 | value: value
164 | });
165 | }
166 |
167 | }
168 |
169 | /**
170 | * Creates string token
171 | * @return {Object}
172 | */
173 | readString() {
174 |
175 | let end = this.buffer.indexOf("'", this.index + 1);
176 |
177 | if (end === -1) {
178 | end = this.buffer.indexOf('"', this.index + 1);
179 | if (end === -1) throw new Error(`Unexpected quote at ${ this.index }!`);
180 | }
181 |
182 | let token = {
183 | name: "STRING",
184 | value: this.buffer.slice(this.index, end + 1)
185 | };
186 |
187 | this.index = end + 1;
188 |
189 | return (token);
190 |
191 | }
192 |
193 | readNegativeNumber() {
194 |
195 | let node = null;
196 |
197 | node = this.readNumber();
198 |
199 | node.value = "-" + node.value;
200 |
201 | return (node);
202 |
203 | }
204 |
205 | /**
206 | * Read sign
207 | * @return {Object}
208 | */
209 | readSign() {
210 |
211 | let c = null;
212 |
213 | let code = 0;
214 |
215 | let name = null;
216 |
217 | let value = "";
218 |
219 | for (;;) {
220 | c = this.buffer.charAt(this.index);
221 | code = c.charCodeAt(0);
222 | if (this.isDigit(code) === true) {
223 | if (value === "-") {
224 | return (this.readNegativeNumber());
225 |
226 | }
227 | }
228 | value += c;
229 | if (this.TOKEN_LIST[value] === void 0) break;
230 | this.index++;
231 | name = this.TOKEN_LIST[value];
232 | if (this.index > this.length) break;
233 | };
234 |
235 | return ({
236 | name: name,
237 | value: value
238 | });
239 |
240 | }
241 |
242 | /**
243 | * Lexical analysis
244 | * @param {String} stream
245 | * @return {Array}
246 | */
247 | scan(stream) {
248 |
249 | this.index = 0;
250 | this.vIndex = 0;
251 | this.buffer = stream;
252 | this.length = this.buffer.length;
253 |
254 | let c = null;
255 | let op = null;
256 | let cCode = 0;
257 | let token = null;
258 |
259 | let tokens = [];
260 |
261 | for (;;) {
262 |
263 | if (!(c = this.buffer.charAt(this.index)) || this.index >= this.length) break;
264 |
265 | cCode = c.charCodeAt(0);
266 |
267 | if ((op = this.TOKEN_LIST[c]) !== void 0) {
268 | token = this.readSign();
269 | if (this.isValidToken(token) === true) tokens.push(token);
270 | }
271 | if (this.isDigit(cCode) === true) {
272 | token = this.readNumber();
273 | if (this.isValidToken(token) === true) tokens.push(token);
274 | }
275 | if (this.isAlpha(cCode) === true) {
276 | token = this.readIdentifier();
277 | if (this.isValidToken(token) === true) tokens.push(token);
278 | }
279 | if (this.isString(cCode) === true) {
280 | token = this.readString();
281 | if (this.isValidToken(token) === true) tokens.push(token);
282 | }
283 |
284 | };
285 |
286 | return (tokens);
287 |
288 | }
289 |
290 | }
--------------------------------------------------------------------------------
/src/Engine/Environment/Tokenizer/tokens.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tokens to match
3 | * @type {Object}
4 | */
5 | export const TOKENS = {
6 | /** Punctuators */
7 | "(": "LPAREN",
8 | ")": "RPAREN",
9 | "[": "LBRACK",
10 | "]": "RBRACK",
11 | "{": "LBRACE",
12 | "}": "RBRACE",
13 | ":": "COLON",
14 | ";": "SEMICOLON",
15 | ".": "PERIOD",
16 | "?": "CONDITIONAL",
17 | "$": "DOLLAR",
18 | "@": "ATSIGN",
19 | /** Logical operators */
20 | "!": "NOT",
21 | "||": "OR",
22 | "&&": "AND",
23 | /** Binary operators */
24 | ",": "COMMA",
25 | "+": "ADD",
26 | "-": "SUB",
27 | "*": "MUL",
28 | "/": "DIV",
29 | "%": "MOD",
30 | "^": "POW",
31 | "+=": "ADDSET",
32 | "-=": "SUBSET",
33 | "*=": "MULSET",
34 | "/=": "DIVSET",
35 | "%=": "MODSET",
36 | /** Compare operators */
37 | "<": "LT",
38 | "<=": "LE",
39 | ">": "GT",
40 | ">=": "GE",
41 | "==": "EQ",
42 | "!=": "NEQ",
43 | /** Assignment operators */
44 | "=": "ASSIGN",
45 | /** Bitwise operators */
46 | "~": "BIT_NOT",
47 | "|": "BIT_OR",
48 | "&": "BIT_AND",
49 | /** Literals */
50 | "null": "NULL",
51 | "true": "TRUE",
52 | "false": "FALSE",
53 | /** Keywords */
54 | "if": "IF",
55 | "else": "ELSE",
56 | "while": "WHILE",
57 | "do": "DO",
58 | "for": "FOR",
59 | "function": "FUNCTION",
60 | "var": "VAR",
61 | "const": "CONST",
62 | "return": "RETURN",
63 | " ": "BLANK",
64 | "\t": "TAB",
65 | "\n": "NL",
66 | "\r": "X",
67 | "\f": "X1",
68 | "\v": "X2"
69 | };
70 |
71 | /**
72 | * Tokens to ignore
73 | * @type {Array}
74 | */
75 | export let IGNORE = [
76 | "BLANK", "TAB", "NL", "X", "X1", "X2"
77 | ];
--------------------------------------------------------------------------------
/src/Engine/Environment/index.js:
--------------------------------------------------------------------------------
1 | import * as tokens from "./Tokenizer/tokens";
2 |
3 | import Tester from "./Tester/";
4 | import Tokenizer from "./Tokenizer/";
5 | import Parser from "./Parser/";
6 | import Evaluator from "./Evaluator/";
7 |
8 | /**
9 | * Environment
10 | * @class Environment
11 | * @export
12 | */
13 | export default class Environment {
14 |
15 | /**
16 | * @constructor
17 | * @param {Object} instance
18 | */
19 | constructor(instance) {
20 |
21 | /**
22 | * Game instance ref
23 | * @type {Object}
24 | */
25 | this.instance = instance;
26 |
27 | /**
28 | * Global flags
29 | * @type {Object}
30 | */
31 | this.FLAGS = {
32 | GOT_STARTER_PKMN: false,
33 | COUNTER: 0
34 | };
35 |
36 | /**
37 | * Tokenizer instance
38 | * @type {Object}
39 | */
40 | this.tokenizer = new Tokenizer(tokens.TOKENS, tokens.IGNORE);
41 |
42 | /**
43 | * Parser instance
44 | * @type {Object}
45 | */
46 | this.parser = new Parser();
47 |
48 | /**
49 | * Evaluator instance
50 | * @type {Object}
51 | */
52 | this.evaluator = new Evaluator(this);
53 |
54 | /**
55 | * Tester instance
56 | * @type {Object}
57 | */
58 | this.tester = new Tester(
59 | this.tokenizer,
60 | this.parser,
61 | this.evaluator
62 | );
63 |
64 | console.log(this.FLAGS);
65 |
66 | }
67 |
68 | /**
69 | * Run a stream
70 | * @param {Object} local
71 | * @param {Object} trigger
72 | * @param {String} stream
73 | */
74 | run(local, trigger, stream) {
75 |
76 | this.evaluator.setTriggerScope(local);
77 | this.evaluator.setGlobalScope(trigger);
78 |
79 | let tokens = this.tokenizer.scan(stream);
80 |
81 | let ast = this.parser.parse(tokens);
82 |
83 | this.evaluator.evaluate(ast, function(result) {
84 | console.log("Ok!", result);
85 | });
86 |
87 | }
88 |
89 | }
--------------------------------------------------------------------------------
/src/Engine/Input/Mouse.js:
--------------------------------------------------------------------------------
1 | import {
2 | uHash
3 | } from "../utils";
4 |
5 | /**
6 | * Mouse
7 | * @class Mouse
8 | * @export
9 | */
10 | export default class Mouse {
11 |
12 | /**
13 | * @constructor
14 | * @param {Array} events
15 | */
16 | constructor(events) {
17 |
18 | return (this);
19 |
20 | }
21 |
22 | /**
23 | * Register a mouse event
24 | * @param {Object} event
25 | */
26 | registerEvent(event, root) {
27 |
28 | let fire = null;
29 |
30 | let events = event.name.split("|");
31 |
32 | for (let ev of events) {
33 | if (ev === "mousewheel") {
34 | window.addWheelListener(document.body, e => root::event.fire(e));
35 | } else {
36 | window.addEventListener(ev, e => root::event.fire(e), false);
37 | }
38 | };
39 |
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/src/Engine/Input/index.js:
--------------------------------------------------------------------------------
1 | import keyboard from "./Keyboard";
2 | import mouse from "./Mouse";
3 |
4 | /**
5 | * Input
6 | * @class Input
7 | * @export
8 | */
9 | export default class Input {
10 |
11 | /**
12 | * @constructor
13 | */
14 | constructor(events, instance) {
15 |
16 | this.instance = instance;
17 |
18 | this.events = events;
19 |
20 | this.KeyBoard = new keyboard();
21 | this.Mouse = new mouse();
22 |
23 | this.registerKeys();
24 | this.registerMouse();
25 | this.registerGlobal();
26 |
27 | }
28 |
29 | /**
30 | * Register keys
31 | */
32 | registerKeys() {
33 |
34 | if (this.events.keys === void 0) return void 0;
35 |
36 | for (let key of this.events.keys) {
37 | this.KeyBoard.registerKey(
38 | key,
39 | this.instance.engine.controller::key.fire,
40 | key.leave instanceof Function ? this.instance.engine.controller::key.leave : void 0
41 | );
42 | };
43 |
44 | }
45 |
46 | /**
47 | * Register mouse
48 | */
49 | registerMouse() {
50 |
51 | if (this.events.mouse === void 0) return void 0;
52 |
53 | for (let ev of this.events.mouse) {
54 | this.Mouse.registerEvent(ev, this.instance.engine.controller);
55 | };
56 |
57 | }
58 |
59 | /**
60 | * Register globals
61 | */
62 | registerGlobal() {
63 |
64 | if (this.events.global === void 0) return void 0;
65 |
66 | for (let ev of this.events.global) {
67 | this.registerGlobalEvent(ev, this.instance.engine.controller);
68 | };
69 |
70 | }
71 |
72 | /**
73 | * Register event
74 | * @param {Object} event
75 | */
76 | registerGlobalEvent(event) {
77 |
78 | window.addEventListener(event.name, this.instance.engine.controller::event.fire, false);
79 |
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/src/Engine/Language/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | DEFAULT_LANG
3 | } from "../../cfg";
4 |
5 | import {
6 | ajax as $GET
7 | } from "../utils";
8 |
9 | /**
10 | * Language
11 | * @class Language
12 | * @export
13 | */
14 | export default class Language {
15 |
16 | /**
17 | * @param {Function} resolve
18 | * @constructor
19 | */
20 | constructor(resolve) {
21 |
22 | /**
23 | * Language packets
24 | * @type {Object}
25 | */
26 | this.packets = {};
27 |
28 | /**
29 | * String base
30 | * @type {String}
31 | */
32 | this.strBase = "s_";
33 |
34 | /**
35 | * Active packet ref
36 | * @type {Object}
37 | */
38 | this.activePacket = null;
39 |
40 | /**
41 | * Default language
42 | * @type {String}
43 | */
44 | this.defaultLanguage = DEFAULT_LANG;
45 |
46 | /**
47 | * Download default lang packet
48 | * Download navigators lang packet
49 | * Auto switch to navigators lang
50 | */
51 | this.downloadPacket(this.defaultLanguage, () => {
52 | this.switch(this.getNavigatorLanguage(), resolve);
53 | });
54 |
55 | }
56 |
57 | /**
58 | * Get navigators language
59 | * @return {String}
60 | */
61 | getNavigatorLanguage() {
62 |
63 | let lang = null;
64 |
65 | if (navigator.languages) {
66 | lang = navigator.languages[0];
67 | } else if (navigator.userLanguage) {
68 | lang = navigator.userLanguage;
69 | } else {
70 | lang = navigator.language;
71 | }
72 |
73 | return (lang.split("-")[0]);
74 |
75 | }
76 |
77 | /**
78 | * Get language dependant string
79 | * @param {String} key
80 | * @return {String}
81 | */
82 | get(key) {
83 | return (
84 | this.activePacket[key] !== void 0 ? this.activePacket[key] :
85 | this.packets[this.defaultLanguage][key] !== void 0 ? this.packets[this.defaultLanguage][key] :
86 | "undefined"
87 | );
88 | }
89 |
90 | /**
91 | * Download language packet
92 | * @param {String} name
93 | * @param {Function} resolve
94 | */
95 | downloadPacket(name, resolve) {
96 |
97 | if (this.packets[name] !== void 0) {
98 | return resolve();
99 | }
100 |
101 | let path = "assets/i18n/";
102 |
103 | try {
104 | $GET(`${path + name}.json`).then(
105 | JSON.parse
106 | ).then(this::function(data) {
107 | this.packets[name] = data;
108 | resolve();
109 | });
110 | } catch(e) {
111 | console.error(`${name} is a invalid language packet!`);
112 | resolve();
113 | }
114 |
115 | return void 0;
116 |
117 | }
118 |
119 | /**
120 | * Switch to another language packet
121 | * @param {String} name
122 | * @param {Function} resolve
123 | */
124 | switch(name, resolve) {
125 |
126 | if (this.packets[name] !== void 0) {
127 | this.activePacket = this.packets[name];
128 | return (resolve && resolve());
129 | }
130 |
131 | this.downloadPacket(name, () => {
132 | if (this.packets[name] !== void 0) {
133 | this.activePacket = this.packets[name];
134 | } else {
135 | this.activePacket = this.packets[this.defaultLanguage];
136 | }
137 |
138 | return (resolve && resolve());
139 | });
140 |
141 | return void 0;
142 |
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/src/Engine/Map/MapEntity.js:
--------------------------------------------------------------------------------
1 | import { DIMENSION } from "../../cfg";
2 |
3 | import Entity from "../Entity";
4 |
5 | /**
6 | * MapEntity
7 | * @class MapEntity
8 | * @export
9 | */
10 | export default class MapEntity extends Entity {
11 |
12 | /**
13 | * @param {Object} obj
14 | * @constructor
15 | */
16 | constructor(obj) {
17 |
18 | super(obj);
19 |
20 | this.zIndex = obj.zIndex === void 0 ? 1 : obj.zIndex;
21 |
22 | this.frames = [0, 0];
23 |
24 | this.facing = 0;
25 |
26 | this.opacity = obj.opacity === void 0 ? 1.0 : obj.opacity;
27 |
28 | this.scale = obj.scale === void 0 ? 1.0 : obj.scale;
29 |
30 | this.frame = obj.frame === void 0 ? 1 : obj.frame;
31 |
32 | this.reversed = [0, 0];
33 |
34 | this.reverseShadow = [0, 0];
35 |
36 | if (obj.collisionBox !== void 0) {
37 | this.collisionBox = obj.collisionBox;
38 | }
39 |
40 | return (this);
41 |
42 | }
43 |
44 | /**
45 | * Get frame index
46 | * @return {Number}
47 | */
48 | getFrameIndex() {
49 | return (0);
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/src/Engine/Map/events.js:
--------------------------------------------------------------------------------
1 | import { DIMENSION } from "../../cfg";
2 | import math from "../../Math";
3 |
4 | /**
5 | * Trigger events
6 | * @param {Object} entity
7 | * @param {Object} parent
8 | * @param {String} event
9 | */
10 | export function triggerEvent(entity, parent, event) {
11 |
12 | let cmd = entity[event];
13 |
14 | /** Collide event */
15 | if (cmd !== null) {
16 | /** JavaScript API */
17 | if (cmd.JavaScript !== void 0) {
18 | cmd.JavaScript.bind(entity)(parent, this);
19 | }
20 | /** EngelScript API */
21 | if (cmd.EngelScript !== void 0) {
22 | this.instance.environment.run(
23 | parent, entity,
24 | cmd.EngelScript
25 | );
26 | } else {
27 | if (cmd.JavaScript === void 0) {
28 | if (cmd instanceof Function) {
29 | cmd.bind(entity)(parent, this);
30 | }
31 | }
32 | }
33 | }
34 |
35 | return void 0;
36 |
37 | }
38 |
39 | /**
40 | * Action trigger
41 | * @param {Object} position
42 | * @param {Object} entity
43 | */
44 | export function actionTrigger(position, entity) {
45 |
46 | let entities = this.entities;
47 |
48 | let ii = 0;
49 | let length = entities.length;
50 |
51 | let event = null;
52 |
53 | let id = entity.id;
54 |
55 | let x = position.x << 0;
56 | let y = position.y << 0;
57 |
58 | for (; ii < length; ++ii) {
59 | event = entities[ii];
60 | if (event.id === id) continue;
61 | if (event.x << 0 === x && event.y << 0 === y) {
62 | this.triggerEvent(event, entity, "onAction");
63 | }
64 | };
65 |
66 | return void 0;
67 |
68 | }
69 |
70 | /**
71 | * Obstacle check
72 | * @param {Object} entity
73 | * @param {Number} dir
74 | * @return {Boolean}
75 | */
76 | export function isObstacle(entity, dir) {
77 |
78 | let position = math.getTilePosition(entity.x << 0, entity.y << 0, dir << 0);
79 |
80 | return (
81 | this.collisionLayer.data[(position.y << 0) / DIMENSION][(position.x << 0) / DIMENSION] === 0 ||
82 | this.isEntityCollidable(entity, position.x, position.y) === true
83 | );
84 |
85 | }
86 |
87 | /**
88 | * Entity collidable check
89 | * @param {Object} entity
90 | * @param {Number} x
91 | * @param {Number} y
92 | * @return {Boolean}
93 | */
94 | export function isEntityCollidable(entity, x, y) {
95 |
96 | let entities = this.entities;
97 |
98 | let ii = 0;
99 | let length = entities.length;
100 |
101 | let intersection = false;
102 |
103 | let collide = false;
104 |
105 | let id = entity.id;
106 |
107 | let event = null;
108 |
109 | for (; ii < length; ++ii) {
110 | event = entities[ii];
111 | if (event.id === id) continue;
112 | intersection = math.linearIntersect(
113 | event.position.x << 0, event.position.y << 0,
114 | ((math.roundTo(event.size.x, DIMENSION) * event.scale) + event.xMargin) - DIMENSION,
115 | ((math.roundTo(event.size.y, DIMENSION) * event.scale) + event.yMargin) - DIMENSION,
116 | x, y,
117 | 1
118 | );
119 | /** Entity is a collidable */
120 | if (event.collidable === true) {
121 | /** Collision box */
122 | if (event.collisionBox.length > 0) {
123 | if (this.collidesWithCollisionBox(event, x, y) === true) {
124 | this.triggerEvent(event, entity, "onCollide");
125 | collide = true;
126 | }
127 | /** Cubic based collision */
128 | } else {
129 | if (intersection === true) {
130 | this.triggerEvent(event, entity, "onCollide");
131 | collide = true;
132 | }
133 | }
134 | } else {
135 | if (
136 | math.linearIntersect(
137 | event.position.x << 0, event.position.y << 0,
138 | ((math.roundTo(event.size.x, DIMENSION) * event.scale) + event.xMargin) - DIMENSION,
139 | ((math.roundTo(event.size.y, DIMENSION) * event.scale) + event.yMargin) - DIMENSION,
140 | entity.position.x << 0, entity.position.y << 0,
141 | 1
142 | ) === true
143 | ) {
144 | this.triggerEvent(event, entity, "onLeave");
145 | }
146 | if (intersection === true) {
147 | this.triggerEvent(event, entity, "onEnter");
148 | }
149 | }
150 | };
151 |
152 | return (collide);
153 |
154 | }
155 |
156 | /**
157 | * Collides with a entity collision box
158 | * @param {Number} entity
159 | * @param {Number} x
160 | * @param {Number} y
161 | * @return {Boolean}
162 | */
163 | export function collidesWithCollisionBox(entity, x, y) {
164 |
165 | let tile = 0;
166 |
167 | let ii = 0;
168 |
169 | let xx = 0;
170 | let yy = 0;
171 |
172 | let dim = DIMENSION * entity.scale;
173 |
174 | let width = (math.roundTo(entity.size.x, DIMENSION) + entity.xMargin) / DIMENSION;
175 | let height = (math.roundTo(entity.size.y, DIMENSION) + entity.yMargin) / DIMENSION;
176 |
177 | let length = width * height;
178 |
179 | let eX = entity.position.x << 0;
180 | let eY = entity.position.y << 0;
181 |
182 | for (; ii < length; ++ii) {
183 | tile = entity.collisionBox[yy + xx];
184 | if (tile === 1) {
185 | if (
186 | eX + (xx * dim) === x &&
187 | eY + ((yy / width) * dim) === y
188 | ) {
189 | return (true);
190 | }
191 | }
192 | ++xx;
193 | if (xx >= width) {
194 | yy += width;
195 | xx = 0;
196 | }
197 | };
198 |
199 | return (false);
200 |
201 | }
--------------------------------------------------------------------------------
/src/Engine/Map/functions.js:
--------------------------------------------------------------------------------
1 | import {
2 | ajax as $GET,
3 | getPath as getPath
4 | } from "../utils";
5 |
6 | import math from "../../Math";
7 |
8 | import Audio from "../Audio";
9 |
10 | import {
11 | DIMENSION,
12 | BGM,
13 | VOLUME
14 | } from "../../cfg";
15 |
16 | import Map from "../Map";
17 |
18 | /**
19 | * Add a new map
20 | * @param {String} path
21 | * @param {Function} resolve
22 | */
23 | export function addMap(path, resolve) {
24 |
25 | $GET(path).then(
26 | JSON.parse
27 | ).then(this::function(data) {
28 | data.path = getPath(path);
29 | let map = new Map(this, data, this::function() {
30 | map.instance = this;
31 | this.maps[map.name] = map;
32 | this.currentMap = this.maps[map.name];
33 | if (this.editor !== null) {
34 | this.editor.map = this.currentMap;
35 | }
36 | if (map.settings.music && BGM) {
37 | Audio.playSong(map.settings.music, VOLUME.MUSIC, true);
38 | }
39 | /** Map name notification */
40 | //this.notify(map, map.name + map.name + map.name + map.name, "MapMessage");
41 | return (resolve());
42 | });
43 | });
44 |
45 | }
46 |
47 | /**
48 | * Measure distance between entity and camera
49 | * @param {Object} entity
50 | * @param {Object} camera
51 | * @return {Object}
52 | */
53 | export function distance(entity, camera) {
54 |
55 | let distance = math.distance(
56 | entity.position.x + (entity.size.x / 2) + entity.xMargin,
57 | entity.position.y + (entity.size.y / 2) + entity.position.z + entity.yMargin,
58 | (((camera.size.x / 2) - camera.position.x) / camera.resolution),
59 | (((camera.size.y / 2) - camera.position.y) / camera.resolution)
60 | );
61 |
62 | distance.x /= 1e2;
63 | distance.y /= 1e2;
64 |
65 | return (distance);
66 |
67 | }
--------------------------------------------------------------------------------
/src/Engine/Path/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION
3 | } from "../../cfg";
4 |
5 | import path from "../../libs/astar";
6 |
7 | /**
8 | * Path
9 | * @class Path
10 | * @export
11 | */
12 | export default class Path {
13 |
14 | /**
15 | * @param {Object} instance
16 | * @constructor
17 | */
18 | constructor(instance) {
19 |
20 | /**
21 | * Instance ref
22 | * @type {Object}
23 | */
24 | this.instance = instance;
25 |
26 | /**
27 | * Grid
28 | * @type {Object}
29 | */
30 | this.grid = new path.Graph(this.instance.collisionLayer.data);
31 |
32 | }
33 |
34 | /**
35 | * Get shortest path
36 | * @param {Number} x1
37 | * @param {Number} y1
38 | * @param {Number} x2
39 | * @param {Number} y2
40 | * @return {Array}
41 | */
42 | getShortestPath(x1, y1, x2, y2) {
43 |
44 | return (
45 | path.astar.search(
46 | this.grid,
47 | this.grid.grid[(x1 << 0) / DIMENSION][(y1 << 0) / DIMENSION],
48 | this.grid.grid[(x2 << 0) / DIMENSION][(y2 << 0) / DIMENSION]
49 | )
50 | );
51 |
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/Engine/Renderer/debug.js:
--------------------------------------------------------------------------------
1 | import { TextureCache } from "../utils";
2 | import {
3 | DIMENSION,
4 | GOD_MODE, EDIT_MODE,
5 | FREE_CAMERA,
6 | SHADOW_Y
7 | } from "../../cfg";
8 |
9 | /**
10 | * Render debug scene
11 | */
12 | export function renderDebugScene() {
13 |
14 | let color = '#313131';
15 |
16 | let get = (str) => this.instance.getUpperCaseString(str);
17 |
18 | this.drawPixelText(
19 | `${get("Width")}: ${this.width} ${get("Height")}: ${this.height}`,
20 | 15, 30,
21 | 20, 1.5,
22 | color
23 | );
24 |
25 | this.drawPixelText(
26 | `${get("Dimension")}: ${DIMENSION}`,
27 | 15, 60,
28 | 20, 1.5,
29 | color
30 | );
31 |
32 | this.drawPixelText(
33 | `${get("X")}: ${this.camera.x.toFixed(2)} ${get("Y")}: ${this.camera.y.toFixed(2)}`,
34 | 15, 90,
35 | 20, 1.5,
36 | color
37 | );
38 |
39 | this.drawPixelText(
40 | `${get("Delta")}: ${this.delta * 1E3} ${get("MS")}`,
41 | 15, 120,
42 | 20, 1.5,
43 | color
44 | );
45 |
46 | this.drawPixelText(
47 | `${get("Scale")}: ${this.camera.resolution.toFixed(6)}`,
48 | 15, 150,
49 | 20, 1.5,
50 | color
51 | );
52 |
53 | if (this.instance.currentMap !== null) {
54 | this.drawPixelText(
55 | `${get("Entities")}: ${this.instance.currentMap.entities.length}`,
56 | 15, 180,
57 | 20, 1.5,
58 | color
59 | );
60 | }
61 |
62 | let ii = 0;
63 | let kk = 0;
64 |
65 | let length = 0;
66 |
67 | if (this.instance.currentMap !== null) {
68 |
69 | let entities = this.instance.currentMap.entities;
70 |
71 | length = entities.length;
72 |
73 | for (; ii < length; ++ii) {
74 | if (this.instance.camera.isInView(
75 | entities[ii].position.x, entities[ii].position.y,
76 | entities[ii].size.x, (entities[ii].size.y * 2) + entities[ii].shadowY
77 | ) && ++kk) {}
78 | };
79 |
80 | }
81 |
82 | this.drawPixelText(
83 | `${get("EntitiesInView")}: ${kk}`,
84 | 15, 210,
85 | 20, 1.5,
86 | color
87 | );
88 |
89 | this.drawPixelText(
90 | `${get("Textures")}: ${Object.keys(TextureCache).length}`,
91 | 15, 240,
92 | 20, 1.5
93 | );
94 |
95 | if (this.instance.localEntity !== null) {
96 | this.drawPixelText(
97 | `${get("Local")} ${get("X")}: ${this.instance.localEntity.x} ${get("Y")}: ${this.instance.localEntity.y.toFixed(2)} ${get("Local")} Z: ${-this.instance.localEntity.z.toFixed(4)}`,
98 | 15, 270,
99 | 20, 1.5,
100 | color
101 | );
102 | }
103 |
104 | this.drawPixelText(
105 | `${get("CommandStack")}: ${this.instance.editor.commander.position + 1} | ${this.instance.editor.commander.stack.length}`,
106 | 15, 300,
107 | 20, 1.5,
108 | color
109 | );
110 |
111 | this.drawPixelText(
112 | `${get("GodMode")}: ${GOD_MODE === true ? get("Enabled") : get("Disabled")}`,
113 | 15, 330,
114 | 20, 1.5,
115 | color
116 | );
117 |
118 | this.drawPixelText(
119 | `${get("FreeCamera")}: ${FREE_CAMERA === true ? get("Enabled") : get("Disabled")}`,
120 | 15, 360,
121 | 20, 1.5,
122 | color
123 | );
124 |
125 | this.drawPixelText(
126 | `${get("EditMode")}: ${EDIT_MODE === true ? get("Enabled") : get("Disabled")}`,
127 | 15, 390,
128 | 20, 1.5,
129 | color
130 | );
131 |
132 | }
--------------------------------------------------------------------------------
/src/Engine/Renderer/grid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Draw a grid
3 | * @param {Object} ctx
4 | * @param {Number} x
5 | * @param {Number} y
6 | * @param {Number} width
7 | * @param {Number} height
8 | * @param {Number} dim
9 | * @param {Number} scale
10 | * @param {Number} ln
11 | * @param {String} color
12 | */
13 | export function drawGrid(ctx, x, y, width, height, dim, scale, ln, color, xPad, yPad) {
14 |
15 | let ww = dim * scale;
16 | let hh = dim * scale;
17 |
18 | let xx = x % ww;
19 | let yy = y % hh;
20 |
21 | ctx.beginPath();
22 |
23 | for (; xx < width; xx += ww) {
24 | ctx.moveTo((xx - ln) + xPad, yPad);
25 | ctx.lineTo((xx - ln) + xPad, height + yPad);
26 | };
27 |
28 | for (; yy < height; yy += hh) {
29 | ctx.moveTo(xPad, (yy + ln) + yPad);
30 | ctx.lineTo(width + xPad, (yy + ln) + yPad);
31 | };
32 |
33 | ctx.strokeStyle = color;
34 | ctx.lineWidth = ln;
35 |
36 | ctx.stroke();
37 |
38 | ctx.closePath();
39 |
40 | return void 0;
41 |
42 | }
--------------------------------------------------------------------------------
/src/Engine/Renderer/index.js:
--------------------------------------------------------------------------------
1 | import "../../polyfill";
2 | import math from "../../Math";
3 |
4 | import * as cfg from "../../cfg";
5 |
6 | import { inherit } from "../utils";
7 |
8 | import * as entity from "../Entity/functions";
9 | import * as render from "./render";
10 | import * as debug from "./debug";
11 |
12 | import WGL_Renderer from "./webgl";
13 |
14 | /**
15 | * Renderer
16 | * @class Renderer
17 | * @export
18 | */
19 | export default class Renderer {
20 |
21 | /**
22 | * @param {Object} instance
23 | * @constructor
24 | */
25 | constructor(instance) {
26 |
27 | /**
28 | * Instance ref
29 | * @type {Object}
30 | */
31 | this.instance = instance;
32 |
33 | /**
34 | * WebGL renderer
35 | * @type {Object}
36 | */
37 | this.glRenderer = null;
38 |
39 | /**
40 | * Size
41 | * @type {Object}
42 | */
43 | this.size = instance.size;
44 |
45 | /**
46 | * Layers ref
47 | * @type {Object}
48 | */
49 | this.layers = instance.layers;
50 |
51 | /**
52 | * Node ref
53 | * @type {Object}
54 | */
55 | this.node = instance.node;
56 |
57 | /**
58 | * WebGL node ref
59 | * @type {Object}
60 | */
61 | this.glNode = instance.glNode;
62 |
63 | /**
64 | * Context ref
65 | * @type {Object}
66 | */
67 | this.context = instance.context;
68 |
69 | /**
70 | * Gl context ref
71 | * @type {Object}
72 | */
73 | this.gl = instance.glContext;
74 |
75 | /**
76 | * Image smoothing
77 | * @type {Boolean}
78 | */
79 | this.imageSmoothing = false;
80 |
81 | /**
82 | * Dimension
83 | * @type {Number}
84 | */
85 | this.dimension = cfg.DIMENSION;
86 |
87 | /**
88 | * Delta timer
89 | * @type {Number}
90 | */
91 | this.delta = 0;
92 |
93 | /**
94 | * Now timestamp
95 | * @type {Number}
96 | */
97 | this.now = 0;
98 |
99 | /**
100 | * Then timestamp
101 | * @type {Number}
102 | */
103 | this.then = 0;
104 |
105 | /**
106 | * Width
107 | * @type {Number}
108 | */
109 | this.width = 0;
110 |
111 | /**
112 | * Height
113 | * @type {Number}
114 | */
115 | this.height = 0;
116 |
117 | /**
118 | * Camera ref
119 | * @type {Object}
120 | */
121 | this.camera = instance.camera;
122 |
123 | if (cfg.WGL_SUPPORT) {
124 | this.glRenderer = new WGL_Renderer(this);
125 | this.glRenderer.init();
126 | }
127 |
128 | /**
129 | * Auto switch to current game mode dependant rendering
130 | */
131 | this.switchRenderingMode(cfg.DEBUG_MODE ? 0 : 1);
132 |
133 | this.resize(false);
134 |
135 | }
136 |
137 | /**
138 | * Switch rendering mode
139 | * @param {Number} mode
140 | */
141 | switchRenderingMode(mode) {
142 |
143 | if (mode === cfg.WGL) {
144 | if (cfg.WGL_SUPPORT) {
145 | this.node.style.display = "none";
146 | this.glNode.style.display = "block";
147 | cfg.RENDER_MODE = mode;
148 | } else {
149 | mode = cfg.CANVAS;
150 | }
151 | }
152 |
153 | if (mode === cfg.CANVAS) {
154 | this.node.style.display = "block";
155 | this.glNode.style.display = "none";
156 | cfg.RENDER_MODE = mode;
157 | }
158 |
159 | }
160 |
161 | /**
162 | * @param {Boolean} value
163 | * @setter
164 | */
165 | set imageSmoothingEnabled(value) {
166 |
167 | value = value ? true : false;
168 |
169 | this.imageSmoothing = value;
170 |
171 | this.context.setImageSmoothing(value);
172 |
173 | }
174 |
175 | /**
176 | * Update
177 | */
178 | update() {
179 |
180 | this.updateTimers();
181 |
182 | if (this.camera.objectFocus !== null) {
183 | this.camera.animate(this.camera.objectFocus);
184 | }
185 |
186 | return void 0;
187 |
188 | }
189 |
190 | /**
191 | * Update timers
192 | */
193 | updateTimers() {
194 | this.now = Date.now();
195 | this.delta = (this.now - this.then) / 1e3;
196 | this.then = this.now;
197 | return void 0;
198 | }
199 |
200 | /**
201 | * Resize
202 | * @param {Boolean} redraw
203 | */
204 | resize(redraw) {
205 | this.width = window.innerWidth;
206 | this.height = window.innerHeight;
207 | this.camera.width = this.width;
208 | this.camera.height = this.height;
209 | this.instance.width = this.width;
210 | this.instance.height = this.height;
211 | if (cfg.RENDER_MODE === cfg.WGL) {
212 | this.glNode.width = this.width;
213 | this.glNode.height = this.height;
214 | this.glRenderer.resize(this.width, this.height);
215 | } else {
216 | this.node.width = this.width;
217 | this.node.height = this.height;
218 | }
219 | this.clear();
220 | this.imageSmoothingEnabled = this.imageSmoothing;
221 | this.instance.mini.resize();
222 | this.instance.editor.updateTilesetPosition();
223 | this.draw();
224 | }
225 |
226 | }
227 |
228 | inherit(Renderer, debug);
229 | inherit(Renderer, render);
230 | inherit(Renderer, entity);
231 | inherit(Renderer, webgl);
--------------------------------------------------------------------------------
/src/Engine/Renderer/webgl/shaders.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Thanks to mattdesl for the
3 | * normal mappping thingys
4 | */
5 | export const spritevs = `
6 |
7 | precision lowp float;
8 |
9 | uniform vec2 uScale;
10 | uniform vec2 uEntityScale;
11 | attribute vec2 aObjCen;
12 | attribute float aObjRot;
13 | attribute float aIdx;
14 | varying vec2 uv;
15 |
16 | void main(void) {
17 | if (aIdx == 0.0) {
18 | uv = vec2(0.0,0.0);
19 | } else if (aIdx == 1.0) {
20 | uv = vec2(1.0,0.0);
21 | } else if (aIdx == 2.0) {
22 | uv = vec2(0.0,1.0);
23 | } else {
24 | uv = vec2(1.0,1.0);
25 | }
26 | vec2 pos = vec2(
27 | aObjCen.x + sin(aObjRot)*uEntityScale.y*(-0.5 + uv.y)
28 | + cos(aObjRot)*uEntityScale.x*(-0.5 + uv.x),
29 | aObjCen.y + cos(aObjRot)*uEntityScale.y*(-0.5 + uv.y)
30 | - sin(aObjRot)*uEntityScale.x*(-0.5 + uv.x)
31 | );
32 | gl_Position = vec4(
33 | -1.0 + 2.0*pos.x/uScale.x,
34 | 1.0 - 2.0*pos.y/uScale.y,
35 | 0.0, 1.0
36 | );
37 | }
38 |
39 | `;
40 |
41 | export const spritefs = `
42 |
43 | precision lowp float;
44 |
45 | #define STEP_A 0.4
46 | #define STEP_B 0.6
47 | #define STEP_C 0.8
48 | #define STEP_D 1.0
49 |
50 | uniform sampler2D u_texture0;
51 | uniform sampler2D u_normals;
52 |
53 | varying vec2 uv;
54 |
55 | uniform vec4 AmbientColor;
56 | uniform vec2 Resolution;
57 |
58 | uniform float Opacity;
59 |
60 | uniform float LightSize;
61 | uniform bool SoftLight;
62 | uniform vec3 LightPos;
63 | uniform vec4 LightColor;
64 | uniform vec3 Falloff;
65 |
66 | void main() {
67 |
68 | vec3 Sum = vec3(0.0);
69 |
70 | vec4 DiffuseColor = texture2D(u_texture0, uv);
71 |
72 | vec3 NormalMap = texture2D(u_normals, uv).rgb;
73 |
74 | vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);
75 |
76 | LightDir.x /= (LightSize / Resolution.x);
77 | LightDir.y /= (LightSize / Resolution.y);
78 |
79 | float D = length(LightDir);
80 |
81 | vec3 N = normalize(NormalMap * 2.0 - 1.0);
82 | vec3 L = normalize(LightDir);
83 |
84 | N = mix(N, vec3(0), 0.5);
85 |
86 | float df = max(dot(N, L), 0.0);
87 |
88 | vec3 Diffuse = (LightColor.rgb * LightColor.a) * df;
89 |
90 | vec3 Ambient = AmbientColor.rgb * AmbientColor.a;
91 |
92 | float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );
93 |
94 | if (SoftLight == false) {
95 | if (Attenuation < STEP_A) Attenuation = 0.0;
96 | else if (Attenuation < STEP_B) Attenuation = STEP_B;
97 | else if (Attenuation < STEP_C) Attenuation = STEP_C;
98 | else Attenuation = STEP_D;
99 | }
100 |
101 | vec3 Intensity = Ambient + Diffuse * Attenuation;
102 | vec3 FinalColor = DiffuseColor.rgb * Intensity;
103 |
104 | Sum += FinalColor;
105 |
106 | if (SoftLight == false) {
107 | gl_FragColor = vec4(Sum, DiffuseColor.a * Opacity);
108 | } else {
109 | gl_FragColor = vec4(FinalColor, DiffuseColor.a * Opacity);
110 | }
111 |
112 | if (gl_FragColor.a < 0.1) discard;
113 |
114 | }
115 |
116 | `;
117 |
118 | export const outlinefs = `
119 |
120 | precision lowp float;
121 |
122 | #define PI 3.14159265359
123 | #define WIDTH 10.0
124 | #define COLOR vec4(0.0,0.0,0.0,1.0)
125 | #define NUM_FRAMES 6.0
126 |
127 | uniform sampler2D u_texture0;
128 |
129 | varying vec2 uv;
130 | uniform vec2 uScale;
131 | uniform vec2 uEntityScale;
132 |
133 | void main() {
134 |
135 | vec2 point = vec2( (WIDTH/uEntityScale.x)*cos(PI), (WIDTH/uEntityScale.y)*sin(PI));
136 | point = clamp(uv + point, vec2(0.0), vec4(uEntityScale.xy, uEntityScale.xy).zw );
137 | float sampledAlpha = texture2D(u_texture0, point).a;
138 | float outlineAlpha = max(0.0, sampledAlpha);
139 |
140 | gl_FragColor = mix(vec4(0.0), COLOR, outlineAlpha);
141 |
142 | vec4 tex0 = texture2D(u_texture0, uv);
143 | gl_FragColor = mix(gl_FragColor, tex0, tex0.a);
144 |
145 | if (gl_FragColor.a < 0.5) discard;
146 |
147 | }
148 |
149 | `;
--------------------------------------------------------------------------------
/src/Engine/Shadow/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION,
3 | LEFT, RIGHT, UP, DOWN,
4 | SHADOW_ALPHA
5 | } from "../../cfg";
6 |
7 | import math from "../../Math";
8 |
9 | import DisplayObject from "../DisplayObject";
10 |
11 | import { TextureCache, uHash, createCanvasBuffer } from "../utils";
12 | import { colorizePixels } from "../Texture/effects";
13 |
14 | /**
15 | * Shadow
16 | * @class Shadow
17 | * @export
18 | */
19 | export default class Shadow extends DisplayObject {
20 |
21 | /**
22 | * @param {Object} parent
23 | * @constructor
24 | */
25 | constructor(parent) {
26 |
27 | super(null);
28 |
29 | /**
30 | * Parent ref
31 | * @type {Object}
32 | */
33 | this.parent = parent;
34 |
35 | /**
36 | * Texture
37 | * @type {Object}
38 | */
39 | this.texture = null;
40 |
41 | /**
42 | * GL texture
43 | * @type {Object}
44 | */
45 | this.glTexture = null;
46 |
47 | /**
48 | * Splitted sprites
49 | * @type {Array}
50 | */
51 | this.sprites = [];
52 |
53 | this.scale.set(0, 0);
54 |
55 | this.init();
56 |
57 | }
58 |
59 | /**
60 | * Initialise
61 | * Build shadow
62 | */
63 | init() {
64 |
65 | this.texture = this.buildShadow();
66 |
67 | }
68 |
69 | /**
70 | * Build shadow
71 | * @return {Object}
72 | */
73 | buildShadow() {
74 |
75 | let ii = 0;
76 | let length = 0;
77 |
78 | let buffer = null;
79 |
80 | let parent = this.parent.texture;
81 |
82 | let width = 0;
83 | let height = 0;
84 |
85 | length = parent.sprites.length;
86 |
87 | for (; ii < length; ++ii) {
88 | width = parent.sprites[ii].canvas.width;
89 | height = parent.sprites[ii].canvas.height;
90 | buffer = createCanvasBuffer(width, height);
91 | buffer.translate(0, height);
92 | buffer.scale(1, -1);
93 | this.drawShadow(
94 | parent.sprites[ii],
95 | buffer,
96 | width, height
97 | );
98 | buffer.setTransform(1, 0, 0, 1, 0, 0);
99 | this.sprites[ii] = buffer;
100 | buffer = null;
101 | };
102 |
103 | return (this);
104 |
105 | }
106 |
107 | /**
108 | * Create shadow of a sprite
109 | * @param {Object} buffer
110 | * @param {Object} ctx
111 | * @param {Number} width
112 | * @param {Number} height
113 | */
114 | drawShadow(buffer, ctx, width, height) {
115 |
116 | ctx.clear();
117 |
118 | ctx.drawImage(
119 | buffer.canvas,
120 | 0, 0,
121 | width, height
122 | );
123 |
124 | this.drawTint(
125 | ctx,
126 | 0, 0,
127 | width, height,
128 | SHADOW_ALPHA * 1e2
129 | );
130 |
131 | }
132 |
133 | /**
134 | * Tint a canvas
135 | * @param {Object} ctx
136 | * @param {Number} x
137 | * @param {Number} y
138 | * @param {Number} width
139 | * @param {Number} height
140 | * @param {Number} value
141 | */
142 | drawTint(ctx, x, y, width, height, value) {
143 |
144 | let imgData = ctx.getImageData(
145 | x, y,
146 | width, height
147 | );
148 |
149 | colorizePixels(
150 | imgData,
151 | 0,
152 | 0,
153 | value,
154 | true
155 | );
156 |
157 | ctx.putImageData(
158 | imgData,
159 | x, y
160 | );
161 |
162 | }
163 |
164 | }
--------------------------------------------------------------------------------
/src/Engine/Texture/effects.js:
--------------------------------------------------------------------------------
1 | import {
2 | getTime
3 | } from "../utils";
4 |
5 | /**
6 | * Draw time based lightning
7 | * @param {Object} buffer
8 | * @param {Object} ctx
9 | * @param {Number} x
10 | * @param {Number} y
11 | * @param {Number} width
12 | * @param {Number} height
13 | * @param {Array} colors
14 | */
15 | export function drawTimeLightning(buffer, ctx, x, y, width, height, colors) {
16 |
17 | let hour = 18/*getTime().hours*/;
18 |
19 | let imgData = buffer.getImageData(
20 | x, y,
21 | width, height
22 | );
23 |
24 | this.colorizePixels(
25 | imgData,
26 | colors[hour][0] / 100,
27 | colors[hour][1] / 100,
28 | colors[hour][2] / 100,
29 | false
30 | );
31 |
32 | ctx.putImageData(
33 | imgData,
34 | x, y
35 | );
36 |
37 | return void 0;
38 |
39 | };
40 |
41 | /**
42 | * Colorize pixels
43 | * @param {Object} imgData
44 | * @param {Number} r
45 | * @param {Number} g
46 | * @param {Number} b
47 | * @param {Boolean} strict
48 | */
49 | export function colorizePixels(imgData, r, g, b, strict) {
50 |
51 | let ii = 0;
52 | let length = 0;
53 |
54 | let pixels = imgData.data;
55 |
56 | length = pixels.length;
57 |
58 | if (strict) {
59 | for (; ii < length / 4; ++ii) {
60 | if (pixels[ii * 4] > 0) {
61 | pixels[ii * 4] = g;
62 | }
63 | if (pixels[ii * 4 + 1] > 0) {
64 | pixels[ii * 4 + 1] = r;
65 | }
66 | if (pixels[ii * 4 + 2] > 0) {
67 | pixels[ii * 4 + 2] = g;
68 | }
69 | if (pixels[ii * 4 + 3] > 2) {
70 | pixels[ii * 4 + 3] = b;
71 | }
72 | };
73 | } else {
74 | for (; ii < length / 4; ++ii) {
75 | pixels[ii * 4 + 1] = pixels[ii * 4 + 1] / r;
76 | pixels[ii * 4 + 2] = pixels[ii * 4 + 2] / g;
77 | pixels[ii * 4 + 3] = pixels[ii * 4 + 3] * b;
78 | };
79 | }
80 |
81 | return void 0;
82 |
83 | }
--------------------------------------------------------------------------------
/src/Engine/Texture/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | DEV_MODE,
3 | ColorPalette
4 | } from "../../cfg";
5 |
6 | import {
7 | inherit,
8 | TextureCache,
9 | createCanvasBuffer,
10 | imageToCanvas,
11 | antiCache
12 | } from "../utils";
13 |
14 | import * as effect from "./effects";
15 |
16 | /**
17 | * Texture
18 | * @class Texture
19 | * @export
20 | */
21 | export default class Texture {
22 |
23 | /**
24 | * @param {String} url
25 | * @param {Number} width
26 | * @param {Number} height
27 | * @param {Function} resolve
28 | * @constructor
29 | */
30 | constructor(url, width, height, resolve) {
31 |
32 | /**
33 | * Texture
34 | * @type {Object}
35 | */
36 | this.texture = null;
37 |
38 | /**
39 | * Texture effect
40 | * @type {Object}
41 | */
42 | this.texture_effect = null;
43 |
44 | /**
45 | * Effect texture
46 | * @type {Object}
47 | */
48 | this.effect_sprites = [];
49 |
50 | /**
51 | * Splitted sprites
52 | * @type {Array}
53 | */
54 | this.sprites = [];
55 |
56 | /**
57 | * Image url
58 | * @type {String}
59 | */
60 | this.imgUrl = url;
61 |
62 | /**
63 | * Width
64 | * @type {Number}
65 | */
66 | this.width = 0;
67 |
68 | /**
69 | * Height
70 | * @type {Number}
71 | */
72 | this.height = 0;
73 |
74 | /**
75 | * Sprite width
76 | * @type {Number}
77 | */
78 | this.sWidth = width;
79 |
80 | /**
81 | * Sprite height
82 | * @type {Number}
83 | */
84 | this.sHeight = height;
85 |
86 | /**
87 | * X multiplicator
88 | * @type {Number}
89 | */
90 | this.xMul = 0;
91 |
92 | /**
93 | * Y multiplicator
94 | * @type {Number}
95 | */
96 | this.yMul = 0;
97 |
98 | /**
99 | * Loading state
100 | * @type {Boolean}
101 | */
102 | this.hasLoaded = false;
103 |
104 | this.fromImage(this.imgUrl, this::function() {
105 | resolve(this);
106 | });
107 |
108 | }
109 |
110 | /**
111 | * @param {String} url
112 | * @param {Function} resolve
113 | */
114 | fromImage(url, resolve) {
115 |
116 | let img = null;
117 |
118 | let texture = TextureCache[url];
119 |
120 | if (
121 | texture !== void 0 &&
122 | texture instanceof Texture
123 | ) {
124 | this.hasLoaded = true;
125 | return (TextureCache[url]);
126 | }
127 |
128 | img = new Image();
129 |
130 | img.addEventListener('load', this::function() {
131 | this.width = img.width;
132 | this.height = img.height;
133 | this.hasLoaded = true;
134 | this.texture = imageToCanvas(img);
135 | this.splitTexture();
136 | TextureCache[url] = this;
137 | this.renderEffects();
138 | resolve();
139 | });
140 |
141 | if (DEV_MODE === true) {
142 | img.src = url + antiCache();
143 | } else {
144 | img.src = url;
145 | }
146 |
147 | return void 0;
148 |
149 | }
150 |
151 | /**
152 | * Split texture into seperate sprites
153 | */
154 | splitTexture() {
155 |
156 | if (this.sWidth === -1 && this.sHeight === -1) {
157 | this.sWidth = this.width / 2;
158 | this.sHeight = this.height / 2;
159 | }
160 |
161 | this.xMul = this.height / (this.sWidth * 2);
162 | this.yMul = this.width / (this.sHeight * 2);
163 |
164 | let buffer = null;
165 |
166 | let ii = 0;
167 |
168 | let xx = 0;
169 | let yy = 0;
170 |
171 | let width = this.width / (this.sWidth * 2);
172 | let height = this.height / (this.sHeight * 2);
173 |
174 | for (; yy < height;) {
175 | for (xx = 0; xx < width; ++xx) {
176 | if (xx === 0) ++yy;
177 | buffer = createCanvasBuffer(this.sWidth * 2, this.sHeight * 2);
178 | buffer.drawImage(
179 | this.texture.canvas,
180 | (this.sWidth * 2) * xx, (this.sHeight * 2) * (yy - 1),
181 | this.width, this.height,
182 | 0, 0,
183 | this.width, this.height
184 | );
185 | this.sprites.push(buffer);
186 | buffer = null;
187 | };
188 | };
189 |
190 | }
191 |
192 | /**
193 | * Render texture effects
194 | */
195 | renderEffects() {
196 | this.buildTimeLightning();
197 | }
198 |
199 | /**
200 | * Build texture time lightning
201 | */
202 | buildTimeLightning() {
203 |
204 | let ii = 0;
205 | let length = 0;
206 |
207 | let buffer = null;
208 |
209 | let width = 0;
210 | let height = 0;
211 |
212 | length = this.sprites.length;
213 |
214 | for (; ii < length; ++ii) {
215 | width = this.sprites[ii].canvas.width;
216 | height = this.sprites[ii].canvas.height;
217 | buffer = createCanvasBuffer(width, height);
218 | buffer.translate(0, height);
219 | buffer.scale(1, -1);
220 | this.drawTimeLightning(
221 | this.sprites[ii],
222 | buffer,
223 | 0, 0,
224 | width, height,
225 | ColorPalette
226 | );
227 | buffer.setTransform(1, 0, 0, 1, 0, 0);
228 | this.effect_sprites[ii] = buffer;
229 | buffer = null;
230 | };
231 |
232 | }
233 |
234 | }
235 |
236 | inherit(Texture, effect);
--------------------------------------------------------------------------------
/src/Engine/logic.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION,
3 | GRAVITY,
4 | TYPES
5 | } from "../cfg";
6 |
7 | /**
8 | * Logic loop
9 | */
10 | export function logic() {
11 |
12 | if (this.currentMap === null) return void 0;
13 |
14 | /** Depth sort entities */
15 | this.sort();
16 |
17 | let ii = 0;
18 | let length = 0;
19 |
20 | let entity = null;
21 | let entities = this.currentMap.entities;
22 |
23 | length = entities.length;
24 |
25 | for (; ii < length; ++ii) {
26 | entity = entities[ii];
27 | entity.idleTime++;
28 | entity.renderable = this.updateEntity(entity);
29 | if (entity.type === TYPES.Notification) {
30 | this.updateNotification(entity);
31 | }
32 | if (entity.opacity < 0) {
33 | this.removeEntity(entity);
34 | --length;
35 | --ii;
36 | continue;
37 | }
38 | if (entity.noise === null) continue;
39 | this.updateEntityNoise(entity, this.currentMap.distance(entity, this.camera));
40 | };
41 |
42 | return void 0;
43 |
44 | }
45 |
46 | /**
47 | * Update notification
48 | * @param {Object} entity
49 | */
50 | export function updateNotification(entity) {
51 |
52 | entity.xPadding = (
53 | (
54 | (Math.max(entity.follow.size.x, entity.size.x / 2) / 2) - entity.follow.size.x / 2
55 | )
56 | - entity.follow.xMargin - (entity.size.x === entity.follow.size.x ? DIMENSION : 0)
57 | );
58 |
59 | entity.yPadding = entity.size.y;
60 |
61 | }
62 |
63 | /**
64 | * Orbit animation
65 | * @param {Object} entity
66 | */
67 | export function orbit(entity) {
68 |
69 | entity.orbitAngle += (entity.velocity * 2) * Math.PI / 180;
70 |
71 | let target = entity.orbitTarget;
72 |
73 | let radius = ((target.size.x * target.scale + target.size.y * target.scale) / DIMENSION) * 2;
74 |
75 | let xPadding = radius - (DIMENSION / 2);
76 | let yPadding = radius - (DIMENSION / 2);
77 |
78 | xPadding += target.xMargin;
79 | yPadding += target.yMargin / 2;
80 |
81 | entity.x = (target.position.x + xPadding) + radius * Math.cos(entity.orbitAngle);
82 | entity.y = (target.position.y + yPadding) + radius * Math.sin(entity.orbitAngle);
83 |
84 | /** Stop the orbit on a dimension friendly position */
85 | if (
86 | entity.stopOrbit === true &&
87 | (entity.x << 0) % 8 === 0 &&
88 | (entity.y << 0) % 8 === 0
89 | ) {
90 | entity.x = math.roundTo(entity.x, DIMENSION);
91 | entity.y = math.roundTo(entity.y, DIMENSION);
92 | entity.orbitAround(null);
93 | entity.stopOrbit = false;
94 | }
95 |
96 | /*if (entity.orbitAngle > 360) {
97 | entity.orbitAngle = 0;
98 | }*/
99 |
100 | return void 0;
101 |
102 | }
103 |
104 | /**
105 | * Floating animation
106 | * TODO: ENTITY CAN ONLY WALK IF ON FLOOR (Z =^ 0)
107 | * @param {Object} entity
108 | */
109 | export function float(entity) {
110 |
111 | entity.z += entity.gravity / 5;
112 |
113 | if (entity.z < 0) {
114 | entity.gravity += (.1 / 5);
115 | } else {
116 | entity.gravity = GRAVITY;
117 | entity.z = 0;
118 | entity.updateShadow();
119 | entity.refreshState();
120 | }
121 |
122 | entity.updateShadow();
123 |
124 | return void 0;
125 |
126 | }
127 |
128 | /**
129 | * Update entity
130 | * @param {Object} entity
131 | * @return {Boolean} renderable
132 | */
133 | export function updateEntity(entity) {
134 |
135 | if (entity.lifeTime > 0) {
136 | if (this.renderer.now >= entity.lifeTime) {
137 | entity.lifeTime = 0;
138 | entity.fadeOut(1, true);
139 | }
140 | }
141 |
142 | entity.scaling = entity.scale + (-entity.position.z / this.camera.resolution) / ((entity.size.x + entity.size.y) / 2);
143 |
144 | entity.animate();
145 |
146 | if (entity.orbit === true) {
147 | this.orbit(entity);
148 | }
149 |
150 | if (entity.floating === true) {
151 | this.float(entity);
152 | }
153 |
154 | if (entity.z !== 0) {
155 | entity.updateShadow();
156 | }
157 |
158 | if (entity.absolute === true) {
159 | return (
160 | this.isRenderable(entity) === true
161 | );
162 | }
163 |
164 | if (this.camera.isInView(
165 | entity.position.x + entity.xMargin, entity.position.y + entity.yMargin,
166 | entity.size.x * entity.scale, ((entity.size.y * 2) * entity.scale) + entity.shadowY
167 | ) === false) {
168 | return (false);
169 | }
170 |
171 | if (this.isRenderable(entity) === false) {
172 | return (false);
173 | }
174 |
175 | this.renderer.updateEntitySpriteFrame(entity);
176 |
177 | return (true);
178 |
179 | }
180 |
181 | /**
182 | * Entity is renderable
183 | * @param {Object} entity
184 | * @return {Boolean} renderable
185 | */
186 | export function isRenderable(entity) {
187 | return (
188 | entity.texture !== null &&
189 | entity.opacity !== .0
190 | );
191 | }
--------------------------------------------------------------------------------
/src/Engine/sound.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION,
3 | VOLUME,
4 | BGS
5 | } from "../cfg";
6 |
7 | import math from "../Math";
8 |
9 | import Audio from "./Audio";
10 |
11 | /**
12 | * Update entity noise
13 | * @param {Object} entity
14 | * @param {Object} distance
15 | */
16 | export function updateEntityNoise(entity, dist) {
17 |
18 | let radius = 0;
19 |
20 | let cx = 0;
21 | let cy = 0;
22 | let dx = 0;
23 | let dy = 0;
24 |
25 | if (BGS === false) {
26 | dist.x = 99999;
27 | dist.y = 99999;
28 | radius = 0;
29 | if (entity.noise._audioNode !== void 0) {
30 | entity.noise._audioNode[0].gain.value = 0;
31 | }
32 | }
33 |
34 | radius = (entity.noiseRadius - DIMENSION) || DIMENSION;
35 | cx = radius / 2;
36 | cy = radius / 2;
37 | dx = Math.floor(dist.x * 1e2) + cx;
38 | dy = Math.floor(dist.y * 1e2) + cy;
39 |
40 | if (entity.STATES.NOISE === false) {
41 | entity.noiseSrcPath = entity.noise;
42 | entity.noise = Audio.playNoise(entity.noise, VOLUME.ENTITY_NOISE, dist.x, dist.y);
43 | entity.STATES.NOISE = true;
44 | }
45 |
46 | if (math.pointIntersectsCircle(dx, dy, cx, cy, radius) === true) {
47 | if (entity.noise.isInView === false) {
48 | let gainNode = entity.noise._audioNode[0];
49 | entity.noise.fadingIn = true;
50 | let start = gainNode.context.currentTime;
51 | let end = start + 1;
52 | gainNode.gain.linearRampToValueAtTime(gainNode.gain.value, start);
53 | gainNode.gain.linearRampToValueAtTime(VOLUME.ENTITY_NOISE / 1e2, end);
54 | entity.noise.isInView = true;
55 | }
56 | } else {
57 | if (entity.noise.isInView === true) {
58 | let gainNode = entity.noise._audioNode[0];
59 | entity.noise.fadingOut = true;
60 | let start = gainNode.context.currentTime;
61 | let end = start + 1;
62 | gainNode.gain.linearRampToValueAtTime(gainNode.gain.value, start);
63 | gainNode.gain.linearRampToValueAtTime(.0, end);
64 | entity.noise.isInView = false;
65 | }
66 | }
67 |
68 | entity.noise.pos3d(dist.x, dist.y, 0);
69 |
70 | return void 0;
71 |
72 | }
--------------------------------------------------------------------------------
/src/Engine/utils/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | DEV_MODE
3 | } from "../../cfg";
4 |
5 | import Texture from "../Texture";
6 |
7 | let rx = {
8 | path: /[^\\/]+$/
9 | };
10 |
11 | /**
12 | * Cached textures
13 | * @type {Object}
14 | */
15 | export let TextureCache = {};
16 |
17 | let hashIndex = -1;
18 | let hashes = [];
19 |
20 | /**
21 | * Parsed maps
22 | * @type {Object}
23 | */
24 | export let Maps = {};
25 |
26 | /**
27 | * Check if webgl is supported
28 | * @return {Boolean}
29 | */
30 | export function supportWGL() {
31 |
32 | let canvas = null;
33 |
34 | try {
35 | canvas = document.createElement("canvas");
36 | if (WebGLRenderingContext !== void 0) {
37 | return (!!getWGLContext(canvas));
38 | }
39 | } catch(e) {
40 | return (false);
41 | };
42 |
43 | return (false);
44 |
45 | }
46 |
47 | /**
48 | * Converts a string into corresponding type
49 | * @param {String} value
50 | * @return {*}
51 | */
52 | export function parseString(value) {
53 |
54 | let isNumber = Number(value) >= 0 || Number(value) < 0;
55 | let isBoolean = value === "true" || value === "false";
56 | let isString = !isNumber && !isBoolean;
57 |
58 | return (
59 | isNumber ? Number(value) :
60 | isBoolean ? value === "true" :
61 | isString ? value :
62 | null
63 | );
64 |
65 | }
66 |
67 | /**
68 | * Get local host
69 | * @return {String}
70 | */
71 | export function getLocalHost() {
72 | if (typeof document === "undefined") return void 0;
73 | return (
74 | document.location.host.replace(/:.*/, "")
75 | );
76 | }
77 |
78 | /**
79 | * Get wgl context of a canvas
80 | * @return {Object}
81 | */
82 | export function getWGLContext(canvas) {
83 | let options = {
84 | alpha: false,
85 | antialias: false,
86 | premultipliedAlpha: false,
87 | stencil: false,
88 | preserveDrawingBuffer: false
89 | };
90 | return (
91 | canvas.getContext("webgl", options) ||
92 | canvas.getContext("experimental-webgl", options)
93 | );
94 | }
95 |
96 | /**
97 | * Get a sprite
98 | * @param {String} sprite
99 | * @param {Number} width
100 | * @param {Number} height
101 | * @param {Function} resolve
102 | */
103 | export function getSprite(sprite, width, height, resolve) {
104 |
105 | if (TextureCache[sprite]) {
106 | resolve(TextureCache[sprite]);
107 | return void 0;
108 | }
109 |
110 | new Texture(sprite, width, height, function(instance) {
111 | resolve(TextureCache[sprite] = instance);
112 | });
113 |
114 | return void 0;
115 |
116 | }
117 |
118 | /**
119 | * Generate a unique hash
120 | * @export
121 | */
122 | export function uHash() {
123 |
124 | let index = ++hashIndex;
125 |
126 | if (hashes.indexOf(index) > -1) return (this.uHash());
127 |
128 | hashes.push(index);
129 |
130 | return (index);
131 |
132 | }
133 |
134 | /**
135 | * Get path without file ext
136 | * @param {String} path
137 | * @return {String}
138 | */
139 | export function getPath(path) {
140 | return (
141 | path.replace(rx.path.exec(path)[0], "")
142 | );
143 | }
144 |
145 | /**
146 | * @param {Object} cls
147 | * @param {Object} prot
148 | * @export
149 | */
150 | export function inherit(cls, prot) {
151 |
152 | let key = null;
153 |
154 | for (key in prot) {
155 | if (prot[key] instanceof Function) {
156 | cls.prototype[key] = prot[key];
157 | }
158 | };
159 |
160 | }
161 |
162 | /**
163 | * @param {Number} width
164 | * @param {Number} height
165 | */
166 | export function createCanvasBuffer(width, height) {
167 |
168 | let canvas = document.createElement("canvas");
169 | let ctx = canvas.getContext("2d");
170 |
171 | ctx.setImageSmoothing(false);
172 |
173 | canvas.width = width;
174 | canvas.height = height;
175 |
176 | return (ctx);
177 |
178 | }
179 |
180 | /**
181 | * @param {Object} img
182 | * @return {Object}
183 | */
184 | export function imageToCanvas(img) {
185 |
186 | let ctx = createCanvasBuffer(
187 | img.width, img.height
188 | );
189 |
190 | ctx.drawImage(
191 | img,
192 | 0, 0,
193 | img.width, img.height
194 | );
195 |
196 | return (ctx);
197 |
198 | }
199 |
200 | /**
201 | * @param {Object} canvas
202 | * @return {Object}
203 | */
204 | export function canvasToImage(canvas) {
205 |
206 | let image = new Image();
207 |
208 | image.src = canvas.toDataURL("image/png");
209 |
210 | return (image);
211 |
212 | }
213 |
214 | /**
215 | * Check if a tile contains any image data
216 | * @param {Object} ctx
217 | * @param {Number} x
218 | * @param {Number} y
219 | * @param {Number} width
220 | * @param {Number} height
221 | * @return {Boolean}
222 | */
223 | export function tileContainsImageData(ctx, x, y, width, height) {
224 |
225 | let ii = 0;
226 | let length = 0;
227 |
228 | let data = ctx.getImageData(x * 2, y * 2, width * 2, height * 2).data;
229 |
230 | length = data.length;
231 |
232 | for (; ii < length; ii += 4) {
233 | if (data[ii] > 0) return (true);
234 | if (data[ii + 1] > 0) return (true);
235 | if (data[ii + 2] > 0) return (true);
236 | if (data[ii + 3] > 0) return (true);
237 | };
238 |
239 | return (false);
240 |
241 | }
242 |
243 | /**
244 | * Get current time
245 | * @return {Object}
246 | */
247 | export function getTime() {
248 |
249 | let date = new Date();
250 |
251 | return ({
252 | hours: date.getHours(),
253 | minutes: date.getMinutes(),
254 | seconds: date.getSeconds()
255 | });
256 |
257 | }
258 |
259 | /**
260 | * Anti cache
261 | * @return {String}
262 | */
263 | export function antiCache() {
264 | return (
265 | `?${+(new Date())}`
266 | );
267 | }
268 |
269 | /**
270 | * Ajax
271 | * @param {String} url
272 | */
273 | export function ajax(url) {
274 | if (DEV_MODE === true) {
275 | url = url + antiCache();
276 | }
277 | return new Promise(function(resolve, reject) {
278 | let req = new XMLHttpRequest();
279 | req.open("GET", url);
280 | req.onload = function() {
281 | if (req.status === 200) {
282 | resolve(req.response);
283 | } else {
284 | reject(new Error(req.statusText));
285 | }
286 | };
287 | req.onerror = function() {
288 | reject(new Error("Network error"));
289 | };
290 | req.send();
291 | });
292 | }
--------------------------------------------------------------------------------
/src/Game/entities/Light/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | LEFT, RIGHT, UP, DOWN,
3 | OFFLINE_MODE,
4 | DIMENSION, GRAVITY,
5 | TYPES
6 | } from "../../../cfg";
7 |
8 | import math from "../../../Math";
9 |
10 | import {
11 | Maps
12 | } from "../../../Engine/utils";
13 |
14 | import MapEntity from "../../../Engine/Map/MapEntity";
15 |
16 | export class Light extends MapEntity {
17 |
18 | /**
19 | * @constructor
20 | * @param {Object} obj
21 | */
22 | constructor(obj) {
23 |
24 | super(obj);
25 |
26 | this.scale = .25;
27 |
28 | this.name = "light" + this.id;
29 |
30 | this.zIndex = 999999;
31 |
32 | this.isLight = true;
33 |
34 | this.lightSize = obj.lightSize === void 0 ? 512 : obj.lightSize;
35 |
36 | this.jumpable = false;
37 |
38 | this.hasShadow = false;
39 |
40 | this.lightSize = obj.lightSize === void 0 ? 256 : obj.lightSize;
41 |
42 | this.soft = obj.soft === void 0 ? true : obj.soft;
43 |
44 | this.color = this.processColor(obj.color);
45 |
46 | this.type = TYPES.Light;
47 |
48 | }
49 |
50 | /**
51 | * Process hex color
52 | * @param {String} color
53 | * @return {Array}
54 | */
55 | processColor(color) {
56 | let cString = color[0] === "#" ? color.substr(1) : color;
57 | return (
58 | math.hexToRGB(cString)
59 | );
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/src/Game/entities/Monster.js:
--------------------------------------------------------------------------------
1 | import Entity from "../../Engine/Entity";
2 |
3 | export class Monster extends Entity {
4 |
5 | /**
6 | * @constructor
7 | * @param {Object} obj
8 | */
9 | constructor(obj) {
10 | super(obj);
11 | this.init(obj)
12 | }
13 |
14 | init() { console.log(this); }
15 |
16 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/face.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE
3 | } from "../../../cfg";
4 |
5 | /**
6 | * Change facing
7 | * @param {Number} dir
8 | */
9 | export function changeFacing(dir) {
10 |
11 | if (this.STATES.LOCK === true || this.moving === true) return void 0;
12 |
13 | this.idleTime = 0;
14 |
15 | if (
16 | this.moving === false &&
17 | this.STATES.BUMPING === false
18 | ) {
19 | this.lastFacing = this.facing;
20 | this.facing = dir;
21 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
22 | this.instance.engine.connection.sendData(
23 | "Facing",
24 | [this.id, this.facing]
25 | );
26 | }
27 | this.frame = (this.frame + 3 + this.getFrameIndex()) % 4;
28 | }
29 |
30 | /** TODO: Avoid settimeout */
31 | setTimeout(this::function() {
32 | if (
33 | this.moving === false &&
34 | this.STATES.BUMPING === false &&
35 | this.STATES.JUMPING === false
36 | ) {
37 | this.resetFrame();
38 | }
39 | }, 30);
40 |
41 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/follow.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION
3 | } from "../../../cfg";
4 |
5 | /**
6 | * Follow a entity
7 | * @param {Number} x
8 | * @param {Number} y
9 | * @param {Boolean} obstacle
10 | */
11 | export function follow(x, y, obstacle) {
12 |
13 | let leader = this.leader;
14 |
15 | if (obstacle === false) {
16 | if (
17 | leader.x << 0 === this.followTarget.x << 0 &&
18 | leader.y << 0 === this.followTarget.y << 0
19 | ) {
20 | leader.walkTo(
21 | x << 0,
22 | y << 0
23 | );
24 | this.followTarget.x = x << 0;
25 | this.followTarget.y = y << 0;
26 | /** Target has moved to new position */
27 | }
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/jump.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE,
3 | GRAVITY
4 | } from "../../../cfg";
5 |
6 | import {
7 | Maps
8 | } from "../../../Engine/utils";
9 |
10 | /**
11 | * Jump
12 | */
13 | export function jump() {
14 |
15 | if (this.jumpable === false) return void 0;
16 |
17 | this.refreshState();
18 |
19 | if (
20 | this.STATES.JUMPING === true ||
21 | this.STATES.LOCK === true
22 | ) return void 0;
23 |
24 | this.STATES.JUMPING = true;
25 |
26 | if (this.onJump !== null) {
27 | Maps[this.map].triggerEvent(this, this, "onJump");
28 | }
29 |
30 | this.jumping();
31 |
32 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
33 | this.instance.engine.connection.sendData(
34 | "Jumping",
35 | [this.id]
36 | );
37 | }
38 |
39 | this.idleTime = 0;
40 |
41 | }
42 |
43 | /**
44 | * Jumping
45 | */
46 | export function jumping() {
47 |
48 | this.frame = 3;
49 |
50 | if (this.z === 0) {
51 | this.playStateSound();
52 | }
53 |
54 | this.z += this.gravity;
55 |
56 | this.refreshState();
57 |
58 | if (this.z < 0) {
59 | this.gravity += .1;
60 | this.shadow.position.set(-(this.z / 2), this.shadowY - (this.z));
61 | this.shadow.scale.set(this.z, this.z);
62 | } else {
63 | this.gravity = GRAVITY;
64 | this.z = 0;
65 | this.resetFrame();
66 | this.refreshState();
67 | this.shadow.position.set(this.shadowX, this.shadowY);
68 | this.shadow.scale.set(0, 0);
69 |
70 | if (this.isLocalPlayer === true) {
71 | this.instance.engine.everythingJump();
72 | this.instance.engine.everythingRotate(1);
73 | }
74 |
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/new/face.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE
3 | } from "../../../cfg";
4 |
5 | /**
6 | * Change facing
7 | * @param {Number} dir
8 | */
9 | export function changeFacing(dir) {
10 |
11 | if (this.STATES.LOCK === true || this.moving === true) return void 0;
12 |
13 | this.idleTime = 0;
14 |
15 | if (
16 | this.moving === false &&
17 | this.STATES.BUMPING === false
18 | ) {
19 | this.lastFacing = this.facing;
20 | this.facing = dir;
21 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
22 | this.instance.engine.connection.sendData(
23 | "Facing",
24 | [this.id, this.facing]
25 | );
26 | }
27 | this.frame = (this.frame + 3 + this.getFrameIndex()) % 4;
28 | }
29 |
30 | /** TODO: Avoid settimeout */
31 | setTimeout(this::function() {
32 | if (
33 | this.moving === false &&
34 | this.STATES.BUMPING === false &&
35 | this.STATES.JUMPING === false
36 | ) {
37 | this.resetFrame();
38 | }
39 | }, 30);
40 |
41 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/new/index.js:
--------------------------------------------------------------------------------
1 | import math from "../../../Math";
2 | import {
3 | OFFLINE_MODE,
4 | DIMENSION, GRAVITY
5 | } from "../../../cfg";
6 |
7 | import {
8 | Maps
9 | } from "../../../Engine/utils";
10 |
11 | import { inherit } from "../../../Engine/utils";
12 |
13 | import Entity from "../../../Engine/Entity";
14 |
15 | import * as jump from "./jump";
16 | import * as walk from "./walk";
17 | import * as face from "./face";
18 | import * as sound from "./sound";
19 |
20 | export class Player extends Entity {
21 |
22 | /**
23 | * @constructor
24 | * @param {Object} obj
25 | */
26 | constructor(obj) {
27 |
28 | super(obj);
29 |
30 | /**
31 | * Local entity requires instance ref
32 | * @type {Object}
33 | */
34 | this.instance = null;
35 |
36 | /**
37 | * Gravity
38 | * @type {Number}
39 | */
40 | this.gravity = GRAVITY;
41 |
42 | /**
43 | * Player facing
44 | * @type {Number}
45 | */
46 | this.facing = 0;
47 |
48 | /**
49 | * Idle state
50 | * @type {Number}
51 | */
52 | this.idle = 0;
53 |
54 | /**
55 | * States
56 | * @type {Object}
57 | */
58 | this.STATES["WALKING"] = false;
59 | this.STATES["RUNNING"] = false;
60 | this.STATES["BUMPING"] = false;
61 | this.STATES["WALKING"] = false;
62 | this.STATES["FACING"] = false;
63 |
64 | /**
65 | * Shadow offsets
66 | * @type {Number}
67 | */
68 | this.shadowX = obj.shadowX === void 0 ? 0 : obj.shadowX;
69 | this.shadowY = obj.shadowY === void 0 ? -1.75 : obj.shadowY;
70 |
71 | /**
72 | * Local player check
73 | * @type {Boolean}
74 | */
75 | this.isLocalPlayer = false;
76 |
77 | /**
78 | * NPC check
79 | * @type {Boolean}
80 | */
81 | this.isNPC = false;
82 |
83 | /**
84 | * Network player check
85 | * @type {Boolean}
86 | */
87 | this.isNetworkPlayer = false;
88 |
89 | /**
90 | * Animation frames
91 | * @type {Array}
92 | */
93 | this.frames = [0, 1, 0, 2, 3, 4];
94 |
95 | /**
96 | * Reset frame
97 | * @type {Array}
98 | */
99 | this.frameReset = [0, 2, 2, 0];
100 |
101 | /**
102 | * Last facing
103 | * @type {Number}
104 | */
105 | this.lastFacing = 0;
106 |
107 | /**
108 | * Step count
109 | * @type {Number}
110 | */
111 | this.stepCount = 0;
112 |
113 | /**
114 | * Face count
115 | * @type {Number}
116 | */
117 | this.faceCount = 0;
118 |
119 | /**
120 | * Latency
121 | * @type {Number}
122 | */
123 | this.latency = .5;
124 |
125 | /**
126 | * Map the player is on
127 | * @type {String}
128 | */
129 | this.map = obj.map;
130 |
131 | /**
132 | * Step sound
133 | * @type {Number}
134 | */
135 | this.soundSteps = DIMENSION * 2;
136 |
137 | this.xMargin = -(DIMENSION / 2);
138 | this.yMargin = -DIMENSION;
139 |
140 | if (
141 | obj.x !== void 0 &&
142 | obj.y !== void 0
143 | ) {
144 | this.x = obj.x;
145 | this.y = obj.y;
146 | }
147 |
148 | this.init(obj);
149 |
150 | }
151 |
152 | /**
153 | * @getter
154 | * @return {Number}
155 | */
156 | get velocity() {
157 | return (this.latency);
158 | }
159 |
160 | /**
161 | * @param {Number} value
162 | * @setter
163 | */
164 | set velocity(value) {
165 | this.latency = value / 2;
166 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
167 | this.instance.engine.connection.sendData(
168 | "Velocity",
169 | [this.id, value]
170 | );
171 | }
172 | this.refreshState();
173 | }
174 |
175 | /**
176 | * Player is moving
177 | * @return {Boolean}
178 | * @getter
179 | */
180 | get moving() {
181 | return (
182 | this.STATES.WALKING === true ||
183 | this.STATES.RUNNING === true
184 | );
185 | }
186 |
187 | /**
188 | * Player is moving
189 | * @param {Boolean} value
190 | * @setter
191 | */
192 | set moving(value) {
193 | this.STATES.WALKING = value;
194 | this.STATES.RUNNING = value;
195 | }
196 |
197 | /**
198 | * Initialise
199 | * @param {Object} obj
200 | */
201 | init(obj) {
202 | this.setPlayerType(obj);
203 | }
204 |
205 | /**
206 | * Set player entity type
207 | * @param {Object} obj
208 | */
209 | setPlayerType(obj) {
210 |
211 | if (obj.isLocalPlayer === true) {
212 | this.isLocalPlayer = true;
213 | this.isNPC = false;
214 | this.isNetworkPlayer = false;
215 | }
216 | else if (obj.isNPC === true) {
217 | this.isLocalPlayer = false;
218 | this.isNPC = true;
219 | this.isNetworkPlayer = false;
220 | }
221 | else if (obj.isNetworkPlayer === true) {
222 | this.isLocalPlayer = false;
223 | this.isNPC = false;
224 | this.isNetworkPlayer = true;
225 | }
226 | /** Default is npc */
227 | else {
228 | this.isLocalPlayer = false;
229 | this.isNPC = true;
230 | this.isNetworkPlayer = false;
231 | }
232 |
233 | }
234 |
235 | /**
236 | * Get frame index
237 | * @return {Number}
238 | */
239 | getFrameIndex() {
240 | return (
241 | this.STATES.RUNNING === true ? 2 : 0
242 | );
243 | }
244 |
245 | /** Reset sprite frame */
246 | resetFrame() {
247 | this.frame = this.frameReset[this.frame] + this.getFrameIndex();
248 | }
249 |
250 | /** Refresh entity states */
251 | refreshState() {
252 | this.STATES.RUNNING = this.velocity === .5 ? false : this.velocity === 1 && this.STATES.WALKING === true ? true : false;
253 | this.STATES.JUMPING = this.z !== 0;
254 | }
255 |
256 | /** Trigger faced tile */
257 | action() {
258 | let position = math.getTilePosition(this.x << 0, this.y << 0, this.facing);
259 | Maps[this.map].actionTrigger(position, this);
260 | }
261 |
262 | /**
263 | * Face a entity
264 | * @param {Object} entity
265 | */
266 | faceEntity(entity) {
267 | if (entity === null) return void 0;
268 | let facing = this.oppositFacing(entity.facing);
269 | if (this.facing !== facing) {
270 | this.changeFacing(facing);
271 | }
272 | }
273 |
274 | /** Animate */
275 | animate() {
276 |
277 | if (this.animations.length <= 0) return void 0;
278 |
279 | if (this.animations[0] !== void 0 && this.animations[0].type === "fade") {
280 | this.fade(this.animations[0]);
281 | }
282 |
283 | if (this.animations[0] !== void 0 && this.animations[0].type === "jump") {
284 | this.jumpAnimation();
285 | }
286 |
287 | if (this.animations[0] !== void 0 && this.animations[0].type === "move") {
288 | this.moveAnimation(this.animations[0]);
289 | }
290 |
291 | if (this.animations[0] !== void 0 && this.animations[0].type === "bump") {
292 | this.bumpAnimation(this.animations[0]);
293 | }
294 |
295 | }
296 |
297 | }
298 |
299 | inherit(Player, jump);
300 | inherit(Player, walk);
301 | inherit(Player, face);
302 | inherit(Player, sound);
--------------------------------------------------------------------------------
/src/Game/entities/Player/new/jump.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE,
3 | GRAVITY
4 | } from "../../../cfg";
5 |
6 | import {
7 | Maps
8 | } from "../../../Engine/utils";
9 |
10 | export function jump() {
11 |
12 | if (
13 | this.STATES.JUMPING === true ||
14 | this.STATES.LOCK === true
15 | ) return void 0;
16 |
17 | this.animations.push({
18 | type: "jump"
19 | });
20 |
21 | }
22 |
23 | /**
24 | * Jump
25 | */
26 | export function jumpAnimation() {
27 |
28 | if (this.jumpable === false) return void 0;
29 |
30 | this.refreshState();
31 |
32 | if (this.onJump !== null) {
33 | Maps[this.map].triggerEvent(this, this, "onJump");
34 | }
35 |
36 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
37 | this.instance.engine.connection.sendData(
38 | "Jumping",
39 | [this.id]
40 | );
41 | }
42 |
43 | this.idleTime = 0;
44 |
45 | this.jumping();
46 |
47 | }
48 |
49 | /**
50 | * Jumping
51 | */
52 | export function jumping() {
53 |
54 | if (this.frame === 0 && this.z === 0) {
55 | this.playStateSound();
56 | }
57 |
58 | this.frame = 3;
59 |
60 | this.z += this.gravity;
61 |
62 | this.refreshState();
63 |
64 | if (this.z < 0) {
65 | this.gravity += .1;
66 | this.shadow.position.set(-(this.z / 2), this.shadowY - (this.z));
67 | this.shadow.scale.set(this.z, this.z);
68 | } else {
69 | this.gravity = GRAVITY;
70 | this.z = 0;
71 | this.resetFrame();
72 | this.refreshState();
73 | this.shadow.position.set(this.shadowX, this.shadowY);
74 | this.shadow.scale.set(0, 0);
75 | this.animations.shift();
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/new/sound.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION,
3 | BGS, VOLUME
4 | } from "../../../cfg";
5 |
6 | import {
7 | Maps
8 | } from "../../../Engine/utils";
9 |
10 | import Audio from "../../../Engine/Audio";
11 |
12 | /**
13 | * Play sound
14 | */
15 | export function playStateSound() {
16 |
17 | if (BGS !== true) return void 0;
18 |
19 | let volume = this.isLocalPlayer === true ? VOLUME.NETWORK_PLAYER : VOLUME.LOCAL_PLAYER;
20 |
21 | let dist = Maps[this.map].distance(this, game.engine.camera);
22 |
23 | if (this.STATES.JUMPING === true && this.z === 0) {
24 | Audio.playSound("jump", volume, dist.x, dist.y);
25 | }
26 |
27 | /** Player is bumping */
28 | if (this.STATES.BUMPING === true) {
29 | Audio.playSound("bump", volume, dist.x, dist.y);
30 | /** Player is walking */
31 | } else {
32 | if (this.moving === true) {
33 | if (this.soundSteps >= DIMENSION * 2) {
34 | this.soundSteps = 0;
35 | if (this.STATES.RUNNING === true) {
36 | Audio.playSound("run_step", volume, dist.x, dist.y);
37 | } else {
38 | Audio.playSound("ground_step", volume, dist.x, dist.y);
39 | }
40 | }
41 | }
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/new/walk.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE,
3 | Y_DEPTH_HACK,
4 | DIMENSION,
5 | LEFT, RIGHT, UP, DOWN,
6 | GOD_MODE
7 | } from "../../../cfg";
8 |
9 | import {
10 | Maps
11 | } from "../../../Engine/utils";
12 |
13 | import math from "../../../Math";
14 |
15 | export function move(dir, resolve) {
16 |
17 | if (
18 | this.STATES.LOCK === true ||
19 | this.STATES.EDITING === true ||
20 | this.moving === true
21 | ) return void 0;
22 |
23 | let x = this.x;
24 | let y = this.y;
25 |
26 | let position = math.getTilePosition(x, y, dir);
27 | let obstacle = Maps[this.map].isObstacle(this, dir);
28 |
29 | if (this.isLocalPlayer === true && GOD_MODE === true) {
30 | obstacle = false;
31 | }
32 |
33 | if (this.isLocalPlayer === true && OFFLINE_MODE === false) {
34 | this.instance.engine.connection.sendData(
35 | "Position",
36 | [this.id, dir, x, y]
37 | );
38 | }
39 |
40 | /** Blocked, bump so */
41 | if (obstacle === true) {
42 | this.animations.push({
43 | type: "bump",
44 | x: x,
45 | y: y
46 | });
47 | this.STATES.BUMPING = true;
48 | /** Crossable */
49 | } else {
50 | this.animations.push({
51 | type: "move",
52 | obstacle: obstacle,
53 | x: position.x,
54 | y: position.y,
55 | oX: x,
56 | oY: y
57 | });
58 | this.moving = true;
59 | }
60 |
61 | this.idleTime = 0;
62 |
63 | }
64 |
65 | /**
66 | * Do halfstep
67 | */
68 | export function halfStep() {
69 |
70 | let half = Math.ceil(Math.ceil(DIMENSION / (this.velocity * 2)) / 2);
71 |
72 | if (this.stepCount === half) {
73 | this.frame = (this.frame + 1 + this.getFrameIndex()) % 4;
74 | }
75 |
76 | }
77 |
78 | /**
79 | * Bump
80 | * @param {Object} animation
81 | */
82 | export function bumpAnimation(animation) {
83 |
84 | if (this.stepCount <= 0) {
85 | this.playStateSound();
86 | }
87 |
88 | this.stepCount += .5;
89 |
90 | if (this.STATES.JUMPING === false) {
91 | this.halfStep();
92 | }
93 |
94 | if (this.stepCount >= DIMENSION * 2) {
95 | if (this.STATES.JUMPING === false) {
96 | this.halfStep();
97 | this.resetFrame();
98 | }
99 | this.stepCount = 0;
100 | this.animations.shift();
101 | this.STATES.BUMPING = false;
102 | this.refreshState();
103 | }
104 |
105 | }
106 |
107 | /**
108 | * Walk
109 | * @param {Object} animation
110 | */
111 | export function moveAnimation(animation) {
112 |
113 | if (this.stepCount <= 0) {
114 | if (this.STATES.JUMPING === false) {
115 | this.resetFrame();
116 | }
117 | if (animation.obstacle === false) {
118 | /** onEnter event => animation.x, animation.y */
119 | }
120 | }
121 |
122 | this.playStateSound();
123 |
124 | if (animation.obstacle === false) {
125 | if (this.STATES.JUMPING === false) {
126 | this.halfStep();
127 | }
128 | if (this.x > animation.x) {
129 | this.x -= this.velocity;
130 | }
131 | else if (this.x < animation.x) {
132 | this.x += this.velocity;
133 | }
134 | else if (this.y > animation.y) {
135 | this.y -= this.velocity;
136 | }
137 | else if (this.y < animation.y) {
138 | this.y += this.velocity;
139 | }
140 | this.stepCount += this.velocity;
141 | } else {
142 | animation.x = this.x;
143 | animation.y = this.y;
144 | this.stopMoving(animation);
145 | }
146 |
147 | if (this.stepCount >= DIMENSION) {
148 | this.lastFacing = this.facing;
149 | this.stopMoving(animation);
150 | }
151 |
152 | this.soundSteps += this.velocity;
153 |
154 | }
155 |
156 | /**
157 | * Stop moving
158 | * @param {Object} animation
159 | */
160 | export function stopMoving(animation) {
161 |
162 | this.x = animation.x;
163 | this.y = animation.y + Y_DEPTH_HACK;
164 |
165 | this.last.x = animation.oX;
166 | this.last.y = animation.oY;
167 |
168 | this.moving = false;
169 |
170 | this.stepCount = 0;
171 |
172 | setTimeout(this::function() {
173 | if (
174 | this.moving === false &&
175 | this.STATES.BUMPING === false &&
176 | this.STATES.JUMPING === false
177 | ) {
178 | this.resetFrame();
179 | }
180 | }, 100);
181 |
182 | this.animations.shift();
183 |
184 | this.refreshState();
185 |
186 | /** Continue moving */
187 | if (this.isLocalPlayer === true) {
188 | if (this.instance.input.KeyBoard.isKeyPressed(this.facingToKey(LEFT)) === true) {
189 | this.move(LEFT);
190 | }
191 | else if (this.instance.input.KeyBoard.isKeyPressed(this.facingToKey(UP)) === true) {
192 | this.move(UP);
193 | }
194 | else if (this.instance.input.KeyBoard.isKeyPressed(this.facingToKey(RIGHT)) === true) {
195 | this.move(RIGHT);
196 | }
197 | else if (this.instance.input.KeyBoard.isKeyPressed(this.facingToKey(DOWN)) === true) {
198 | this.move(DOWN);
199 | } else {
200 | this.soundSteps = DIMENSION;
201 | }
202 | } else {
203 | this.soundSteps = DIMENSION;
204 | }
205 |
206 | if (this.moveCB) {
207 | this.moveCB();
208 | }
209 |
210 | }
--------------------------------------------------------------------------------
/src/Game/entities/Player/sound.js:
--------------------------------------------------------------------------------
1 | import {
2 | DIMENSION,
3 | BGS, VOLUME
4 | } from "../../../cfg";
5 |
6 | import {
7 | Maps
8 | } from "../../../Engine/utils";
9 |
10 | import Audio from "../../../Engine/Audio";
11 |
12 | /**
13 | * Play sound
14 | */
15 | export function playStateSound() {
16 |
17 | if (BGS !== true) return void 0;
18 |
19 | let volume = this.isLocalPlayer === true ? VOLUME.NETWORK_PLAYER : VOLUME.LOCAL_PLAYER;
20 |
21 | let dist = Maps[this.map].distance(this, game.engine.camera);
22 |
23 | if (Math.abs(dist.x) + Math.abs(dist.y) >= 1.0) {
24 | dist.x *= 4;
25 | dist.y *= 4;
26 | }
27 |
28 | if (this.STATES.JUMPING === true && this.z === 0) {
29 | Audio.playSound("jump", volume, dist.x, dist.y);
30 | }
31 |
32 | /** Player is bumping */
33 | if (this.STATES.BUMPING === true) {
34 | Audio.playSound("bump", volume, dist.x, dist.y);
35 | /** Player is walking */
36 | } else {
37 | if (this.moving === true) {
38 | if (this.soundSteps >= DIMENSION * 2) {
39 | this.soundSteps = 0;
40 | if (this.STATES.RUNNING === true) {
41 | Audio.playSound("run_step", volume, dist.x, dist.y);
42 | } else {
43 | Audio.playSound("ground_step", volume, dist.x, dist.y);
44 | }
45 | }
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/Game/entities/index.js:
--------------------------------------------------------------------------------
1 | export { Light } from "./Light";
2 | export { Player } from "./Player";
3 | export { Monster } from "./Monster";
--------------------------------------------------------------------------------
/src/Game/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_MODE,
3 | LEFT, RIGHT, UP, DOWN,
4 | CONNECTION_URL, CONNECTION_PORT
5 | } from "../cfg";
6 |
7 | import Engine from "../Engine";
8 | import Renderer from "../Engine/Renderer";
9 | import Input from "../Engine/Input";
10 | import Connection from "../Engine/Connection";
11 |
12 | import * as Events from "./input.js";
13 | import * as entities from "./entities";
14 |
15 | /**
16 | * Game
17 | * @class Game
18 | * @export
19 | */
20 | export default class Game {
21 |
22 | /**
23 | * @constructor
24 | */
25 | constructor() {
26 |
27 | this.glNode = document.querySelector("#webgl");
28 | this.canvasNode = document.querySelector("#canvas");
29 |
30 | this.entities = entities;
31 |
32 | this.engine = new Engine(this, () => this.setup());
33 |
34 | }
35 |
36 | /**
37 | * Setup
38 | * @param {Number} stage
39 | */
40 | setup(stage = stage === void 0 ? 0 : stage) {
41 |
42 | switch (++stage) {
43 | case 1:
44 | this.engine.renderer = new Renderer(this.engine);
45 | window.rAF(() => this.engine.renderer.render());
46 | this.setup(stage);
47 | return void 0;
48 | case 2:
49 | this.addWorld(() => this.setup(stage));
50 | return void 0;
51 | case 3:
52 | this.addMap(() => this.setup(stage));
53 | return void 0;
54 | case 4:
55 | this.addEntities(() => this.setup(stage));
56 | return void 0;
57 | case 5:
58 | this.animateNPC();
59 | this.setup(stage);
60 | return void 0;
61 | case 6:
62 | /** Instant focus local player */
63 | this.engine.camera.focus(this.engine.getEntityByProperty("Felix", "name"), true);
64 | this.setup(stage);
65 | return void 0;
66 | case 7:
67 | this.input = new Input(Events, this);
68 | this.setup(stage);
69 | return void 0;
70 | case 8:
71 | if (!OFFLINE_MODE) {
72 | this.engine.connection = new Connection(
73 | this,
74 | `${CONNECTION_URL}:${CONNECTION_PORT}`
75 | );
76 | }
77 | this.setup(stage);
78 | return void 0;
79 | };
80 |
81 | return void 0;
82 |
83 | }
84 |
85 | animateNPC() {
86 | setTimeout(this::function() {
87 | let entity = this.engine.getEntityByProperty("Joy", "name");
88 | let move = [LEFT, RIGHT, UP, DOWN][(Math.random() * 3) << 0];
89 | entity.move(move);
90 | this.animateNPC();
91 | }, 2e3);
92 | }
93 |
94 | /**
95 | * Add world
96 | * @param {Function} resolve
97 | */
98 | addWorld(resolve) {
99 | this.engine.addWorld("worlds/kanto/index.js", resolve);
100 | }
101 |
102 | /**
103 | * Add map
104 | * @param {Function} resolve
105 | */
106 | addMap(resolve) {
107 | this.engine.addMap("worlds/kanto/town/town.json", resolve);
108 | }
109 |
110 | /**
111 | * Add entities
112 | * @param {Function} resolve
113 | */
114 | addEntities(resolve) {
115 |
116 | let player = this.entities.Player;
117 |
118 | this.engine.addEntity(new entities.Light({
119 | sprite: "assets/img/light.png",
120 | map: "Town",
121 | x: 168, y: 96,
122 | width: 32, height: 32,
123 | soft: false,
124 | color: "#E6E6E6"
125 | }));
126 |
127 | this.engine.addEntity(new player({ name: "Joy", map: "Town", x: 96, y: 144, sprite: "assets/img/200.png", width: 16, height: 16, collidable: true,
128 | facing: 1,
129 | onCollide: {
130 | JavaScript: function(entity, engine) {
131 | this.faceEntity(entity);
132 | engine.instance.notify(this, "Stop!");
133 | }
134 | }
135 | }));
136 |
137 | this.engine.addEntity(new player({ name: "Merlin", map: "Town", x: 160, y: 144, sprite: "assets/img/85.png", width: 16, height: 16, collidable: true, shadowY: -3, normal: true,
138 | onAction: {
139 | EngelScript: `
140 | if (trigger.facing == 2 || trigger.facing == 3) {
141 | FLAGS.COUNTER += 1;
142 | } {
143 | FLAGS.COUNTER -= 1;
144 | }
145 | kernel.notify(this, '+' + FLAGS.COUNTER + " ");
146 | this.faceEntity(trigger);
147 | `
148 | }
149 | }));
150 |
151 | this.engine.addEntity(new player({ name: "Merlin2", map: "Town", x: 136, y: 120, sprite: "assets/img/85.png", width: 16, height: 16, collidable: true, shadowY: -3, normal: true,
152 | onCollide: {
153 | EngelScript: `
154 | kernel.notify(this, trigger.name);
155 | `
156 | }
157 | }));
158 |
159 | this.engine.addEntity(new player({
160 | name: "Mew", map: "Town",
161 | sprite: "assets/img/151.png",
162 | width: 16, height: 16,
163 | collidable: false,
164 | following: "Joy"
165 | }));
166 |
167 | this.engine.addEntity(new player({
168 | name: "Charizard", map: "Town",
169 | sprite: "assets/img/4.png",
170 | width: 16, height: 16,
171 | collidable: false,
172 | following: "Felix",
173 | onAction: {
174 | EngelScript: `
175 | kernel.notify(this, ":p");
176 | trigger.leader.faceEntity(trigger);
177 | `
178 | },
179 | normal: true
180 | }));
181 |
182 | this.engine.addEntity(new player({
183 | name: "Flareon", map: "Town",
184 | sprite: "assets/img/136.png",
185 | width: 16, height: 16,
186 | collidable: false,
187 | following: "Mew"
188 | }));
189 |
190 | if (OFFLINE_MODE) {
191 | this.engine.addEntity(new player({
192 | name: "Felix", map: "Town", x: 144, y: 152, sprite: "assets/img/0.png", width: 16, height: 16, isLocalPlayer: true, collidable: true, normal: true,
193 | onJump: (entity, map) => {
194 | if (entity.leader) {
195 | setTimeout(() => map.instance.notify(entity.leader, " :3 "), 250);
196 | setTimeout(() => entity.leader.jump(), 500);
197 | }
198 | }
199 | }));
200 | }
201 |
202 | return (resolve());
203 |
204 | }
205 |
206 | }
207 |
208 | window.game = new Game();
--------------------------------------------------------------------------------
/src/Game/input.js:
--------------------------------------------------------------------------------
1 | export const keys = [
2 | {
3 | name: "SHIFT",
4 | fire: function() {},
5 | leave: function() {
6 | this.action("SHIFT");
7 | }
8 | },
9 | {
10 | name: "CTRL+Z",
11 | simultaneous: false,
12 | fire: function() {
13 | this.action("CTRL+Z");
14 | }
15 | },
16 | {
17 | name: "CTRL+Y",
18 | simultaneous: false,
19 | fire: function() {
20 | this.action("CTRL+Y");
21 | }
22 | },
23 | {
24 | name: "CTRL+C",
25 | spam: false,
26 | simultaneous: false,
27 | fire: function() {
28 | this.action("CTRL+C");
29 | }
30 | },
31 | {
32 | name: "CTRL+V",
33 | spam: false,
34 | simultaneous: false,
35 | fire: function() {
36 | this.action("CTRL+V");
37 | }
38 | },
39 | {
40 | name: "CTRL+X",
41 | spam: false,
42 | simultaneous: false,
43 | fire: function() {
44 | this.action("CTRL+X");
45 | }
46 | },
47 | {
48 | name: "DELETE",
49 | fire: function() {
50 | this.action("DELETE");
51 | }
52 | },
53 | {
54 | name: "F1",
55 | spam: false,
56 | fire: function() {
57 | this.action("F1");
58 | }
59 | },
60 | {
61 | name: "F2",
62 | spam: false,
63 | fire: function() {
64 | this.action("F2");
65 | }
66 | },
67 | {
68 | name: "F3",
69 | spam: false,
70 | fire: function() {
71 | this.action("F3");
72 | }
73 | },
74 | {
75 | name: "F4",
76 | spam: false,
77 | fire: function() {
78 | this.action("F4");
79 | }
80 | },
81 | {
82 | name: "F6",
83 | spam: false,
84 | fire: function() {
85 | this.action("F6");
86 | }
87 | },
88 | /** BUGGY, KEY COMBOS DONT WORK WITHOUT THIS */
89 | {
90 | name: "Y",
91 | fire: function() {}
92 | },
93 | /** BUGGY, KEY COMBOS DONT WORK WITHOUT THIS */
94 | {
95 | name: "G",
96 | fire: function() {}
97 | },
98 | /** BUGGY, KEY COMBOS DONT WORK WITHOUT THIS */
99 | {
100 | name: "V",
101 | fire: function() {}
102 | },
103 | /** BUGGY, KEY COMBOS DONT WORK WITHOUT THIS */
104 | {
105 | name: "CTRL",
106 | fire: function() {}
107 | },
108 | {
109 | name: "ESCAPE",
110 | spam: false,
111 | fire: function() {
112 | this.action("ESCAPE");
113 | }
114 | },
115 | {
116 | name: "B",
117 | spam: false,
118 | fire: function() {
119 | this.action("B");
120 | }
121 | },
122 | {
123 | name: "Z",
124 | spam: false,
125 | fire: function() {
126 | this.action("Z");
127 | }
128 | },
129 | {
130 | name: "X",
131 | spam: false,
132 | fire: function() {
133 | this.action("X_FIRE");
134 | },
135 | leave: function() {
136 | this.action("X_LEAVE");
137 | }
138 | },
139 | {
140 | name: "C",
141 | spam: false,
142 | fire: function() {
143 | this.action("C");
144 | }
145 | },
146 | {
147 | name: "←",
148 | fire: function() {
149 | this.action("←");
150 | }
151 | },
152 | {
153 | name: "→",
154 | fire: function() {
155 | this.action("→");
156 | }
157 | },
158 | {
159 | name: "↑",
160 | fire: function() {
161 | this.action("↑");
162 | }
163 | },
164 | {
165 | name: "↓",
166 | fire: function() {
167 | this.action("↓");
168 | }
169 | },
170 | {
171 | name: "SPACE",
172 | fire: function() {
173 | this.action("SPACE");
174 | }
175 | }
176 | ];
177 |
178 | export const mouse = [
179 | {
180 | name: "dblclick",
181 | fire: function(e) {
182 | this.action("DBLCLICK", [e]);
183 | }
184 | },
185 | {
186 | name: "mousedown|touchstart",
187 | fire: function(e) {
188 | this.action("LEFTCLICK", [e]);
189 | }
190 | },
191 | {
192 | name: "contextmenu",
193 | fire: function(e) {
194 | this.action("RIGHTCLICK", [e]);
195 | }
196 | },
197 | {
198 | name: "mouseup|touchend",
199 | fire: function(e) {
200 | this.action("MOUSEUP", [e]);
201 | }
202 | },
203 | {
204 | name: "mousemove|touchmove",
205 | fire: function(e) {
206 | this.action("MOUSEMOVE", [e]);
207 | }
208 | },
209 | {
210 | name: "mousewheel",
211 | fire: function(e) {
212 | this.action("MOUSEWHEEL", [e]);
213 | }
214 | }
215 | ];
216 |
217 | export const global = [
218 | {
219 | name: "resize",
220 | fire: function(e) {
221 | this.action("RESIZE");
222 | }
223 | }
224 | ];
--------------------------------------------------------------------------------
/src/Packets/Facing.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Facing packet
3 | * @class Facing
4 | * @export
5 | */
6 | export class Facing {
7 |
8 | /**
9 | * @param {Number} id
10 | * @param {Number} dir
11 | * @return {Object}
12 | * @constructor
13 | */
14 | constructor(id, dir) {
15 |
16 | /**
17 | * Entity id
18 | * @type {Number}
19 | */
20 | this.id = id;
21 |
22 | /**
23 | * Direction
24 | * @type {Number}
25 | */
26 | this.dir = dir;
27 |
28 | return (this.encode());
29 |
30 | }
31 |
32 | /**
33 | * Encode process
34 | * @return {Object}
35 | */
36 | encode() {
37 |
38 | let buffer = new ArrayBuffer(5);
39 | let view = new DataView(buffer);
40 |
41 | view.setUint8(0, 31, true);
42 | view.setUint16(1, this.id, true);
43 | view.setUint16(3, this.dir, true);
44 |
45 | return (view);
46 |
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/Packets/Jumping.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Jumping packet
3 | * @class Jumping
4 | * @export
5 | */
6 | export class Jumping {
7 |
8 | /**
9 | * @param {Number} id
10 | * @return {Object}
11 | * @constructor
12 | */
13 | constructor(id) {
14 |
15 | /**
16 | * Entity id
17 | * @type {Number}
18 | */
19 | this.id = id;
20 |
21 | return (this.encode());
22 |
23 | }
24 |
25 | /**
26 | * Encode process
27 | * @return {Object}
28 | */
29 | encode() {
30 |
31 | let buffer = new ArrayBuffer(3);
32 | let view = new DataView(buffer);
33 |
34 | view.setUint8(0, 30, true);
35 | view.setUint16(1, this.id, true);
36 |
37 | return (view);
38 |
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/src/Packets/Position.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Position packet
3 | * @class Position
4 | * @export
5 | */
6 | export class Position {
7 |
8 | /**
9 | * @param {Number} id
10 | * @param {Number} dir
11 | * @param {Number} x
12 | * @param {Number} y
13 | * @return {Object}
14 | * @constructor
15 | */
16 | constructor(id, dir, x, y) {
17 |
18 | /**
19 | * Entity id
20 | * @type {Number}
21 | */
22 | this.id = id;
23 |
24 | /**
25 | * Direction
26 | * @type {Number}
27 | */
28 | this.dir = dir;
29 |
30 | /**
31 | * X
32 | * @type {Number}
33 | */
34 | this.x = x;
35 |
36 | /**
37 | * Y
38 | * @type {Number}
39 | */
40 | this.y = y;
41 |
42 | return (this.encode());
43 |
44 | }
45 |
46 | /**
47 | * Encode process
48 | * @return {Object}
49 | */
50 | encode() {
51 |
52 | let buffer = new ArrayBuffer(9);
53 | let view = new DataView(buffer);
54 |
55 | view.setUint8(0, 32, true);
56 | view.setUint16(1, this.id, true);
57 | view.setUint16(3, this.dir, true);
58 | view.setUint16(5, this.x, true);
59 | view.setUint16(7, this.y, true);
60 |
61 | return (view);
62 |
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/src/Packets/Velocity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Velocity packet
3 | * @class Velocity
4 | * @export
5 | */
6 | export class Velocity {
7 |
8 | /**
9 | * @param {Number} id
10 | * @param {Number} velocity
11 | * @return {Object}
12 | * @constructor
13 | */
14 | constructor(id, velocity) {
15 |
16 | /**
17 | * Entity id
18 | * @type {Number}
19 | */
20 | this.id = id;
21 |
22 | /**
23 | * Velocity
24 | * @type {Number}
25 | */
26 | this.velocity = velocity;
27 |
28 | return (this.encode());
29 |
30 | }
31 |
32 | /**
33 | * Encode process
34 | * @return {Object}
35 | */
36 | encode() {
37 |
38 | let buffer = new ArrayBuffer(5);
39 | let view = new DataView(buffer);
40 |
41 | view.setUint8(0, 33, true);
42 | view.setUint16(1, this.id, true);
43 | view.setUint16(3, this.velocity, true);
44 |
45 | return (view);
46 |
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/Packets/index.js:
--------------------------------------------------------------------------------
1 | export { Facing } from "./Facing";
2 | export { Jumping } from "./Jumping";
3 | export { Position } from "./Position";
4 | export { Velocity } from "./Velocity";
--------------------------------------------------------------------------------
/src/cfg.js:
--------------------------------------------------------------------------------
1 | import { supportWGL, getLocalHost } from "./Engine/utils";
2 |
3 | /**
4 | * Canvas rendering mode
5 | * @constant
6 | * @type {Number}
7 | */
8 | export const CANVAS = 0;
9 |
10 | /**
11 | * WebGL rendering mode
12 | * @constant
13 | * @type {Number}
14 | */
15 | export const WGL = 1;
16 |
17 | /**
18 | * Game rendering mode
19 | * @type {Number}
20 | */
21 | export let RENDER_MODE = -1;
22 |
23 | /**
24 | * Grid width
25 | * @constant
26 | * @type {Number}
27 | */
28 | export const GRID_WIDTH = 1;
29 |
30 | /**
31 | * Local player name
32 | * @type {String}
33 | */
34 | export let LOCAL_PLAYER = null;
35 |
36 | /**
37 | * Connection url
38 | * @constant
39 | * @type {String}
40 | */
41 | export const CONNECTION_URL = getLocalHost();
42 |
43 | /**
44 | * Connection port
45 | * @constant
46 | * @type {String}
47 | */
48 | export const CONNECTION_PORT = 449;
49 |
50 | /**
51 | * @constant
52 | * @type {String}
53 | */
54 | export const __dirname = "./src/";
55 |
56 | /**
57 | * Version
58 | * @constant
59 | * @type {String}
60 | */
61 | export const VERSION = "0.1.0";
62 |
63 | /**
64 | * WebGL support
65 | * @constant
66 | * @type {Boolean}
67 | */
68 | export const WGL_SUPPORT = supportWGL();
69 |
70 | /**
71 | * Walk by keyboard
72 | * @constant
73 | * @type {Boolean}
74 | */
75 | export const WALK_BY_KEYBOARD = true;
76 |
77 | /**
78 | * Free camera
79 | * @type {Boolean}
80 | */
81 | export let FREE_CAMERA = false;
82 |
83 | /**
84 | * Easing camera
85 | * @type {Boolean}
86 | */
87 | export let EASING_CAMERA = false;
88 |
89 | /**
90 | * Developer mode
91 | * @type {Boolean}
92 | */
93 | export let DEV_MODE = true;
94 |
95 | /**
96 | * Debug mode
97 | * @type {Boolean}
98 | */
99 | export let DEBUG_MODE = false;
100 |
101 | /**
102 | * Offline mode
103 | * @constant
104 | * @type {Boolean}
105 | */
106 | export let OFFLINE_MODE = true;
107 |
108 | /**
109 | * Record mode
110 | * @type {Boolean}
111 | */
112 | export let RECORD_MODE = true;
113 |
114 | /**
115 | * Edit mode
116 | * @type {Boolean}
117 | */
118 | export let EDIT_MODE = true;
119 |
120 | /**
121 | * God mode
122 | * @type {Boolean}
123 | */
124 | export let GOD_MODE = false;
125 |
126 | /**
127 | * Tileset drawind mode
128 | * @type {Boolean}
129 | */
130 | export let TILESET_MODE = true;
131 |
132 | /**
133 | * Debug mode
134 | * @type {Boolean}
135 | */
136 | export let MINI_MAP = true;
137 |
138 | /**
139 | * Debug fps
140 | * @constant
141 | * @type {Number}
142 | */
143 | export const DEBUG_FPS = 60;
144 |
145 | /**
146 | * Vertical depth sorting hack
147 | * @constant
148 | * @type {Number}
149 | */
150 | export const Y_DEPTH_HACK = .0001;
151 |
152 | /**
153 | * @constant
154 | * @type {Number}
155 | */
156 | export const DIMENSION = 8;
157 |
158 | /**
159 | * PP rounding
160 | * @constant
161 | * @type {Number}
162 | */
163 | export const PIXEL_SCALE = .125;
164 |
165 | /**
166 | * @constant
167 | * @type {Number}
168 | */
169 | export const MIN_SCALE = 3.0;
170 |
171 | /**
172 | * @constant
173 | * @type {Number}
174 | */
175 | export const MAX_SCALE = 12.5;
176 |
177 | /**
178 | * Display shadows
179 | * @constant
180 | * @type {Boolean}
181 | */
182 | export const DISPLAY_SHADOWS = true;
183 |
184 | /**
185 | * Shadow x scale
186 | * @constant
187 | * @type {Number}
188 | */
189 | export const SHADOW_X = 1.0;
190 |
191 | /**
192 | * Shadow y scale
193 | * @constant
194 | * @type {Number}
195 | */
196 | export const SHADOW_Y = 1.45;
197 |
198 | /**
199 | * Shadow alpha
200 | * @type {Number}
201 | */
202 | export let SHADOW_ALPHA = .85;
203 |
204 | /**
205 | * Direction
206 | * @constant
207 | * @type {Number}
208 | */
209 | export const LEFT = 3;
210 |
211 | /**
212 | * Direction
213 | * @constant
214 | * @type {Number}
215 | */
216 | export const UP = 1;
217 |
218 | /**
219 | * Direction
220 | * @constant
221 | * @type {Number}
222 | */
223 | export const RIGHT = 2;
224 |
225 | /**
226 | * Direction
227 | * @constant
228 | * @type {Number}
229 | */
230 | export const DOWN = 0;
231 |
232 | /**
233 | * Gravity
234 | * @constant
235 | * @type {Number}
236 | */
237 | export const GRAVITY = -1;
238 |
239 | /**
240 | * Play bgm
241 | * @constant
242 | * @type {Number}
243 | */
244 | export const BGM = true;
245 |
246 | /**
247 | * Play bgs
248 | * @constant
249 | * @type {Number}
250 | */
251 | export const BGS = true;
252 |
253 | /**
254 | * @constant
255 | * @type {Object}
256 | */
257 | export const VOLUME = {
258 | LOCAL_PLAYER: 100,
259 | NETWORK_PLAYER: 10,
260 | MUSIC: 30,
261 | ENTITY_NOISE: 30
262 | };
263 |
264 | /**
265 | * @constant
266 | * @type {Object}
267 | */
268 | export const TYPES = {
269 | Notification: 0,
270 | MapEntity: 1,
271 | Player: 2,
272 | Ping: 3,
273 | Light: 4
274 | };
275 |
276 | /**
277 | * Which browser we
278 | * are running on
279 | * @type {Object}
280 | */
281 | export let BROWSERS = {
282 | IE: false,
283 | iOS: false,
284 | Chrome: false,
285 | Firefox: false,
286 | Vivaldi: false,
287 | Electron: false
288 | };
289 |
290 | BROWSERS::function() {
291 |
292 | if (typeof window === "undefined") return void 0;
293 |
294 | let isChrome = !!(navigator.userAgent.match(/Chrome/i));
295 | let isVivaldi = !!(navigator.userAgent.match(/Vivaldi/i));
296 | let isElectron = !!(typeof window !== "undefined" && window.process && window.process.type === "renderer");
297 |
298 | this.IE = !!(typeof window !== "undefined" && window.ActiveXObject !== void 0);
299 | this.iOS = !!(navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i));
300 | this.Firefox = !!(navigator.userAgent.match(/Firefox/i));
301 |
302 | this.Chrome = isChrome && !isVivaldi;
303 | this.Vivaldi = !this.Chrome;
304 |
305 | this.Electron = !this.Chrome && this.Vivaldi;
306 |
307 | }();
308 |
309 | /**
310 | * Default language packet
311 | * to auto load and use,
312 | * if no language file for
313 | * the navigator was found
314 | * @type {String}
315 | */
316 | export const DEFAULT_LANG = "en";
317 |
318 | /**
319 | * Is client
320 | * @type {Boolean}
321 | */
322 | export let IS_CLIENT = true;
323 |
324 | /**
325 | * @constant
326 | * @type {Array}
327 | */
328 | export const ColorPalette = [
329 | [135, 100, 100],
330 | [135, 105, 100],
331 | [140, 110, 100],
332 | [150, 115, 100],
333 | [155, 125, 100],
334 | [150, 135, 100],
335 | [135, 135, 100],
336 | [135, 125, 100],
337 | [130, 125, 100],
338 | /** Morning */
339 | [130, 120, 100],
340 | [135, 120, 100],
341 | [145, 130, 100],
342 | [150, 145, 100],
343 | /** Day */
344 | [135, 145, 100],
345 | [145, 150, 100],
346 | [150, 125, 100],
347 | [145, 130, 100],
348 | [135, 130, 100],
349 | /** Early night */
350 | [125, 135, 100],
351 | [135, 130, 100],
352 | [135, 135, 100],
353 | [135, 100, 100],
354 | [135, 105, 100],
355 | [140, 110, 100],
356 | [150, 115, 100]
357 | ];
--------------------------------------------------------------------------------
/src/libs/wheel.js:
--------------------------------------------------------------------------------
1 | // from: https://developer.mozilla.org/de/docs/Web/Events/wheel
2 | // creates a global "addWheelListener" method
3 | // example: addWheelListener( elem, function( e ) { console.log( e.deltaY ); e.preventDefault(); } );
4 | (function(window,document) {
5 |
6 | var prefix = "", _addEventListener, support;
7 |
8 | // detect event model
9 | if ( window.addEventListener ) {
10 | _addEventListener = "addEventListener";
11 | } else {
12 | _addEventListener = "attachEvent";
13 | prefix = "on";
14 | }
15 |
16 | // detect available wheel event
17 | support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
18 | document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
19 | "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
20 |
21 | window.addWheelListener = function( elem, callback, useCapture ) {
22 | _addWheelListener( elem, support, callback, useCapture );
23 |
24 | // handle MozMousePixelScroll in older Firefox
25 | if( support == "DOMMouseScroll" ) {
26 | _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
27 | }
28 | };
29 |
30 | function _addWheelListener( elem, eventName, callback, useCapture ) {
31 | elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
32 | !originalEvent && ( originalEvent = window.event );
33 |
34 | // create a normalized event object
35 | var event = {
36 | // keep a ref to the original event object
37 | originalEvent: originalEvent,
38 | target: originalEvent.target || originalEvent.srcElement,
39 | type: "wheel",
40 | deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
41 | deltaX: 0,
42 | deltaZ: 0,
43 | preventDefault: function() {
44 | originalEvent.preventDefault ?
45 | originalEvent.preventDefault() :
46 | originalEvent.returnValue = false;
47 | }
48 | };
49 |
50 | // calculate deltaY (and deltaX) according to the event
51 | if ( support == "mousewheel" ) {
52 | event.deltaY = - 1/40 * originalEvent.wheelDelta;
53 | // Webkit also support wheelDeltaX
54 | originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
55 | } else {
56 | event.deltaY = originalEvent.detail;
57 | }
58 |
59 | // it's time to fire the callback
60 | return callback( event );
61 |
62 | }, useCapture || false );
63 | }
64 |
65 | })(window,document);
--------------------------------------------------------------------------------
/src/polyfill.js:
--------------------------------------------------------------------------------
1 | import { Howler } from "./libs/Howler";
2 |
3 | window.rAF = (function() {
4 | return (
5 | window.requestAnimationFrame ||
6 | window.webkitRequestAnimationFrame ||
7 | window.mozRequestAnimationFrame ||
8 | window.oRequestAnimationFrame ||
9 | window.msRequestAnimationFrame
10 | );
11 | })();
12 |
13 | /**
14 | * @param {Boolean} value
15 | */
16 | CanvasRenderingContext2D.prototype.setImageSmoothing = function(value) {
17 |
18 | this.imageSmoothingEnabled = value;
19 | this.oImageSmoothingEnabled = value;
20 | this.msImageSmoothingEnabled = value;
21 | this.mozImageSmoothingEnabled = value;
22 | this.webkitImageSmoothingEnabled = value;
23 |
24 | return void 0;
25 |
26 | };
27 |
28 | /**
29 | * Clear a context
30 | * @param {String} color Clear by color
31 | */
32 | CanvasRenderingContext2D.prototype.clear = function (color) {
33 |
34 | if (color) {
35 | let original = this.fillStyle;
36 | this.fillStyle = color;
37 | this.fillRect(0, 0, this.canvas.width, this.canvas.height);
38 | this.fillStyle = original;
39 | } else {
40 | this.clearRect(0, 0, this.canvas.width, this.canvas.height);
41 | }
42 |
43 | return void 0;
44 |
45 | };
46 |
47 | // from: https://developer.mozilla.org/de/docs/Web/Events/wheel
48 | // creates a global "addWheelListener" method
49 | // example: addWheelListener( elem, function( e ) { console.log( e.deltaY ); e.preventDefault(); } );
50 | (function(window, document) {
51 |
52 | var prefix = "",
53 | _addEventListener, support;
54 |
55 | // detect event model
56 | if (window.addEventListener) {
57 | _addEventListener = "addEventListener";
58 | } else {
59 | _addEventListener = "attachEvent";
60 | prefix = "on";
61 | }
62 |
63 | // detect available wheel event
64 | support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
65 | document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
66 | "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
67 |
68 | window.addWheelListener = function(elem, callback, useCapture) {
69 | _addWheelListener(elem, support, callback, useCapture);
70 |
71 | // handle MozMousePixelScroll in older Firefox
72 | if (support == "DOMMouseScroll") {
73 | _addWheelListener(elem, "MozMousePixelScroll", callback, useCapture);
74 | }
75 | };
76 |
77 | function _addWheelListener(elem, eventName, callback, useCapture) {
78 | elem[_addEventListener](prefix + eventName, support == "wheel" ? callback : function(originalEvent) {
79 | !originalEvent && (originalEvent = window.event);
80 |
81 | // create a normalized event object
82 | var event = {
83 | // keep a ref to the original event object
84 | originalEvent: originalEvent,
85 | target: originalEvent.target || originalEvent.srcElement,
86 | type: "wheel",
87 | deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
88 | deltaX: 0,
89 | deltaZ: 0,
90 | preventDefault: function() {
91 | originalEvent.preventDefault ?
92 | originalEvent.preventDefault() :
93 | originalEvent.returnValue = false;
94 | }
95 | };
96 |
97 | // calculate deltaY (and deltaX) according to the event
98 | if (support == "mousewheel") {
99 | event.deltaY = -1 / 40 * originalEvent.wheelDelta;
100 | // Webkit also support wheelDeltaX
101 | originalEvent.wheelDeltaX && (event.deltaX = -1 / 40 * originalEvent.wheelDeltaX);
102 | } else {
103 | event.deltaY = originalEvent.detail;
104 | }
105 |
106 | // it's time to fire the callback
107 | return callback(event);
108 |
109 | }, useCapture || false);
110 | }
111 |
112 | })(window, document);
--------------------------------------------------------------------------------
/stats.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){function f(a,e,b){a=document.createElement(a);a.id=e;a.style.cssText=b;return a}function l(a,e,b){var c=f("div",a,"padding:0 0 3px 3px;text-align:left;background:"+b),d=f("div",a+"Text","font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px;color:"+e);d.innerHTML=a.toUpperCase();c.appendChild(d);a=f("div",a+"Graph","width:74px;height:30px;background:"+e);c.appendChild(a);for(e=0;74>e;e++)a.appendChild(f("span","","width:1px;height:30px;float:left;opacity:0.9;background:"+
3 | b));return c}function m(a){for(var b=c.children,d=0;dr+1E3&&(d=Math.round(1E3*
5 | t/(a-r)),u=Math.min(u,d),v=Math.max(v,d),A.textContent=d+" FPS ("+u+"-"+v+")",p(B,d/100),r=a,t=0,void 0!==h)){var b=performance.memory.usedJSHeapSize,c=performance.memory.jsHeapSizeLimit;h=Math.round(9.54E-7*b);y=Math.min(y,h);z=Math.max(z,h);E.textContent=h+" MB ("+y+"-"+z+")";p(F,b/c)}return a},update:function(){k=this.end()}}};"object"===typeof module&&(module.exports=Stats);
6 |
7 | var stats = new Stats();
8 | stats.setMode( 0 ); // 0: fps, 1: ms, 2: mb
9 |
10 | // align top-left
11 | stats.domElement.style.position = 'absolute';
12 | stats.domElement.style.left = '0px';
13 | stats.domElement.style.top = '0px';
14 | stats.domElement.style.zIndex = 999999;
15 | stats.domElement.style.opacity = 1.0;
16 |
17 | document.body.appendChild( stats.domElement );
18 |
19 | var update = function () {
20 |
21 | stats.begin();
22 |
23 | // monitored code goes here
24 |
25 | stats.end();
26 |
27 | requestAnimationFrame( update );
28 |
29 | };
30 |
31 | requestAnimationFrame( update );
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: './src/Game/index.js',
6 | output: {
7 | path: __dirname,
8 | filename: 'bundle.js'
9 | },
10 | module: {
11 | loaders: [{
12 | loader: 'babel-loader',
13 | test: path.join(__dirname, 'src'),
14 | query: {
15 | plugins: ['transform-runtime'],
16 | presets: ['es2015', 'stage-0'],
17 | },
18 | exclude: /node_modules/
19 | }]
20 | },
21 | plugins: [
22 | // Avoid publishing files when compilation fails
23 | new webpack.NoErrorsPlugin()/*,
24 | new webpack.optimize.UglifyJsPlugin({
25 | sourceMap: false,
26 | mangle: true,
27 | compress: true
28 | })*/
29 | ],
30 | stats: {
31 | // Nice colored output
32 | colors: true
33 | }
34 | };
--------------------------------------------------------------------------------
/worlds/kanto/i18n/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_Name": "Kanto",
3 | "s_Settings": "Willkommen"
4 | }
--------------------------------------------------------------------------------
/worlds/kanto/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "s_Name": "Kanto",
3 | "s_Settings": "Welcome"
4 | }
--------------------------------------------------------------------------------
/worlds/kanto/index.js:
--------------------------------------------------------------------------------
1 | return (function() {
2 |
3 | "use strict";
4 |
5 | var WORLD = {
6 | GLOBAL_FLAGS: {
7 | ADMIN_ONLINE: false,
8 | HEAL_DISABLED: false
9 | },
10 | USER_FLAGS: {
11 | GOT_STARTER_PKMN: false,
12 | GOT_POKEDEX: false,
13 | BILLS_PC_ACCOUNT: false
14 | },
15 | SETTINGS: {
16 | DAY_NIGHT_CYCLE: true
17 | }
18 | };
19 |
20 | return (WORLD);
21 |
22 | })();
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/building1.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Building1",
3 | "sprite" : "building1.png",
4 | "normal": true,
5 | "width" : 32,
6 | "height" : 40,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "collidable": true,
10 | "collisionBox": [
11 | 0, 0, 0, 0,
12 | 1, 1, 1, 1,
13 | 1, 1, 1, 1,
14 | 1, 0, 1, 1,
15 | 1, 0, 1, 1
16 | ]
17 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/building1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/building1.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/building1_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/building1_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/campfire.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "CampFire",
3 | "sprite" : "campfire.png",
4 | "normal": true,
5 | "width" : 8,
6 | "height" : 8,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "shadowY": -2,
10 | "collidable": true,
11 | "animation": true,
12 | "animationFrames": 4,
13 | "animationSpeed": 300,
14 | "loop": true,
15 | "noise": "campfire",
16 | "noiseRadius": 32
17 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/campfire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/campfire.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/campfire_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/campfire_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/charizard.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Charizard",
3 | "sprite" : "charizard.png",
4 | "normal": true,
5 | "width" : 32,
6 | "height" : 40,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "collidable": true,
10 | "shadowY": -14,
11 | "collisionBox": [
12 | 0, 0, 0, 0,
13 | 0, 0, 0, 0,
14 | 1, 1, 1, 1,
15 | 1, 1, 1, 1,
16 | 1, 1, 1, 1
17 | ]
18 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/charizard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/charizard.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/charizard_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/charizard_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/door1.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Door1",
3 | "sprite" : "door1.png",
4 | "width" : 10,
5 | "xMargin": -1,
6 | "height" : 7,
7 | "shadow" : false,
8 | "collidable": true,
9 | "animation": true,
10 | "animationFrames": 4,
11 | "animationSpeed": 500,
12 | "loop": false
13 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/door1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/door1.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/flower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Flower",
3 | "sprite" : "flower.png",
4 | "normal": true,
5 | "width" : 8,
6 | "height" : 8,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "shadowY": -4,
10 | "collidable": false,
11 | "animation": true,
12 | "animationFrames": 4,
13 | "animationSpeed": 500,
14 | "loop": true
15 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/flower.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/flower.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/flower_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/flower_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/grass.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Grass",
3 | "sprite" : "grass.png",
4 | "width" : 8,
5 | "height" : 8,
6 | "scale" : 1,
7 | "shadow" : true,
8 | "shadowY": -4,
9 | "collidable": false,
10 | "animation": true,
11 | "animationFrames": 4,
12 | "animationSpeed": 175,
13 | "loop": true
14 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/grass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/grass.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/lantern.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Lantern",
3 | "sprite" : "lantern.png",
4 | "normal" : true,
5 | "width" : 8,
6 | "height" : 24,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "shadowY": -5,
10 | "collidable": true,
11 | "collisionBox": [
12 | 0,
13 | 0,
14 | 1
15 | ]
16 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/lantern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/lantern.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/lantern_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/lantern_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/ping.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Ping",
3 | "sprite" : "ping.png",
4 | "width" : 8,
5 | "height" : 8,
6 | "scale" : 1,
7 | "zIndex" : 9999999,
8 | "shadow" : true,
9 | "shadowY": 0,
10 | "collidable": false
11 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/ping.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/raindrop.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "RainDrop",
3 | "sprite" : "raindrop.png",
4 | "width" : 15,
5 | "height" : 11,
6 | "scale" : 0.25,
7 | "shadow" : true,
8 | "shadowY": -2,
9 | "collidable": false,
10 | "animation": true,
11 | "animationFrames": 4,
12 | "animationSpeed": 100,
13 | "loop": true,
14 | "xMargin": 2,
15 | "yMargin": 2
16 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/raindrop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/raindrop.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/sign.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Sign",
3 | "sprite" : "sign.png",
4 | "normal": true,
5 | "width" : 8,
6 | "height" : 9,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "shadowY": -2,
10 | "collidable": true
11 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/sign.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/sign.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/sign_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/sign_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/table.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Table",
3 | "sprite" : "table.png",
4 | "normal": true,
5 | "width" : 16,
6 | "height" : 16,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "collidable": true,
10 | "collisionBox": [
11 | 1, 1,
12 | 1, 1
13 | ]
14 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/table.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/table_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/table_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/tree.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Tree",
3 | "sprite" : "tree.png",
4 | "normal" : true,
5 | "width" : 32,
6 | "height" : 32,
7 | "scale" : 1,
8 | "shadow" : true,
9 | "collidable": true,
10 | "collisionBox": [
11 | 0, 0, 0, 0,
12 | 0, 0, 0, 0,
13 | 0, 1, 1, 0,
14 | 0, 1, 1, 0
15 | ]
16 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/tree.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/tree_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/tree_normal.png
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/water1.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Water1",
3 | "sprite" : "water1.png",
4 | "width" : 16,
5 | "height" : 16,
6 | "scale" : 1,
7 | "zIndex" : 0,
8 | "shadow" : false,
9 | "animation": true,
10 | "animationFrames": 32,
11 | "loop": true,
12 | "jumpable": false,
13 | "collidable": true
14 | }
--------------------------------------------------------------------------------
/worlds/kanto/town/objects/water1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maierfelix/PokeMMO/4ac97013664a1bae640f44ecc35f887f69bea67a/worlds/kanto/town/objects/water1.png
--------------------------------------------------------------------------------